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}