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}