pwd_grp/
convert.rs

1//! Conversions and types (internal module)
2//!
3//! Mainly, this is implementations of `TryConvertFrom`.
4
5use super::*;
6
7//---------- conversions from the uninhabited NoError ----------
8
9impl From<NoError> for io::Error {
10    fn from(n: NoError) -> io::Error {
11        match n {}
12    }
13}
14impl From<NoError> for NonUtf8Error {
15    fn from(n: NoError) -> NonUtf8Error {
16        match n {}
17    }
18}
19
20//---------- "string" type conversions - TryConvertFrom impls ----------
21
22// Manual implementations
23
24impl TryConvertFrom<Box<[u8]>> for String {
25    type Error = NonUtf8Error;
26    fn try_convert_from(v: Box<[u8]>, f: &str) -> Result<Self, Self::Error> {
27        let v: Vec<u8> = v.into();
28        let v = String::from_utf8(v)
29            .map_err(|_| NonUtf8Error { field: f.into() })?;
30        Ok(v)
31    }
32}
33impl TryConvertFrom<Box<[u8]>> for Box<str> {
34    type Error = NonUtf8Error;
35    fn try_convert_from(v: Box<[u8]>, f: &str) -> Result<Self, Self::Error> {
36        let v: String = TryConvertFrom::try_convert_from(v, f)?;
37        Ok(v.into())
38    }
39}
40impl TryConvertFrom<Box<str>> for Box<[u8]> {
41    type Error = NoError;
42    fn try_convert_from(v: Box<str>, _f: &str) -> Result<Self, Self::Error> {
43        let v: String = v.into();
44        let v = v.into_bytes();
45        Ok(v.into())
46    }
47}
48
49impl<T, U> TryConvertFrom<Box<[T]>> for Box<[U]>
50where
51    U: TryConvertFrom<T>,
52{
53    type Error = U::Error;
54    fn try_convert_from(v: Box<[T]>, f: &str) -> Result<Self, Self::Error> {
55        let v: Vec<_> = v.into();
56        IntoIterator::into_iter(v)
57            .map(|v| U::try_convert_from(v, f))
58            .collect()
59    }
60}
61
62// Conversions that can be derived by converting each field
63
64define_derive_deftly! {
65    /// Define `TryConvert` in terms of individual field conversions
66    TryConvertFrom for struct, expect items:
67
68    impl<T, S> TryConvertFrom<$tname<T>> for $tname<S>
69    where S: TryConvertFrom<T>,
70    {
71        type Error = S::Error;
72        fn try_convert_from(v: $tname<T>, _f: &str)
73                            -> Result<Self, Self::Error>
74        {
75            Ok($tname { $( ${select1 fmeta(dummy) {
76                $fname: NonExhaustive {},
77            } else {
78                $fname: TryConvertFrom::try_convert_from(
79                    v.$fname,
80                    stringify!(${paste ${tmeta(abbrev) as str} _ $fname}),
81                )?,
82            }}) })
83        }
84    }
85}
86
87// Infallible conversions that can use `Into`
88
89macro_rules! impl_try_convert_from_via_into { { $T:ty, $U:ty } => {
90    impl TryConvertFrom<$T> for $U {
91        type Error = NoError;
92        fn try_convert_from(v: $T, _f: &str) -> Result<Self, Self::Error> {
93            Ok(v.into())
94        }
95    }
96} }
97macro_rules! impl_infallible_std_from_into { { $T:ty, $U:ty
98                                               $(, via $VIA:ty )? } => {
99    impl From<Passwd<$T>> for Passwd<$U> {
100        fn from(v: Passwd<$T>) -> Passwd<$U> {
101            $( let v: Passwd<$VIA> = v.into(); )?
102            TryConvertFrom::try_convert_from(v, "")
103                .unwrap_or_else(|e | match e { })
104        }
105    }
106
107    impl From<Group<$T>> for Group<$U> {
108        fn from(v: Group<$T>) -> Group<$U> {
109            $( let v: Group<$VIA> = v.into(); )?
110            TryConvertFrom::try_convert_from(v, "")
111                .unwrap_or_else(|e | match e { })
112        }
113    }
114} }
115macro_rules! impl_infallible_conversions { { $T:ty, $U:ty } => {
116    impl_try_convert_from_via_into!($T, $U);
117    impl_infallible_std_from_into!($T, $U);
118} }
119
120impl_try_convert_from_via_into!(Id, Id);
121impl_try_convert_from_via_into!(Box<[u8]>, Box<[u8]>);
122
123impl_infallible_conversions!(Box<[u8]>, Vec<u8>); // make growable
124impl_infallible_conversions!(Vec<u8>, Box<[u8]>); // make fixed-len
125impl_infallible_conversions!(Box<str>, String); // make growable
126impl_infallible_conversions!(String, Box<str>); // make fixed-len
127impl_infallible_conversions!(String, Vec<u8>); // to bytes (growable)
128impl_infallible_std_from_into!(Box<str>, Box<[u8]>); // to bytes (fixed)
129impl_infallible_std_from_into!(String, Box<[u8]>, via Box<str>); // for mocks
130
131// fallible From/Into between various Passwd and Group
132
133macro_rules! impl_std_try_from_into { { $P:ident, $T:ty, $U:ty } => {
134    impl TryFrom<$P<$T>> for $P<$U> {
135        type Error = NonUtf8Error;
136        fn try_from(v: $P<$T>) -> Result<$P<$U>, Self::Error> {
137            let v: $P<RawSafe> = v.into();
138            let v: $P<Box<str>> = TryConvertFrom::try_convert_from(v, "")?;
139            Ok(v.into())
140        }
141    }
142} }
143
144impl_std_try_from_into!(Passwd, Vec<u8>, String); // growable
145impl_std_try_from_into!(Passwd, Box<[u8]>, Box<str>); // fixed-len
146impl_std_try_from_into!(Group, Vec<u8>, String); // growable
147impl_std_try_from_into!(Group, Box<[u8]>, Box<str>); // fixed-len
148
149//---------- helper types and functions ----------
150
151pub(crate) fn handle_nul_in_name_as_io(e: NulError) -> io::Error {
152    io::Error::new(InvalidInput, e)
153}
154
155pub(crate) fn cstring_from(name: &[u8]) -> io::Result<CString> {
156    CString::new(name).map_err(handle_nul_in_name_as_io)
157}