facet_args/
lib.rs

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