1use super::printf_impl::Error;
2use bstr::{BStr, BString, ByteSlice};
3use std::result::Result;
4
5#[derive(Debug, PartialEq)]
9pub enum Arg<'a> {
10 Str(&'a BStr),
11 String(BString),
12 UInt(u64),
13 SInt(i64),
14 Float(f64),
15 USizeRef(&'a mut usize), }
17
18impl<'a> Arg<'a> {
19 pub fn string(bytes: &'a BStr) -> Self {
20 Self::Str(bytes)
21 }
22
23 pub fn int(value: i32) -> Self {
24 Self::SInt(i64::from(value))
25 }
26
27 pub fn sint(value: i64) -> Self {
28 Self::SInt(value)
29 }
30
31 pub fn hex(value: u32) -> Self {
32 Self::UInt(u64::from(value))
33 }
34
35 pub fn uint(value: u64) -> Self {
36 Self::UInt(value)
37 }
38
39 pub fn float(value: f64) -> Self {
40 Self::Float(value)
41 }
42
43 pub fn pointer(value: usize) -> Self {
44 Self::UInt(value as u64)
45 }
46
47 pub fn set_count(&mut self, count: usize) -> Result<(), Error> {
48 match self {
49 Arg::USizeRef(p) => **p = count,
50 _ => return Err(Error::BadArgType),
51 }
52 Ok(())
53 }
54
55 pub fn as_bstr(&self) -> Result<&BStr, Error> {
56 match self {
57 Arg::Str(s) => Ok(s),
58 Arg::String(s) => Ok(s.as_bstr()),
59 _ => Err(Error::BadArgType),
60 }
61 }
62
63 pub fn as_uint(&self) -> Result<u64, Error> {
65 match *self {
66 Arg::UInt(u) => Ok(u),
67 Arg::SInt(i) => i.try_into().map_err(|_| Error::Overflow),
68 _ => Err(Error::BadArgType),
69 }
70 }
71
72 pub fn as_sint(&self) -> Result<i64, Error> {
74 match *self {
75 Arg::UInt(u) => u.try_into().map_err(|_| Error::Overflow),
76 Arg::SInt(i) => Ok(i),
77 _ => Err(Error::BadArgType),
78 }
79 }
80
81 pub fn as_wrapping_sint(&self) -> Result<u64, Error> {
85 match *self {
86 Arg::UInt(u) => Ok(u),
87 Arg::SInt(i) => Ok(i as u64),
88 _ => Err(Error::BadArgType),
89 }
90 }
91
92 pub fn as_float(&self) -> Result<f64, Error> {
94 #[allow(clippy::cast_precision_loss)]
95 match *self {
96 Arg::Float(f) => Ok(f),
97 Arg::UInt(u) => Ok(u as f64),
98 Arg::SInt(i) => Ok(i as f64),
99 _ => Err(Error::BadArgType),
100 }
101 }
102
103 pub fn as_uchar(&self) -> Result<u8, Error> {
104 Ok(self.as_wrapping_sint()? as u8)
105 }
106}
107
108pub trait ToArg<'a> {
110 fn to_arg(self) -> Arg<'a>;
111}
112
113impl<'a> ToArg<'a> for &'a str {
114 fn to_arg(self) -> Arg<'a> {
115 Arg::Str(self.as_bytes().as_bstr())
116 }
117}
118
119impl<'a> ToArg<'a> for &'a String {
120 fn to_arg(self) -> Arg<'a> {
121 Arg::Str(self.as_bytes().as_bstr())
122 }
123}
124
125impl<'a> ToArg<'a> for String {
126 fn to_arg(self) -> Arg<'a> {
127 Arg::String(BString::from(self))
128 }
129}
130
131impl<'a> ToArg<'a> for &'a BStr {
132 fn to_arg(self) -> Arg<'a> {
133 Arg::Str(self)
134 }
135}
136
137impl<'a> ToArg<'a> for &'a BString {
138 fn to_arg(self) -> Arg<'a> {
139 Arg::Str(self.as_bstr())
140 }
141}
142
143impl<'a> ToArg<'a> for BString {
144 fn to_arg(self) -> Arg<'a> {
145 Arg::String(self)
146 }
147}
148
149impl<'a> ToArg<'a> for &'a [u8] {
150 fn to_arg(self) -> Arg<'a> {
151 Arg::Str(self.as_bstr())
152 }
153}
154
155impl<'a> ToArg<'a> for &'a Vec<u8> {
156 fn to_arg(self) -> Arg<'a> {
157 Arg::Str(self.as_slice().as_bstr())
158 }
159}
160
161impl<'a> ToArg<'a> for Vec<u8> {
162 fn to_arg(self) -> Arg<'a> {
163 Arg::String(BString::from(self))
164 }
165}
166
167impl<'a, const N: usize> ToArg<'a> for &'a [u8; N] {
168 fn to_arg(self) -> Arg<'a> {
169 Arg::Str(self.as_bstr())
170 }
171}
172
173impl<'a> ToArg<'a> for Arg<'a> {
174 fn to_arg(self) -> Arg<'a> {
175 self
176 }
177}
178
179impl<'a> ToArg<'a> for &'a std::io::Error {
180 fn to_arg(self) -> Arg<'a> {
181 Arg::String(BString::from(self.to_string()))
182 }
183}
184
185impl<'a> ToArg<'a> for f32 {
186 fn to_arg(self) -> Arg<'a> {
187 Arg::Float(self.into())
188 }
189}
190
191impl<'a> ToArg<'a> for f64 {
192 fn to_arg(self) -> Arg<'a> {
193 Arg::Float(self)
194 }
195}
196
197impl<'a> ToArg<'a> for &'a mut usize {
198 fn to_arg(self) -> Arg<'a> {
199 Arg::USizeRef(self)
200 }
201}
202
203impl<'a, T> ToArg<'a> for &'a *const T {
204 fn to_arg(self) -> Arg<'a> {
205 Arg::UInt((*self) as usize as u64)
206 }
207}
208
209macro_rules! impl_to_arg {
211 ($($t:ty),*) => {
212 $(
213 impl<'a> ToArg<'a> for $t {
214 fn to_arg(self) -> Arg<'a> {
215 Arg::SInt(self as i64)
216 }
217 }
218 )*
219 };
220}
221impl_to_arg!(i8, i16, i32, i64, isize);
222
223macro_rules! impl_to_arg_u {
225 ($($t:ty),*) => {
226 $(
227 impl<'a> ToArg<'a> for $t {
228 fn to_arg(self) -> Arg<'a> {
229 Arg::UInt(self as u64)
230 }
231 }
232 )*
233 };
234}
235impl_to_arg_u!(u8, u16, u32, u64, usize);
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 #[test]
242 fn test_to_arg() {
243 assert!(matches!("test".to_arg(), Arg::Str(_)));
244 assert!(matches!((&String::from("test")).to_arg(), Arg::Str(_)));
245 assert!(matches!(String::from("test").to_arg(), Arg::String(_)));
246 assert!(matches!(b"test".to_arg(), Arg::Str(_)));
247 assert!(matches!(b"test".as_slice().to_arg(), Arg::Str(_)));
248 assert!(matches!((&BString::from("test")).to_arg(), Arg::Str(_)));
249 assert!(matches!(BString::from("test").to_arg(), Arg::String(_)));
250 assert!(matches!((&b"test".to_vec()).to_arg(), Arg::Str(_)));
251 assert!(matches!(b"test".to_vec().to_arg(), Arg::String(_)));
252 assert!(matches!(42f32.to_arg(), Arg::Float(_)));
253 assert!(matches!(42f64.to_arg(), Arg::Float(_)));
254 let mut usize_val: usize = 0;
255 assert!(matches!((&mut usize_val).to_arg(), Arg::USizeRef(_)));
256 assert!(matches!(42i8.to_arg(), Arg::SInt(42)));
257 assert!(matches!(42i16.to_arg(), Arg::SInt(42)));
258 assert!(matches!(42i32.to_arg(), Arg::SInt(42)));
259 assert!(matches!(42i64.to_arg(), Arg::SInt(42)));
260 assert!(matches!(42isize.to_arg(), Arg::SInt(42)));
261
262 assert_eq!((-42i8).to_arg(), Arg::SInt(-42));
263 assert_eq!((-42i16).to_arg(), Arg::SInt(-42));
264 assert_eq!((-42i32).to_arg(), Arg::SInt(-42));
265 assert_eq!((-42i64).to_arg(), Arg::SInt(-42));
266 assert_eq!((-42isize).to_arg(), Arg::SInt(-42));
267
268 assert!(matches!(42u8.to_arg(), Arg::UInt(42)));
269 assert!(matches!(42u16.to_arg(), Arg::UInt(42)));
270 assert!(matches!(42u32.to_arg(), Arg::UInt(42)));
271 assert!(matches!(42u64.to_arg(), Arg::UInt(42)));
272 assert!(matches!(42usize.to_arg(), Arg::UInt(42)));
273
274 let ptr = std::ptr::from_ref(&42f32);
275 assert!(matches!(ptr.to_arg(), Arg::UInt(_)));
276 }
277
278 #[test]
279 fn test_negative_to_arg() {
280 assert_eq!((-1_i8).to_arg().as_sint(), Ok(-1));
281 assert_eq!((-1_i16).to_arg().as_sint(), Ok(-1));
282 assert_eq!((-1_i32).to_arg().as_sint(), Ok(-1));
283 assert_eq!((-1_i64).to_arg().as_sint(), Ok(-1));
284
285 assert_eq!((u64::MAX).to_arg().as_sint(), Err(Error::Overflow));
286 }
287}