pwd_grp/
private.rs

1//! Internal types which are `pub` but not reachable - sealed
2//!
3//! "Private in public" rules mean all of this has to be `pub`
4//!
5//! But only `SealedString` is actually even shown publicly,
6//! and even that isn't visible.
7
8use super::*;
9
10/// Types which are enough like `String` or `Vec<u8>` for us to work with
11pub trait SealedString: Deref + TryConvertFrom<Box<[u8]>> {
12    /// Get a `[u8]` (from the type's deref target)
13    fn as_u8(s: &Self::Target) -> &[u8];
14
15    /// Convert a conversion error into an `io::Error`
16    fn handle_error_as_io(e: Self::Error) -> io::Error;
17}
18
19/// Like `TryFrom` but we have it for `[u]` to `str`
20///
21/// Implemented for various conversions between safe Rust string types.
22///
23/// (The raw libc pointers aren't handled by this -
24/// they're in `unsafe_::Frolic`.)
25pub trait TryConvertFrom<Input>: Sized {
26    type Error: Sized // this + comment to avoid rustfmt deleting comments!!
27        // TryConvertFrom derive needs this for infallible fields
28        + From<NoError>
29        // TryConvertFrom derive, needs this for error propagation;
30        // the compiler can't see that this blanket impl exists unless
31        // we explicitly demand it here.
32        + From<Self::Error>
33        // So we can wrap it in io::Error
34        + std::error::Error
35        + Send
36        + Sync
37        + 'static;
38    fn try_convert_from(v: Input, f: &str) -> Result<Self, Self::Error>;
39}
40
41/// Error from infallible conversions
42///
43/// We must use our own type because (i) `Infallible` is hopeless
44/// (ii) we want to
45#[derive(Error, Debug)]
46pub enum NoError {}
47
48/// Marker type for the `__non_exhaustive` field in `Passwd` and `Groups`
49///
50/// We want to be able to add fields to [`Passwd`] and [`Group`]
51/// without it being a semver break.
52/// (Several Unix variants including MacOS have additional fields
53/// which we might want to expose.)
54///
55/// We don't use `#[non_exhaustive]` because that prevents callers
56/// from creating the struct with struct display syntax.
57/// For the same reason, we must make the field `pub`.
58///
59/// The error message then refers to the field name,
60/// so we have a note in the docs for each of the two structs.
61///
62/// Sadly, `NonExhaustive` must be `Default` for serde's benefit,
63/// so although the user cannot name it, they could use `Default::default`
64/// (but even if that weren't the case they could obtain one
65/// from another `Passwd` or `Group`).
66#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
67pub struct NonExhaustive {}
68
69//---------- SealedDataProvider ----------
70
71pub struct SealedData<'r>(pub(crate) &'r mock::Data);
72
73pub trait SealedProvider {
74    fn with_mocks<R>(&self, f: impl FnOnce(SealedData) -> R) -> Option<R>;
75}
76
77impl SealedProvider for generic::PwdGrp {
78    #[inline]
79    fn with_mocks<R>(&self, _: impl FnOnce(SealedData) -> R) -> Option<R> {
80        None
81    }
82}
83
84//---------- implementations of SealedString ----------
85
86/// impl for `RawSafe`, our primary internal type
87impl SealedString for Box<[u8]> {
88    fn as_u8(s: &Self::Target) -> &[u8] {
89        s
90    }
91    fn handle_error_as_io(e: Self::Error) -> io::Error {
92        match e {}
93    }
94}
95
96impl SealedString for String {
97    fn as_u8(s: &Self::Target) -> &[u8] {
98        s.as_bytes()
99    }
100    fn handle_error_as_io(e: Self::Error) -> io::Error {
101        e.into()
102    }
103}
104impl SealedString for Vec<u8> {
105    fn as_u8(s: &Self::Target) -> &[u8] {
106        s
107    }
108    fn handle_error_as_io(e: Self::Error) -> io::Error {
109        match e {}
110    }
111}
112impl SealedString for Box<str> {
113    fn as_u8(s: &Self::Target) -> &[u8] {
114        s.as_bytes()
115    }
116    fn handle_error_as_io(e: Self::Error) -> io::Error {
117        e.into()
118    }
119}