facet_args/
lib.rs

1use facet_core::{Facet, FieldAttribute};
2use facet_reflect::{PokeStruct, PokeUninit};
3
4fn parse_field(field: PokeUninit, value: &str, field_index: usize, ps: &mut PokeStruct<'_>) {
5    let field_shape = field.shape();
6    log::trace!("Field shape: {}", field_shape);
7
8    let field = match field {
9        PokeUninit::Scalar(pv) => {
10            let pv = match pv.typed::<String>() {
11                Ok(pv) => {
12                    pv.put(value.to_string());
13                    unsafe { ps.mark_initialized(field_index) }
14                    return;
15                }
16                Err(pv) => pv,
17            };
18            let pv = match pv.typed::<bool>() {
19                Ok(pv) => {
20                    log::trace!("Boolean field detected, setting to true");
21                    pv.put(value.to_lowercase() == "true");
22                    unsafe { ps.mark_initialized(field_index) }
23                    return;
24                }
25                Err(pv) => pv,
26            };
27            PokeUninit::Scalar(pv)
28        }
29        field => field,
30    };
31
32    let parse = field_shape.vtable.parse.unwrap_or_else(|| {
33        log::trace!("No parse function found for shape {}", field.shape());
34        panic!("shape {} does not support parse", field.shape())
35    });
36    log::trace!("Parsing field value");
37    unsafe { (parse)(value, field.into_value().data()) }.unwrap_or_else(|e| {
38        log::trace!("Failed to parse field: {}", e);
39        panic!("Failed to parse field of shape {}: {}", field_shape, e)
40    });
41    unsafe { ps.mark_initialized(field_index) }
42}
43
44pub fn from_slice<T: Facet>(s: &[&str]) -> T {
45    log::trace!("Entering from_slice function");
46    let mut s = s;
47    let (poke, guard) = PokeUninit::alloc::<T>();
48    log::trace!("Allocated Poke for type T");
49    let mut ps = poke.into_struct();
50    log::trace!("Converted Poke into struct");
51
52    while let Some(token) = s.first() {
53        log::trace!("Processing token: {}", token);
54        s = &s[1..];
55
56        if let Some(key) = token.strip_prefix("--") {
57            log::trace!("Found named argument: {}", key);
58            let (field_index, field) = ps.field_by_name(key).unwrap();
59            if field.shape().is_type::<bool>() {
60                parse_field(field, "true", field_index, &mut ps);
61            } else {
62                let value = s.first().expect("expected value after argument");
63                log::trace!("Field value: {}", value);
64                s = &s[1..];
65                parse_field(field, value, field_index, &mut ps);
66            }
67        } else {
68            log::trace!("Encountered positional argument: {}", token);
69            for f in ps.def().fields {
70                if f.attributes
71                    .iter()
72                    .any(|a| matches!(a, FieldAttribute::Arbitrary(a) if a.contains("positional")))
73                {
74                    let (field_index, field) = ps.field_by_name(f.name).unwrap();
75                    parse_field(field, token, field_index, &mut ps);
76                    break;
77                }
78            }
79        }
80    }
81    ps.build(Some(guard))
82}