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}