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