1#![warn(missing_docs)]
2#![warn(clippy::std_instead_of_core)]
3#![warn(clippy::std_instead_of_alloc)]
4#![forbid(unsafe_code)]
5#![doc = include_str!("../README.md")]
6
7use facet_core::{Def, Facet, FieldAttribute};
8use facet_reflect::{ReflectError, Wip};
9
10fn parse_field<'facet>(wip: Wip<'facet>, value: &'facet str) -> Result<Wip<'facet>, ReflectError> {
11 let shape = wip.shape();
12 match shape.def {
13 Def::Scalar(_) => {
14 if shape.is_type::<String>() {
15 wip.put(value.to_string())
16 } else if shape.is_type::<&str>() {
17 wip.put(value)
18 } else if shape.is_type::<bool>() {
19 log::trace!("Boolean field detected, setting to true");
20 wip.put(value.to_lowercase() == "true")
21 } else {
22 wip.parse(value)
23 }
24 }
25 _def => {
26 return Err(ReflectError::OperationFailed {
27 shape,
28 operation: "parsing field",
29 });
30 }
31 }?
32 .pop()
33}
34
35pub fn from_slice<'input, 'facet, T>(s: &[&'input str]) -> T
37where
38 T: Facet<'facet>,
39 'input: 'facet,
40{
41 log::trace!("Entering from_slice function");
42 let mut s = s;
43 let mut wip = Wip::alloc::<T>().expect("failed to allocate");
44 log::trace!("Allocated Poke for type T");
45
46 while let Some(token) = s.first() {
47 log::trace!("Processing token: {}", token);
48 s = &s[1..];
49
50 if let Some(key) = token.strip_prefix("--") {
51 log::trace!("Found named argument: {}", key);
52 let field_index = match wip.field_index(key) {
53 Some(index) => index,
54 None => panic!("Unknown argument: {}", key),
55 };
56 let field = wip.field(field_index).unwrap();
57
58 if field.shape().is_type::<bool>() {
59 wip = parse_field(field, "true").unwrap();
60 } else {
61 let value = s.first().expect("expected value after argument");
62 log::trace!("Field value: {}", value);
63 s = &s[1..];
64 wip = parse_field(field, value).unwrap();
65 }
66 } else {
67 log::trace!("Encountered positional argument: {}", token);
68 let Def::Struct(sd) = wip.shape().def else {
69 panic!("Expected struct definition");
70 };
71
72 for (field_index, f) in sd.fields.iter().enumerate() {
73 if f.attributes
74 .iter()
75 .any(|a| matches!(a, FieldAttribute::Arbitrary(a) if a.contains("positional")))
76 {
77 let field = wip.field(field_index).unwrap();
78 wip = parse_field(field, token).unwrap();
79 break;
80 }
81 }
82 }
83 }
84 wip.build().unwrap().materialize().unwrap()
85}