fidl_next_codec/
validate.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use thiserror::Error;
6
7use crate::Slot;
8
9/// Errors that can be produced when validating FIDL messages.
10///
11/// Validation errors may occur during both encoding and decoding.
12#[derive(Error, Debug, PartialEq, Eq, Clone)]
13pub enum ValidationError {
14    /// Vector too long.
15    #[error("vector too long, has {count}, limit is {limit}")]
16    VectorTooLong {
17        /// The number of elements.
18        count: u64,
19        /// The maximum number of elements allowed.
20        limit: u64,
21    },
22    /// String too long.
23    #[error("string too long, has {count}, limit is {limit}")]
24    StringTooLong {
25        /// The number of bytes in the string.
26        count: u64,
27        /// The maximum number of bytes allowed.
28        limit: u64,
29    },
30}
31
32/// Implemented by types that have constraints that can be validated.
33pub trait Constrained {
34    /// Type of constraint information for this type.
35    type Constraint: Copy;
36
37    /// Validate a value of this type against a constraint. Can be called when
38    /// pointers/envelopes are just presence markers.
39    fn validate(value: Slot<'_, Self>, constraint: Self::Constraint)
40    -> Result<(), ValidationError>;
41}
42
43/// Implemented by types that can't have constraints.
44///
45/// Note: this is intended as an implementation helper, not as a where clause
46/// bound. If you want bound a type on being unconstrained you must use
47/// something like: `T: Constrained<Constraint=()>``
48pub trait Unconstrained {}
49
50impl<T: Unconstrained> Constrained for T {
51    type Constraint = ();
52
53    #[inline]
54    fn validate(_: Slot<'_, Self>, _: ()) -> Result<(), ValidationError> {
55        Ok(())
56    }
57}
58
59// Arrays have the constraints of their member.
60impl<T: Constrained, const N: usize> Constrained for [T; N] {
61    type Constraint = T::Constraint;
62    fn validate(
63        mut slot: Slot<'_, Self>,
64        constraint: Self::Constraint,
65    ) -> Result<(), ValidationError> {
66        // SAFETY: this slot must be initialized.
67        let slice = unsafe { (slot.as_mut_ptr() as *mut [T]).as_mut() }.unwrap();
68        for member in slice {
69            // SAFETY: every member of the array must have been initialized already.
70            let member_slot = unsafe { Slot::new_unchecked(member) };
71            T::validate(member_slot, constraint)?;
72        }
73        Ok(())
74    }
75}