validated_slice/
lib.rs

1//! A library to easily define validated custom slice and vector types.
2#![warn(missing_docs)]
3#![warn(clippy::missing_docs_in_private_items)]
4
5#[macro_use]
6mod macros;
7
8/// A trait to provide types and features for a custom slice type.
9///
10/// # Safety
11///
12/// To avoid undefined behavior, users are responsible to let implementations satisfy all
13/// conditions below:
14///
15/// * `Self::validate()` always returns the same result for the same input.
16/// * `Self::Inner` is the only non-zero type field of `Self::Custom`.
17/// * `Self::Custom` has attribute `#[repr(transparent)]` or `#[repr(C)]`.
18///
19/// If any of the condition is not met, use of methods may cause undefined behavior.
20///
21/// # Examples
22///
23/// ```
24/// /// ASCII string slice.
25/// // `#[repr(transparent)]` or `#[repr(C)]` is required.
26/// // Without it, generated codes would be unsound.
27/// #[repr(transparent)]
28/// #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
29/// pub struct AsciiStr(str);
30///
31/// /// ASCII string validation error.
32/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33/// pub struct AsciiError {
34///     /// Byte position of the first invalid byte.
35///     valid_up_to: usize,
36/// }
37///
38/// enum AsciiStrSpec {}
39///
40/// impl validated_slice::SliceSpec for AsciiStrSpec {
41///     type Custom = AsciiStr;
42///     type Inner = str;
43///     type Error = AsciiError;
44///
45///     fn validate(s: &Self::Inner) -> Result<(), Self::Error> {
46///         match s.as_bytes().iter().position(|b| !b.is_ascii()) {
47///             Some(pos) => Err(AsciiError { valid_up_to: pos }),
48///             None => Ok(()),
49///         }
50///     }
51///
52///     validated_slice::impl_slice_spec_methods! {
53///         field=0;
54///         methods=[
55///             as_inner,
56///             as_inner_mut,
57///             from_inner_unchecked,
58///             from_inner_unchecked_mut,
59///         ];
60///     }
61/// }
62/// ```
63pub trait SliceSpec {
64    /// Custom borrowed slice type.
65    type Custom: ?Sized;
66    /// Borrowed inner slice type of `Self::Custom`.
67    type Inner: ?Sized;
68    /// Validation error type.
69    type Error;
70
71    /// Validates the inner slice to check if the value is valid as the custom slice type value.
72    ///
73    /// Returns `Ok(())` if the value is valid (and safely convertible to `Self::Custom`.
74    /// Returns `Err(_)` if the validation failed.
75    fn validate(s: &Self::Inner) -> Result<(), Self::Error>;
76    /// Converts a reference to the custom slice into a reference to the inner slice type.
77    fn as_inner(s: &Self::Custom) -> &Self::Inner;
78    /// Converts a mutable reference to the custom slice into a mutable reference to the inner slice
79    /// type.
80    fn as_inner_mut(s: &mut Self::Custom) -> &mut Self::Inner;
81    /// Creates a reference to the custom slice type without any validation.
82    ///
83    /// # Safety
84    ///
85    /// This is safe only when all of the conditions below are met:
86    ///
87    /// * `Self::validate(s)` returns `Ok(())`.
88    /// * `Self::Inner` is the only non-zero type field of `Self::Custom`.
89    /// * `Self::Custom` has attribute `#[repr(transparent)]` or `#[repr(C)]`.
90    ///
91    /// If any of the condition is not met, this function may cause undefined behavior.
92    unsafe fn from_inner_unchecked(s: &Self::Inner) -> &Self::Custom;
93    /// Creates a mutable reference to the custom slice type without any validation.
94    ///
95    /// # Safety
96    ///
97    /// Safety condition is same as [`from_inner_unchecked`].
98    ///
99    /// [`from_inner_unchecked`]: #tymethod.from_inner_unchecked
100    unsafe fn from_inner_unchecked_mut(s: &mut Self::Inner) -> &mut Self::Custom;
101}
102
103/// A trait to provide types and features for an owned custom slice type.
104///
105/// # Safety
106///
107/// To avoid undefined behavior, users are responsible to let implementations satisfy all
108/// conditions below:
109///
110/// * Safety conditions for `Self::SliceSpec` is satisfied.
111/// * `Self::SliceCustom` is set to `<Self::SliceSpec as SliceSpec>::Custom`.
112/// * `Self::SliceInner` is set to `<Self::SliceSpec as SliceSpec>::Inner`.
113/// * `Self::SliceError` is set to `<Self::SliceSpec as SliceSpec>::Error`.
114///
115/// If any of the conditions is not met, use of methods may cause undefined behavior.
116///
117/// # Examples
118///
119/// ```ignore
120/// /// ASCII string boxed slice.
121/// #[derive(Default, Debug, Clone, Eq, Ord, Hash)]
122/// pub struct AsciiString(String);
123///
124/// enum AsciiStringSpec {}
125///
126/// impl validated_slice::OwnedSliceSpec for AsciiStringSpec {
127///     type Custom = AsciiString;
128///     type Inner = String;
129///     // You can use dedicated error type for owned slice here,
130///     // as `std::str::Utf8Error` is used for borrowed slice validation and
131///     // `std::string::FromUtf8Error` is used for owned slice validation.
132///     type Error = AsciiError;
133///     type SliceSpec = AsciiStrSpec;
134///     type SliceCustom = AsciiStr;
135///     type SliceInner = str;
136///     type SliceError = AsciiError;
137///
138///     #[inline]
139///     fn convert_validation_error(e: Self::SliceError, _: Self::Inner) -> Self::Error {
140///         e
141///     }
142///
143///     #[inline]
144///     fn as_slice_inner(s: &Self::Custom) -> &Self::SliceInner {
145///         &s.0
146///     }
147///
148///     #[inline]
149///     fn as_slice_inner_mut(s: &mut Self::Custom) -> &mut Self::SliceInner {
150///         &mut s.0
151///     }
152///
153///     #[inline]
154///     fn inner_as_slice_inner(s: &Self::Inner) -> &Self::SliceInner {
155///         s
156///     }
157///
158///     #[inline]
159///     unsafe fn from_inner_unchecked(s: Self::Inner) -> Self::Custom {
160///         AsciiString(s)
161///     }
162///
163///     #[inline]
164///     fn into_inner(s: Self::Custom) -> Self::Inner {
165///         s.0
166///     }
167/// }
168/// ```
169pub trait OwnedSliceSpec {
170    /// Custom owned slice type.
171    type Custom;
172    /// Owned inner slice type of `Self::Custom`.
173    type Inner;
174    /// Validation error type for owned inner type.
175    type Error;
176    /// Spec of the borrowed slice type.
177    type SliceSpec: SliceSpec;
178    /// Same type as `<Self::SliceSpec as SliceSpec>::Custom`.
179    type SliceCustom: ?Sized;
180    /// Same type as `<Self::SliceSpec as SliceSpec>::Inner`.
181    type SliceInner: ?Sized;
182    /// Same type as `<Self::SliceSpec as SliceSpec>::Error`.
183    type SliceError;
184
185    /// Converts a borrowed slice validation error into an owned slice validation error.
186    fn convert_validation_error(e: Self::SliceError, v: Self::Inner) -> Self::Error;
187    /// Returns the borrowed inner slice for the given reference to a custom owned slice.
188    fn as_slice_inner(s: &Self::Custom) -> &Self::SliceInner;
189    /// Returns the borrowed inner slice for the given mutable reference to a custom owned slice.
190    fn as_slice_inner_mut(s: &mut Self::Custom) -> &mut Self::SliceInner;
191    /// Returns the borrowed inner slice for the given reference to owned inner slice.
192    fn inner_as_slice_inner(s: &Self::Inner) -> &Self::SliceInner;
193    /// Creates a reference to the custom slice type without any validation.
194    ///
195    /// # Safety
196    ///
197    /// This is safe only when all of the conditions below are met:
198    ///
199    /// * `Self::validate(s)` returns `Ok(())`.
200    /// * Safety condition for `Self::SliceSpec` is satisfied.
201    ///
202    /// If any of the condition is not met, this function may cause undefined behavior.
203    unsafe fn from_inner_unchecked(s: Self::Inner) -> Self::Custom;
204    /// Returns the inner value with its ownership.
205    fn into_inner(s: Self::Custom) -> Self::Inner;
206}