facet_args/
lib.rs

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