1use std::ffi::CStr;
9use std::fmt;
10use std::str::{FromStr, Utf8Error};
11
12#[cfg(unix)]
13use std::os::unix::ffi::{OsStrExt, OsStringExt};
14
15#[cfg(unix)]
16use std::ffi::{OsStr, OsString};
17
18pub trait FromWordPointer<'a>: Sized + 'a {
22 type Err: std::fmt::Display;
24
25 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err>;
27
28 #[doc(hidden)]
33 const OPTSTR_ARGUMENT: u8 = b':';
34
35 #[doc(hidden)]
37 fn extract_value(arg: Option<&'a CStr>) -> crate::Result<Self> {
38 match arg {
39 None => {
40 crate::log::missing_argument();
41 Err(crate::Error::Usage)
42 }
43
44 Some(arg) => Self::from_cstr(arg).map_err(|e| {
45 crate::error!("{:?}: {}", arg, e);
46 crate::Error::Usage
47 }),
48 }
49 }
50}
51
52impl<'a, T: FromWordPointer<'a>> FromWordPointer<'a> for Option<T> {
54 const OPTSTR_ARGUMENT: u8 = b';';
55
56 type Err = <T as FromWordPointer<'a>>::Err;
57
58 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
59 <T as FromWordPointer<'a>>::from_cstr(s).map(Some)
60 }
61
62 fn extract_value(arg: Option<&'a CStr>) -> crate::Result<Self> {
63 match arg {
64 None => Ok(None),
65
66 Some(arg) => match <T as FromWordPointer<'a>>::from_cstr(arg) {
67 Ok(v) => Ok(Some(v)),
68
69 Err(e) => {
70 crate::error!("{:?}: {}", arg, e);
71 Err(crate::Error::Usage)
72 }
73 },
74 }
75 }
76}
77
78impl<'a> FromWordPointer<'a> for &'a str {
81 type Err = Utf8Error;
82
83 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
84 s.to_str()
85 }
86}
87
88impl<'a> FromWordPointer<'a> for String {
89 type Err = Utf8Error;
90
91 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
92 s.to_str().map(str::to_owned)
93 }
94}
95
96#[cfg(unix)]
97impl<'a> FromWordPointer<'a> for &'a std::path::Path {
98 type Err = std::convert::Infallible;
99
100 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
101 Ok(std::path::Path::new(OsStr::from_bytes(s.to_bytes())))
102 }
103}
104
105#[cfg(unix)]
106impl<'a> FromWordPointer<'a> for std::path::PathBuf {
107 type Err = std::convert::Infallible;
108
109 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
110 Ok(Self::from(OsStr::from_bytes(s.to_bytes())))
111 }
112}
113
114#[cfg(unix)]
115impl<'a> FromWordPointer<'a> for &'a OsStr {
116 type Err = std::convert::Infallible;
117
118 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
119 Ok(OsStr::from_bytes(s.to_bytes()))
120 }
121}
122
123#[cfg(unix)]
124impl<'a> FromWordPointer<'a> for OsString {
125 type Err = std::convert::Infallible;
126
127 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
128 Ok(OsString::from_vec(s.to_bytes().into()))
129 }
130}
131
132#[doc(hidden)]
135pub enum Utf8OrParseError<T> {
136 Utf8(Utf8Error),
137 Parse(T),
138}
139
140impl<T: fmt::Display> fmt::Display for Utf8OrParseError<T> {
141 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
142 match self {
143 Utf8OrParseError::Utf8(e) => e.fmt(fmt),
144 Utf8OrParseError::Parse(e) => e.fmt(fmt),
145 }
146 }
147}
148
149macro_rules! impl_primitive {
150 ($ty:ty) => {
151 impl<'a> FromWordPointer<'a> for $ty {
152 type Err = Utf8OrParseError<<$ty as FromStr>::Err>;
153
154 fn from_cstr(s: &'a CStr) -> Result<Self, Self::Err> {
155 let s = s.to_str().map_err(Utf8OrParseError::Utf8)?;
156 <$ty as FromStr>::from_str(s).map_err(Utf8OrParseError::Parse)
157 }
158 }
159 };
160}
161
162impl_primitive!(bool);
163impl_primitive!(char);
164impl_primitive!(f32);
165impl_primitive!(f64);
166impl_primitive!(i8);
167impl_primitive!(i16);
168impl_primitive!(i32);
169impl_primitive!(i64);
170impl_primitive!(i128);
171impl_primitive!(isize);
172impl_primitive!(u8);
173impl_primitive!(u16);
174impl_primitive!(u32);
175impl_primitive!(u64);
176impl_primitive!(u128);
177impl_primitive!(usize);