aopt_core/value/
parser.rs

1use std::ffi::OsStr;
2use std::ffi::OsString;
3use std::io::Stdin;
4use std::path::PathBuf;
5
6use crate::ctx::Ctx;
7use crate::Error;
8
9/// Implement this if you want parsing the raw value into your type.
10pub trait RawValParser
11where
12    Self: Sized,
13{
14    type Error: Into<Error>;
15
16    fn parse(raw: Option<&OsStr>, ctx: &Ctx) -> Result<Self, Self::Error>;
17}
18
19fn ok_or_else(raw: Option<&OsStr>) -> Result<&OsStr, Error> {
20    raw.ok_or_else(|| Error::sp_rawval(None, "unexcepted empty value"))
21}
22
23/// Convert raw value to &[`str`].
24pub fn raw2str(raw: Option<&OsStr>) -> Result<&str, Error> {
25    ok_or_else(raw)?
26        .to_str()
27        .ok_or_else(|| Error::sp_rawval(raw, "can not convert OsStr to str"))
28}
29
30impl RawValParser for () {
31    type Error = Error;
32
33    fn parse(_: Option<&OsStr>, _: &Ctx) -> Result<Self, Self::Error> {
34        Ok(())
35    }
36}
37
38macro_rules! impl_raw_val_parser {
39    ($int:ty) => {
40        impl $crate::value::parser::RawValParser for $int {
41            type Error = Error;
42
43            fn parse(raw: Option<&OsStr>, ctx: &Ctx) -> Result<$int, Self::Error> {
44                let val = $crate::value::parser::raw2str(raw)?;
45                let uid = ctx.uid()?;
46
47                val.parse::<$int>().map_err(|e| {
48                    $crate::err::Error::sp_rawval(
49                        raw,
50                        format!("not a valid value of type {}", stringify!($int)),
51                    )
52                    .with_uid(uid)
53                    .cause_by(e.into())
54                })
55            }
56        }
57    };
58}
59
60impl_raw_val_parser!(i8);
61impl_raw_val_parser!(i16);
62impl_raw_val_parser!(i32);
63impl_raw_val_parser!(i64);
64impl_raw_val_parser!(i128);
65impl_raw_val_parser!(u8);
66impl_raw_val_parser!(u16);
67impl_raw_val_parser!(u32);
68impl_raw_val_parser!(u64);
69impl_raw_val_parser!(u128);
70impl_raw_val_parser!(f32);
71impl_raw_val_parser!(f64);
72impl_raw_val_parser!(isize);
73impl_raw_val_parser!(usize);
74
75impl RawValParser for String {
76    type Error = Error;
77
78    fn parse(raw: Option<&OsStr>, _ctx: &Ctx) -> Result<Self, Self::Error> {
79        Ok(raw2str(raw)?.to_string())
80    }
81}
82
83impl RawValParser for OsString {
84    type Error = Error;
85
86    fn parse(raw: Option<&OsStr>, ctx: &Ctx) -> Result<Self, Self::Error> {
87        let uid = ctx.uid()?;
88
89        Ok(ok_or_else(raw).map_err(|e| e.with_uid(uid))?.to_os_string())
90    }
91}
92
93impl RawValParser for bool {
94    type Error = Error;
95
96    fn parse(raw: Option<&OsStr>, ctx: &Ctx) -> Result<Self, Self::Error> {
97        let val = raw2str(raw)?;
98
99        match val {
100            crate::opt::BOOL_TRUE => Ok(true),
101            crate::opt::BOOL_FALSE => Ok(false),
102            _ => Err(Error::sp_rawval(raw, "except true or false").with_uid(ctx.uid()?)),
103        }
104    }
105}
106
107impl RawValParser for PathBuf {
108    type Error = Error;
109
110    fn parse(raw: Option<&OsStr>, _ctx: &Ctx) -> Result<Self, Self::Error> {
111        Ok(PathBuf::from(ok_or_else(raw)?))
112    }
113}
114
115impl RawValParser for Stdin {
116    type Error = Error;
117
118    fn parse(raw: Option<&OsStr>, ctx: &Ctx) -> Result<Self, Self::Error> {
119        const STDIN: &str = "-";
120
121        if ctx.name()?.map(|v| v.as_ref()) == Some(STDIN) {
122            Ok(std::io::stdin())
123        } else {
124            Err(Error::sp_rawval(raw, "except `-` for Stdin").with_uid(ctx.uid()?))
125        }
126    }
127}