1extern crate alloc;
8
9use alloc::borrow::Cow;
10use alloc::collections::BTreeMap;
11use alloc::collections::BTreeSet;
12use alloc::format;
13use alloc::string::String;
14use alloc::string::ToString;
15use alloc::vec::Vec;
16use core::fmt;
17
18use facet_core::{Field, Shape};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Default)]
26pub enum FieldCategory {
27 #[default]
30 Flat,
31 Attribute,
33 Element,
35 Text,
37 Tag,
39 Elements,
41}
42
43impl FieldCategory {
44 pub fn from_field_dom(field: &Field) -> Option<Self> {
49 if field.is_flattened() {
50 return None;
52 }
53 if field.is_attribute() {
54 Some(FieldCategory::Attribute)
55 } else if field.is_text() {
56 Some(FieldCategory::Text)
57 } else if field.is_tag() {
58 Some(FieldCategory::Tag)
59 } else if field.is_elements() {
60 Some(FieldCategory::Elements)
61 } else {
62 Some(FieldCategory::Element)
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub enum FieldKey<'a> {
74 Flat(Cow<'a, str>),
76 Dom(FieldCategory, Cow<'a, str>),
78}
79
80impl<'a> FieldKey<'a> {
81 pub fn flat(name: impl Into<Cow<'a, str>>) -> Self {
83 FieldKey::Flat(name.into())
84 }
85
86 pub fn attribute(name: impl Into<Cow<'a, str>>) -> Self {
88 FieldKey::Dom(FieldCategory::Attribute, name.into())
89 }
90
91 pub fn element(name: impl Into<Cow<'a, str>>) -> Self {
93 FieldKey::Dom(FieldCategory::Element, name.into())
94 }
95
96 pub fn text() -> Self {
98 FieldKey::Dom(FieldCategory::Text, Cow::Borrowed(""))
99 }
100
101 pub fn tag() -> Self {
103 FieldKey::Dom(FieldCategory::Tag, Cow::Borrowed(""))
104 }
105
106 pub fn elements() -> Self {
108 FieldKey::Dom(FieldCategory::Elements, Cow::Borrowed(""))
109 }
110
111 pub fn name(&self) -> &str {
113 match self {
114 FieldKey::Flat(name) => name.as_ref(),
115 FieldKey::Dom(_, name) => name.as_ref(),
116 }
117 }
118
119 pub fn category(&self) -> Option<FieldCategory> {
121 match self {
122 FieldKey::Flat(_) => None,
123 FieldKey::Dom(cat, _) => Some(*cat),
124 }
125 }
126
127 pub fn into_owned(self) -> FieldKey<'static> {
129 match self {
130 FieldKey::Flat(name) => FieldKey::Flat(Cow::Owned(name.into_owned())),
131 FieldKey::Dom(cat, name) => FieldKey::Dom(cat, Cow::Owned(name.into_owned())),
132 }
133 }
134}
135
136impl<'a> From<&'a str> for FieldKey<'a> {
138 fn from(s: &'a str) -> Self {
139 FieldKey::Flat(Cow::Borrowed(s))
140 }
141}
142
143impl From<String> for FieldKey<'static> {
144 fn from(s: String) -> Self {
145 FieldKey::Flat(Cow::Owned(s))
146 }
147}
148
149impl<'a> From<&'a String> for FieldKey<'a> {
150 fn from(s: &'a String) -> Self {
151 FieldKey::Flat(Cow::Borrowed(s.as_str()))
152 }
153}
154
155impl<'a> From<Cow<'a, str>> for FieldKey<'a> {
156 fn from(s: Cow<'a, str>) -> Self {
157 FieldKey::Flat(s)
158 }
159}
160
161impl fmt::Display for FieldKey<'_> {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 match self {
164 FieldKey::Flat(name) => write!(f, "{}", name),
165 FieldKey::Dom(cat, name) => write!(f, "{:?}:{}", cat, name),
166 }
167 }
168}
169
170pub type KeyPath = Vec<&'static str>;
174
175pub type DomKeyPath = Vec<FieldKey<'static>>;
178
179#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
181pub enum PathSegment {
182 Field(&'static str),
184 Variant(&'static str, &'static str),
186}
187
188#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
190pub struct FieldPath {
191 segments: Vec<PathSegment>,
192}
193
194impl fmt::Debug for FieldPath {
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 write!(f, "FieldPath(")?;
197 for (i, seg) in self.segments.iter().enumerate() {
198 if i > 0 {
199 write!(f, ".")?;
200 }
201 match seg {
202 PathSegment::Field(name) => write!(f, "{name}")?,
203 PathSegment::Variant(field, variant) => write!(f, "{field}::{variant}")?,
204 }
205 }
206 write!(f, ")")
207 }
208}
209
210impl fmt::Display for FieldPath {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 let mut first = true;
213 for seg in &self.segments {
214 match seg {
215 PathSegment::Field(name) => {
216 if !first {
217 write!(f, ".")?;
218 }
219 write!(f, "{name}")?;
220 first = false;
221 }
222 PathSegment::Variant(_, _) => {
223 }
225 }
226 }
227 Ok(())
228 }
229}
230
231impl FieldPath {
232 pub const fn empty() -> Self {
234 Self {
235 segments: Vec::new(),
236 }
237 }
238
239 pub const fn depth(&self) -> usize {
241 self.segments.len()
242 }
243
244 pub fn push_field(&self, name: &'static str) -> Self {
246 let mut new = self.clone();
247 new.segments.push(PathSegment::Field(name));
248 new
249 }
250
251 pub fn push_variant(&self, field_name: &'static str, variant_name: &'static str) -> Self {
253 let mut new = self.clone();
254 new.segments
255 .push(PathSegment::Variant(field_name, variant_name));
256 new
257 }
258
259 pub fn parent(&self) -> Self {
261 let mut new = self.clone();
262 new.segments.pop();
263 new
264 }
265
266 pub fn segments(&self) -> &[PathSegment] {
268 &self.segments
269 }
270
271 pub fn last(&self) -> Option<&PathSegment> {
273 self.segments.last()
274 }
275}
276
277#[derive(Debug, Clone)]
279pub struct VariantSelection {
280 pub path: FieldPath,
282 pub enum_name: &'static str,
284 pub variant_name: &'static str,
286}
287
288#[derive(Debug, Clone)]
290pub struct FieldInfo {
291 pub serialized_name: &'static str,
293
294 pub path: FieldPath,
296
297 pub required: bool,
299
300 pub value_shape: &'static Shape,
302
303 pub field: &'static Field,
305
306 pub category: FieldCategory,
308}
309
310impl PartialEq for FieldInfo {
311 fn eq(&self, other: &Self) -> bool {
312 self.serialized_name == other.serialized_name
313 && self.path == other.path
314 && self.required == other.required
315 && core::ptr::eq(self.value_shape, other.value_shape)
316 && core::ptr::eq(self.field, other.field)
317 && self.category == other.category
318 }
319}
320
321impl FieldInfo {
322 pub fn key(&self) -> FieldKey<'static> {
324 match self.category {
325 FieldCategory::Flat => FieldKey::Flat(Cow::Borrowed(self.serialized_name)),
326 cat => FieldKey::Dom(cat, Cow::Borrowed(self.serialized_name)),
327 }
328 }
329}
330
331impl Eq for FieldInfo {}
332
333#[derive(Debug)]
335pub enum MatchResult {
336 Exact,
338 WithOptionalMissing(Vec<&'static str>),
340 NoMatch {
342 missing_required: Vec<&'static str>,
344 unknown: Vec<String>,
346 },
347}
348
349#[derive(Debug, Clone)]
355pub struct Resolution {
356 variant_selections: Vec<VariantSelection>,
359
360 fields: BTreeMap<FieldKey<'static>, FieldInfo>,
364
365 required_field_names: BTreeSet<&'static str>,
367
368 known_paths: BTreeSet<KeyPath>,
372
373 dom_known_paths: BTreeSet<DomKeyPath>,
376
377 catch_all_maps: BTreeMap<FieldCategory, FieldInfo>,
381}
382
383#[derive(Debug, Clone)]
385pub struct DuplicateFieldError {
386 pub field_name: &'static str,
388 pub first_path: FieldPath,
390 pub second_path: FieldPath,
392}
393
394impl fmt::Display for DuplicateFieldError {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 write!(
397 f,
398 "duplicate field '{}': found at {} and {}",
399 self.field_name, self.first_path, self.second_path
400 )
401 }
402}
403
404impl Resolution {
405 pub const fn new() -> Self {
407 Self {
408 variant_selections: Vec::new(),
409 fields: BTreeMap::new(),
410 required_field_names: BTreeSet::new(),
411 known_paths: BTreeSet::new(),
412 dom_known_paths: BTreeSet::new(),
413 catch_all_maps: BTreeMap::new(),
414 }
415 }
416
417 pub fn set_catch_all_map(&mut self, category: FieldCategory, info: FieldInfo) {
419 self.catch_all_maps.insert(category, info);
420 }
421
422 pub fn catch_all_map(&self, category: FieldCategory) -> Option<&FieldInfo> {
424 self.catch_all_maps.get(&category)
425 }
426
427 pub fn catch_all_maps(&self) -> &BTreeMap<FieldCategory, FieldInfo> {
429 &self.catch_all_maps
430 }
431
432 pub fn add_key_path(&mut self, path: KeyPath) {
434 self.known_paths.insert(path);
435 }
436
437 pub fn add_dom_key_path(&mut self, path: DomKeyPath) {
439 self.dom_known_paths.insert(path);
440 }
441
442 pub fn add_field(&mut self, info: FieldInfo) -> Result<(), DuplicateFieldError> {
448 let key = info.key();
449 if let Some(existing) = self.fields.get(&key)
450 && existing.path != info.path
451 {
452 return Err(DuplicateFieldError {
453 field_name: info.serialized_name,
454 first_path: existing.path.clone(),
455 second_path: info.path,
456 });
457 }
458 if info.required {
459 self.required_field_names.insert(info.serialized_name);
460 }
461 self.fields.insert(key, info);
462 Ok(())
463 }
464
465 pub fn add_variant_selection(
467 &mut self,
468 path: FieldPath,
469 enum_name: &'static str,
470 variant_name: &'static str,
471 ) {
472 self.variant_selections.push(VariantSelection {
473 path,
474 enum_name,
475 variant_name,
476 });
477 }
478
479 pub fn merge(&mut self, other: &Resolution) -> Result<(), DuplicateFieldError> {
485 for (key, info) in &other.fields {
486 if let Some(existing) = self.fields.get(key)
487 && existing.path != info.path
488 {
489 return Err(DuplicateFieldError {
490 field_name: info.serialized_name,
491 first_path: existing.path.clone(),
492 second_path: info.path.clone(),
493 });
494 }
495 self.fields.insert(key.clone(), info.clone());
496 if info.required {
497 self.required_field_names.insert(info.serialized_name);
498 }
499 }
500 for vs in &other.variant_selections {
501 self.variant_selections.push(vs.clone());
502 }
503 for path in &other.known_paths {
504 self.known_paths.insert(path.clone());
505 }
506 for path in &other.dom_known_paths {
507 self.dom_known_paths.insert(path.clone());
508 }
509 for (cat, info) in &other.catch_all_maps {
511 self.catch_all_maps.insert(*cat, info.clone());
512 }
513 Ok(())
514 }
515
516 pub fn mark_all_optional(&mut self) {
519 self.required_field_names.clear();
520 for info in self.fields.values_mut() {
521 info.required = false;
522 }
523 }
524
525 pub fn matches(&self, input_fields: &BTreeSet<Cow<'_, str>>) -> MatchResult {
527 let mut missing_required = Vec::new();
528 let mut missing_optional = Vec::new();
529
530 for info in self.fields.values() {
531 if !input_fields
532 .iter()
533 .any(|k| k.as_ref() == info.serialized_name)
534 {
535 if info.required {
536 missing_required.push(info.serialized_name);
537 } else {
538 missing_optional.push(info.serialized_name);
539 }
540 }
541 }
542
543 let unknown: Vec<String> = input_fields
545 .iter()
546 .filter(|f| {
547 !self
548 .fields
549 .values()
550 .any(|info| info.serialized_name == f.as_ref())
551 })
552 .map(|s| s.to_string())
553 .collect();
554
555 if !missing_required.is_empty() || !unknown.is_empty() {
556 MatchResult::NoMatch {
557 missing_required,
558 unknown,
559 }
560 } else if missing_optional.is_empty() {
561 MatchResult::Exact
562 } else {
563 MatchResult::WithOptionalMissing(missing_optional)
564 }
565 }
566
567 pub fn describe(&self) -> String {
572 if self.variant_selections.is_empty() {
573 String::from("(no variants)")
574 } else {
575 let parts: Vec<_> = self
576 .variant_selections
577 .iter()
578 .map(|vs| format!("{}::{}", vs.enum_name, vs.variant_name))
579 .collect();
580 parts.join(" + ")
581 }
582 }
583
584 pub fn deserialization_order(&self) -> Vec<&FieldInfo> {
586 let mut fields: Vec<_> = self.fields.values().collect();
587 fields.sort_by(|a, b| {
588 b.path
590 .depth()
591 .cmp(&a.path.depth())
592 .then_with(|| a.path.cmp(&b.path))
594 });
595 fields
596 }
597
598 pub fn field(&self, key: &FieldKey<'static>) -> Option<&FieldInfo> {
602 self.fields.get(key)
603 }
604
605 pub fn field_by_key(&self, key: &FieldKey<'_>) -> Option<&FieldInfo> {
610 self.fields.iter().find_map(|(k, v)| {
611 let matches = match (k, key) {
613 (FieldKey::Flat(a), FieldKey::Flat(b)) => a.as_ref() == b.as_ref(),
614 (FieldKey::Dom(cat_a, a), FieldKey::Dom(cat_b, b)) => {
615 cat_a == cat_b && a.as_ref() == b.as_ref()
616 }
617 _ => false,
618 };
619 if matches { Some(v) } else { None }
620 })
621 }
622
623 pub fn field_by_name(&self, name: &str) -> Option<&FieldInfo> {
626 self.fields.values().find(|f| f.serialized_name == name)
628 }
629
630 pub const fn fields(&self) -> &BTreeMap<FieldKey<'static>, FieldInfo> {
632 &self.fields
633 }
634
635 pub const fn required_field_names(&self) -> &BTreeSet<&'static str> {
637 &self.required_field_names
638 }
639
640 pub fn missing_optional_fields<'a>(
645 &'a self,
646 seen_keys: &'a BTreeSet<Cow<'_, str>>,
647 ) -> impl Iterator<Item = &'a FieldInfo> {
648 self.fields.values().filter(move |info| {
649 !info.required && !seen_keys.iter().any(|k| k.as_ref() == info.serialized_name)
650 })
651 }
652
653 pub fn variant_selections(&self) -> &[VariantSelection] {
655 &self.variant_selections
656 }
657
658 pub fn child_fields(&self) -> impl Iterator<Item = &FieldInfo> {
663 self.fields.values().filter(|f| f.field.is_child())
664 }
665
666 pub fn property_fields(&self) -> impl Iterator<Item = &FieldInfo> {
671 self.fields.values().filter(|f| !f.field.is_child())
672 }
673
674 pub const fn known_paths(&self) -> &BTreeSet<KeyPath> {
676 &self.known_paths
677 }
678
679 pub fn has_key_path(&self, path: &[&str]) -> bool {
681 self.known_paths.iter().any(|known| {
682 known.len() == path.len() && known.iter().zip(path.iter()).all(|(a, b)| *a == *b)
683 })
684 }
685
686 pub fn has_dom_key_path(&self, path: &[FieldKey<'_>]) -> bool {
688 self.dom_known_paths.iter().any(|known| {
689 known.len() == path.len()
690 && known.iter().zip(path.iter()).all(|(a, b)| {
691 match (a, b) {
693 (FieldKey::Flat(sa), FieldKey::Flat(sb)) => sa.as_ref() == sb.as_ref(),
694 (FieldKey::Dom(ca, sa), FieldKey::Dom(cb, sb)) => {
695 ca == cb && sa.as_ref() == sb.as_ref()
696 }
697 _ => false,
698 }
699 })
700 })
701 }
702
703 pub const fn dom_known_paths(&self) -> &BTreeSet<DomKeyPath> {
705 &self.dom_known_paths
706 }
707}
708
709impl Default for Resolution {
710 fn default() -> Self {
711 Self::new()
712 }
713}