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