facet_format/
event.rs

1extern crate alloc;
2
3use alloc::borrow::Cow;
4use core::fmt;
5
6/// Location hint for a serialized field.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum FieldLocationHint {
9    /// Key/value entry (JSON/YAML/TOML).
10    KeyValue,
11    /// XML attribute.
12    Attribute,
13    /// XML/KDL text node.
14    Text,
15    /// XML/KDL child element/node.
16    Child,
17    /// KDL property.
18    Property,
19    /// KDL positional argument.
20    Argument,
21    /// Element tag name (for custom elements in XML/HTML).
22    Tag,
23}
24
25/// Field key with optional namespace (for XML).
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct FieldKey<'de> {
28    /// Field name.
29    pub name: Cow<'de, str>,
30    /// Location hint.
31    pub location: FieldLocationHint,
32    /// Optional namespace URI (for XML namespace support).
33    pub namespace: Option<Cow<'de, str>>,
34}
35
36impl<'de> FieldKey<'de> {
37    /// Create a new field key without namespace.
38    pub fn new(name: impl Into<Cow<'de, str>>, location: FieldLocationHint) -> Self {
39        Self {
40            name: name.into(),
41            location,
42            namespace: None,
43        }
44    }
45
46    /// Add a namespace to this field key (builder pattern).
47    pub fn with_namespace(mut self, namespace: impl Into<Cow<'de, str>>) -> Self {
48        self.namespace = Some(namespace.into());
49        self
50    }
51}
52
53/// The kind of container being parsed.
54///
55/// This distinguishes between format-specific container types to enable
56/// better error messages and type checking.
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum ContainerKind {
59    /// JSON/YAML/TOML object: definitely struct-like with key-value pairs.
60    /// Type mismatches (e.g., object where array expected) should produce errors.
61    Object,
62    /// JSON/YAML array: definitely sequence-like.
63    /// Type mismatches (e.g., array where object expected) should produce errors.
64    Array,
65    /// XML/KDL element: semantically ambiguous.
66    /// Could be interpreted as struct, sequence, or scalar wrapper depending on target type.
67    /// The deserializer decides based on what type it's deserializing into.
68    Element,
69}
70
71impl ContainerKind {
72    /// Returns true if this container kind is ambiguous (can be struct or sequence).
73    pub fn is_ambiguous(self) -> bool {
74        matches!(self, ContainerKind::Element)
75    }
76
77    /// Human-readable name for error messages.
78    pub fn name(self) -> &'static str {
79        match self {
80            ContainerKind::Object => "object",
81            ContainerKind::Array => "array",
82            ContainerKind::Element => "element",
83        }
84    }
85}
86
87/// Value classification hint for evidence gathering.
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum ValueTypeHint {
90    /// Null-like values.
91    Null,
92    /// Boolean.
93    Bool,
94    /// Numeric primitive.
95    Number,
96    /// Text string.
97    String,
98    /// Raw bytes (e.g., base64 segments).
99    Bytes,
100    /// Sequence (array/list/tuple).
101    Sequence,
102    /// Map/struct/object.
103    Map,
104}
105
106/// Scalar data extracted from the wire format.
107#[derive(Debug, Clone, PartialEq)]
108pub enum ScalarValue<'de> {
109    /// Null literal.
110    Null,
111    /// Boolean literal.
112    Bool(bool),
113    /// Character literal.
114    Char(char),
115    /// Signed integer literal (fits in i64).
116    I64(i64),
117    /// Unsigned integer literal (fits in u64).
118    U64(u64),
119    /// Signed 128-bit integer literal.
120    I128(i128),
121    /// Unsigned 128-bit integer literal.
122    U128(u128),
123    /// Floating-point literal.
124    F64(f64),
125    /// UTF-8 string literal (definitely a string, not a number).
126    Str(Cow<'de, str>),
127    /// Binary literal.
128    Bytes(Cow<'de, [u8]>),
129    /// Stringly-typed value from formats like XML where all values are text.
130    ///
131    /// Unlike `Str`, this value's type is ambiguous - it could be a number,
132    /// boolean, or actual string depending on the target type. The deserializer
133    /// will attempt to parse it according to the expected type.
134    ///
135    /// Examples:
136    /// - XML `<value>42</value>` → StringlyTyped("42") → parses as i32, u64, String, etc.
137    /// - XML `<value>2.5</value>` → StringlyTyped("2.5") → parses as f64, Decimal, String, etc.
138    /// - JSON `"42"` → Str("42") → definitely a string, not a number
139    StringlyTyped(Cow<'de, str>),
140}
141
142/// Event emitted by a format parser while streaming through input.
143#[derive(Clone, PartialEq)]
144pub enum ParseEvent<'de> {
145    /// Beginning of a struct/object/node.
146    StructStart(ContainerKind),
147    /// End of a struct/object/node.
148    StructEnd,
149    /// Encountered a field key (for self-describing formats like JSON/YAML).
150    FieldKey(FieldKey<'de>),
151    /// Next field value in struct field order (for non-self-describing formats like postcard).
152    ///
153    /// The driver tracks the current field index and uses the schema to determine
154    /// which field this value belongs to. This allows formats without field names
155    /// in the wire format to still support Tier-0 deserialization.
156    OrderedField,
157    /// Beginning of a sequence/array/tuple.
158    SequenceStart(ContainerKind),
159    /// End of a sequence/array/tuple.
160    SequenceEnd,
161    /// Scalar literal.
162    Scalar(ScalarValue<'de>),
163    /// Variant discriminant that needs to be propagated to the solver.
164    VariantTag(&'de str),
165}
166
167impl<'de> fmt::Debug for ParseEvent<'de> {
168    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169        match self {
170            ParseEvent::StructStart(kind) => f.debug_tuple("StructStart").field(kind).finish(),
171            ParseEvent::StructEnd => f.write_str("StructEnd"),
172            ParseEvent::FieldKey(key) => f.debug_tuple("FieldKey").field(key).finish(),
173            ParseEvent::OrderedField => f.write_str("OrderedField"),
174            ParseEvent::SequenceStart(kind) => f.debug_tuple("SequenceStart").field(kind).finish(),
175            ParseEvent::SequenceEnd => f.write_str("SequenceEnd"),
176            ParseEvent::Scalar(value) => f.debug_tuple("Scalar").field(value).finish(),
177            ParseEvent::VariantTag(tag) => f.debug_tuple("VariantTag").field(tag).finish(),
178        }
179    }
180}