Skip to main content

maybe_valid/impls/
core_impls.rs

1use ::core::char::CharTryFromError;
2use ::core::ffi::CStr;
3use ::core::str::Utf8Error;
4
5use ::core::ffi::FromBytesWithNulError;
6use ::core::num::{
7    NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
8    NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
9};
10
11use crate::{AsValidated, IntoValidated, MaybeValidOwned, MaybeValidRef, Validated};
12
13/// Returned on the invalid path when validating an integer as a
14/// corresponding `NonZero*` type.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct ZeroReason;
17
18/// Returned on the invalid path when validating bytes as `CStr` or
19/// `CString`.
20///
21/// `CStr` borrow validation can report specific positional reasons.
22/// `CString` owned validation in `alloc` mode may only report
23/// `Unspecified`, because `FromVecWithNulError` does not expose
24/// detailed failure information.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum CStrInvalidReason {
27    /// No nul terminator found within the byte slice.
28    MissingNul,
29    /// An interior nul byte was found at this position.
30    InteriorNul { position: usize },
31    /// Unspecified reason.
32    ///
33    /// Used when validating into `CString`, where the standard library
34    /// does not expose more specific diagnostics.
35    Unspecified,
36}
37
38impl Validated for str {
39    type InvalidReason = Utf8Error;
40}
41
42impl AsValidated<str> for [u8] {
43    fn as_validated(&self) -> MaybeValidRef<'_, str, Self> {
44        match ::core::str::from_utf8(self) {
45            Ok(v) => MaybeValidRef::Valid(v),
46            Err(e) => MaybeValidRef::Invalid(self, e),
47        }
48    }
49}
50
51impl Validated for CStr {
52    type InvalidReason = CStrInvalidReason;
53}
54
55impl AsValidated<CStr> for [u8] {
56    fn as_validated(&self) -> MaybeValidRef<'_, CStr, Self> {
57        match CStr::from_bytes_with_nul(self) {
58            Ok(v) => MaybeValidRef::Valid(v),
59            Err(FromBytesWithNulError::InteriorNul { position }) => {
60                MaybeValidRef::Invalid(self, CStrInvalidReason::InteriorNul { position })
61            }
62            Err(FromBytesWithNulError::NotNulTerminated) => {
63                MaybeValidRef::Invalid(self, CStrInvalidReason::MissingNul)
64            }
65        }
66    }
67}
68
69impl Validated for char {
70    type InvalidReason = CharTryFromError;
71}
72
73impl IntoValidated<char> for u32 {
74    fn into_validated(self) -> MaybeValidOwned<char, Self> {
75        match char::try_from(self) {
76            Ok(v) => MaybeValidOwned::Valid(v),
77            Err(e) => MaybeValidOwned::Invalid(self, e),
78        }
79    }
80}
81
82macro_rules! impl_nonzero {
83    ($nz:ty, $raw:ty) => {
84        impl Validated for $nz {
85            type InvalidReason = ZeroReason;
86        }
87
88        impl AsValidated<$nz> for $raw {
89            fn as_validated(&self) -> MaybeValidRef<'_, $nz, $raw> {
90                // SAFETY: $nz is #[repr(transparent)] over $raw in std,
91                // and the predicate (value != 0) holds here, so the
92                // bit pattern is a valid $nz.
93                if *self != 0 {
94                    let nz = unsafe { &*(self as *const $raw as *const $nz) };
95                    MaybeValidRef::Valid(nz)
96                } else {
97                    MaybeValidRef::Invalid(self, ZeroReason)
98                }
99            }
100        }
101
102        impl IntoValidated<$nz> for $raw {
103            fn into_validated(self) -> MaybeValidOwned<$nz, Self> {
104                match <$nz>::new(self) {
105                    Some(nz) => MaybeValidOwned::Valid(nz),
106                    None => MaybeValidOwned::Invalid(self, ZeroReason),
107                }
108            }
109        }
110    };
111}
112
113impl_nonzero!(NonZeroU8, u8);
114impl_nonzero!(NonZeroU16, u16);
115impl_nonzero!(NonZeroU32, u32);
116impl_nonzero!(NonZeroU64, u64);
117impl_nonzero!(NonZeroU128, u128);
118impl_nonzero!(NonZeroUsize, usize);
119impl_nonzero!(NonZeroI8, i8);
120impl_nonzero!(NonZeroI16, i16);
121impl_nonzero!(NonZeroI32, i32);
122impl_nonzero!(NonZeroI64, i64);
123impl_nonzero!(NonZeroI128, i128);
124impl_nonzero!(NonZeroIsize, isize);