1use std::fmt;
17use std::marker::PhantomData;
18
19use schemars::JsonSchema;
20use serde::de::{
21 self, Deserialize, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, SeqAccess, Visitor,
22};
23
24use super::node::{Key, Kind, Node};
25
26pub const UNKNOWN: &str = "$unknown";
28const LOCATED: &str = "$dre::Located";
29const LOOSE: &str = "$dre::Loose";
30const ONE_OF: &str = "$dre::OneOf";
31
32pub fn from_node<'a, T: Deserialize<'a>>(node: &'a Node) -> Result<T, Error> {
34 T::deserialize(NodeDe(node, node.line))
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct Error {
40 pub line: Option<usize>,
41 pub message: String,
42}
43
44impl fmt::Display for Error {
45 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46 f.write_str(&self.message)
47 }
48}
49
50impl std::error::Error for Error {}
51
52impl de::Error for Error {
53 fn custom<T: fmt::Display>(msg: T) -> Self {
54 Error {
55 line: None,
56 message: msg.to_string(),
57 }
58 }
59}
60
61impl Error {
62 fn at(mut self, line: usize) -> Self {
63 if self.line.is_none() && line > 0 {
64 self.line = Some(line);
65 }
66 self
67 }
68}
69
70#[derive(Debug, Clone, PartialEq)]
73pub struct Located<T> {
74 pub value: T,
75 pub line: usize,
76 pub column: usize,
77}
78
79impl<T> Located<T> {
80 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Located<U> {
82 Located {
83 value: f(self.value),
84 line: self.line,
85 column: self.column,
86 }
87 }
88
89 pub fn line(&self) -> Option<usize> {
91 (self.line > 0).then_some(self.line)
92 }
93}
94
95impl<'de, T: Deserialize<'de>> Deserialize<'de> for Located<T> {
96 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
97 struct V<T>(PhantomData<T>);
98 impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
99 type Value = Located<T>;
100 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 f.write_str("a located value")
102 }
103 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
104 let line = seq.next_element()?.unwrap_or(0);
105 let column = seq.next_element()?.unwrap_or(0);
106 let value = seq
107 .next_element()?
108 .ok_or_else(|| de::Error::custom("a located value without a value"))?;
109 Ok(Located { value, line, column })
110 }
111 }
112 d.deserialize_newtype_struct(LOCATED, V(PhantomData))
113 }
114}
115
116impl<T: JsonSchema> JsonSchema for Located<T> {
117 fn schema_name() -> std::borrow::Cow<'static, str> {
118 T::schema_name()
119 }
120 fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
121 T::json_schema(g)
122 }
123 fn inline_schema() -> bool {
124 T::inline_schema()
125 }
126}
127
128#[derive(Debug, Clone, PartialEq)]
130pub enum Loose<T> {
131 Ok(T),
132 Bad(Found),
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct Found {
138 pub kind: &'static str,
140 pub line: usize,
141 pub problem: String,
143}
144
145impl<T> Loose<T> {
146 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Loose<U> {
147 match self {
148 Loose::Ok(v) => Loose::Ok(f(v)),
149 Loose::Bad(b) => Loose::Bad(b),
150 }
151 }
152
153 pub fn ok(&self) -> Option<&T> {
154 match self {
155 Loose::Ok(v) => Some(v),
156 Loose::Bad(_) => None,
157 }
158 }
159}
160
161impl<'de, T: Deserialize<'de>> Deserialize<'de> for Loose<T> {
162 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
163 struct V<T>(PhantomData<T>);
164 impl<'de, T: Deserialize<'de>> Visitor<'de> for V<T> {
165 type Value = Loose<T>;
166 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 f.write_str("a value")
168 }
169 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
170 match seq.next_element::<T>() {
171 Ok(Some(v)) => Ok(Loose::Ok(v)),
172 Ok(None) => Err(de::Error::custom("a loose value without a value")),
173 Err(e) => {
174 let line = seq.next_element::<usize>()?.unwrap_or(0);
175 let kind = seq.next_element::<String>()?.unwrap_or_default();
176 Ok(Loose::Bad(Found {
177 kind: kind_name(&kind),
178 line,
179 problem: e.to_string(),
180 }))
181 }
182 }
183 }
184 }
185 d.deserialize_newtype_struct(LOOSE, V(PhantomData))
186 }
187}
188
189fn kind_name(name: &str) -> &'static str {
190 ["nothing", "a boolean", "a number", "a string", "a list", "a map"]
191 .into_iter()
192 .find(|k| *k == name)
193 .unwrap_or("a value")
194}
195
196impl<T: JsonSchema> JsonSchema for Loose<T> {
197 fn schema_name() -> std::borrow::Cow<'static, str> {
198 T::schema_name()
199 }
200 fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
201 T::json_schema(g)
202 }
203 fn inline_schema() -> bool {
204 T::inline_schema()
205 }
206}
207
208#[derive(Debug, Clone, Default, PartialEq)]
211pub enum Maybe<T> {
212 #[default]
213 Absent,
214 Given(T),
215}
216
217impl<'de, T: Deserialize<'de>> Deserialize<'de> for Maybe<T> {
218 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
219 T::deserialize(d).map(Maybe::Given)
220 }
221}
222
223impl<T: JsonSchema> JsonSchema for Maybe<T> {
224 fn schema_name() -> std::borrow::Cow<'static, str> {
225 T::schema_name()
226 }
227 fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
228 T::json_schema(g)
229 }
230 fn inline_schema() -> bool {
231 T::inline_schema()
232 }
233}
234
235#[derive(Debug, Clone, PartialEq, Eq)]
237pub struct Text(pub String);
238
239impl<'de> Deserialize<'de> for Text {
240 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
241 struct V;
242 impl Visitor<'_> for V {
243 type Value = Text;
244 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 f.write_str("a string")
246 }
247 fn visit_str<E>(self, v: &str) -> Result<Text, E> {
248 Ok(Text(v.to_string()))
249 }
250 fn visit_bool<E>(self, v: bool) -> Result<Text, E> {
251 Ok(Text(v.to_string()))
252 }
253 fn visit_i64<E>(self, v: i64) -> Result<Text, E> {
254 Ok(Text(v.to_string()))
255 }
256 fn visit_u64<E>(self, v: u64) -> Result<Text, E> {
257 Ok(Text(v.to_string()))
258 }
259 fn visit_f64<E>(self, v: f64) -> Result<Text, E> {
260 Ok(Text(v.to_string()))
261 }
262 }
263 d.deserialize_any(V)
264 }
265}
266
267impl JsonSchema for Text {
268 fn schema_name() -> std::borrow::Cow<'static, str> {
269 "String".into()
270 }
271 fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
272 String::json_schema(g)
273 }
274 fn inline_schema() -> bool {
275 true
276 }
277}
278
279#[derive(Debug, Clone, PartialEq)]
281pub enum OneOf<A, B> {
282 A(A),
283 B(B),
284}
285
286impl<'de, A: Deserialize<'de>, B: Deserialize<'de>> Deserialize<'de> for OneOf<A, B> {
287 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
288 struct V<A, B>(PhantomData<(A, B)>);
289 impl<'de, A: Deserialize<'de>, B: Deserialize<'de>> Visitor<'de> for V<A, B> {
290 type Value = OneOf<A, B>;
291 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
292 f.write_str("one of two shapes")
293 }
294 fn visit_seq<S: SeqAccess<'de>>(self, mut seq: S) -> Result<Self::Value, S::Error> {
295 if let Ok(Some(a)) = seq.next_element::<A>() {
296 return Ok(OneOf::A(a));
297 }
298 match seq.next_element::<B>()? {
299 Some(b) => Ok(OneOf::B(b)),
300 None => Err(de::Error::custom("one of two shapes without a value")),
301 }
302 }
303 }
304 d.deserialize_newtype_struct(ONE_OF, V(PhantomData))
305 }
306}
307
308impl<A: JsonSchema, B: JsonSchema> JsonSchema for OneOf<A, B> {
309 fn schema_name() -> std::borrow::Cow<'static, str> {
310 format!("OneOf_{}_{}", A::schema_name(), B::schema_name()).into()
311 }
312 fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
313 let mut alternatives = Vec::new();
315 for s in [g.subschema_for::<A>(), g.subschema_for::<B>()] {
316 match s.as_object() {
317 Some(o) if o.len() == 1 && o.contains_key("oneOf") => {
318 alternatives.extend(o["oneOf"].as_array().into_iter().flatten().cloned());
319 }
320 _ => alternatives.push(s.to_value()),
321 }
322 }
323 schemars::json_schema!({"oneOf": alternatives})
324 }
325 fn inline_schema() -> bool {
326 true
327 }
328}
329
330#[derive(Debug, Clone, Default, PartialEq, Eq)]
332pub struct UnknownKeys(pub Vec<Key>);
333
334impl<'de> Deserialize<'de> for UnknownKeys {
335 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
336 struct V;
337 impl<'de> Visitor<'de> for V {
338 type Value = UnknownKeys;
339 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
340 f.write_str("unknown keys")
341 }
342 fn visit_map<A: MapAccess<'de>>(self, mut m: A) -> Result<UnknownKeys, A::Error> {
343 let mut keys = Vec::new();
344 while let Some((k, _)) = m.next_entry::<Located<String>, de::IgnoredAny>()? {
345 keys.push(Key {
346 name: k.value,
347 line: k.line,
348 });
349 }
350 Ok(UnknownKeys(keys))
351 }
352 }
353 d.deserialize_map(V)
354 }
355}
356
357#[derive(Debug, Clone, PartialEq)]
359pub struct Map<V>(pub Vec<(Located<String>, V)>);
360
361impl<V> Default for Map<V> {
362 fn default() -> Self {
363 Map(Vec::new())
364 }
365}
366
367impl<V> Map<V> {
368 pub fn iter(&self) -> impl Iterator<Item = (&Located<String>, &V)> {
369 self.0.iter().map(|(k, v)| (k, v))
370 }
371 pub fn get(&self, key: &str) -> Option<&V> {
372 self.0.iter().find(|(k, _)| k.value == key).map(|(_, v)| v)
373 }
374 pub fn contains_key(&self, key: &str) -> bool {
375 self.get(key).is_some()
376 }
377 pub fn len(&self) -> usize {
378 self.0.len()
379 }
380 pub fn is_empty(&self) -> bool {
381 self.0.is_empty()
382 }
383}
384
385impl<'de, V: Deserialize<'de>> Deserialize<'de> for Map<V> {
386 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
387 struct Vis<V>(PhantomData<V>);
388 impl<'de, V: Deserialize<'de>> Visitor<'de> for Vis<V> {
389 type Value = Map<V>;
390 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
391 f.write_str("a map")
392 }
393 fn visit_unit<E>(self) -> Result<Map<V>, E> {
394 Ok(Map(Vec::new()))
395 }
396 fn visit_map<A: MapAccess<'de>>(self, mut m: A) -> Result<Map<V>, A::Error> {
397 let mut entries = Vec::new();
398 while let Some(e) = m.next_entry()? {
399 entries.push(e);
400 }
401 Ok(Map(entries))
402 }
403 }
404 d.deserialize_map(Vis(PhantomData))
405 }
406}
407
408impl<V: JsonSchema> JsonSchema for Map<V> {
409 fn schema_name() -> std::borrow::Cow<'static, str> {
410 format!("Map_of_{}", V::schema_name()).into()
411 }
412 fn json_schema(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
413 schemars::json_schema!({"type": "object", "additionalProperties": g.subschema_for::<V>()})
414 }
415 fn inline_schema() -> bool {
416 true
417 }
418}
419
420struct KeyDe<'a>(&'a Key);
422
423impl<'de> Deserializer<'de> for KeyDe<'de> {
424 type Error = Error;
425 fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
426 v.visit_borrowed_str(&self.0.name)
427 }
428 fn deserialize_newtype_struct<V: Visitor<'de>>(
429 self,
430 name: &'static str,
431 v: V,
432 ) -> Result<V::Value, Error> {
433 if name == LOCATED {
434 v.visit_seq(KeySeq { key: self.0, at: 0 })
435 } else {
436 v.visit_newtype_struct(self)
437 }
438 }
439 serde::forward_to_deserialize_any! {
440 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option
441 unit unit_struct seq tuple tuple_struct map struct enum identifier ignored_any
442 }
443}
444
445struct KeySeq<'a> {
446 key: &'a Key,
447 at: usize,
448}
449
450impl<'a> SeqAccess<'a> for KeySeq<'a> {
451 type Error = Error;
452 fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
453 self.at += 1;
454 match self.at {
455 1 => seed.deserialize(self.key.line.into_deserializer()).map(Some),
456 2 => seed.deserialize(0usize.into_deserializer()).map(Some),
457 3 => seed.deserialize(KeyDe(self.key)).map(Some),
458 _ => Ok(None),
459 }
460 }
461}
462
463#[derive(Clone, Copy)]
466struct NodeDe<'a>(&'a Node, usize);
467
468impl<'a> NodeDe<'a> {
469 fn err(&self, msg: impl fmt::Display) -> Error {
470 Error {
471 line: (self.1 > 0).then_some(self.1),
472 message: msg.to_string(),
473 }
474 }
475
476 fn mismatch(&self, expected: &str) -> Error {
477 self.err(format!("expected {expected}, found {}", self.0.kind.name()))
478 }
479}
480
481macro_rules! via_any {
482 ($($m:ident)*) => {$(
483 fn $m<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
484 self.deserialize_any(v)
485 }
486 )*};
487}
488
489impl<'a> Deserializer<'a> for NodeDe<'a> {
490 type Error = Error;
491
492 fn deserialize_any<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
493 let line = self.0.line;
494 match &self.0.kind {
495 Kind::Null => v.visit_unit(),
496 Kind::Bool(b) => v.visit_bool(*b),
497 Kind::Int(i) => v.visit_i64(*i),
498 Kind::UInt(u) => v.visit_u64(*u),
499 Kind::Float(f) => v.visit_f64(*f),
500 Kind::Str(s) => v.visit_borrowed_str(s),
501 Kind::Seq(items) => v.visit_seq(Items(items.iter())),
502 Kind::Map(entries) => v.visit_map(Entries {
503 entries: entries.iter(),
504 value: None,
505 fields: None,
506 unknown: Vec::new(),
507 unknown_done: true,
508 }),
509 }
510 .map_err(|e| e.at(line))
511 }
512
513 via_any!(deserialize_bool deserialize_i8 deserialize_i16 deserialize_i32 deserialize_i64
514 deserialize_u8 deserialize_u16 deserialize_u32 deserialize_u64 deserialize_f32
515 deserialize_f64 deserialize_char deserialize_bytes deserialize_byte_buf
516 deserialize_unit deserialize_identifier deserialize_ignored_any);
517
518 fn deserialize_str<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
519 match &self.0.kind {
520 Kind::Str(s) => v.visit_borrowed_str(s),
521 _ => Err(self.mismatch("a string")),
522 }
523 }
524
525 fn deserialize_string<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
526 self.deserialize_str(v)
527 }
528
529 fn deserialize_option<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
530 match self.0.kind {
531 Kind::Null => v.visit_none(),
532 _ => v.visit_some(self),
533 }
534 }
535
536 fn deserialize_unit_struct<V: Visitor<'a>>(self, _: &'static str, v: V) -> Result<V::Value, Error> {
537 self.deserialize_unit(v)
538 }
539
540 fn deserialize_newtype_struct<V: Visitor<'a>>(self, name: &'static str, v: V) -> Result<V::Value, Error> {
541 match name {
542 LOCATED => v.visit_seq(LocatedSeq {
543 node: self.0,
544 line: self.1,
545 at: 0,
546 }),
547 LOOSE => v.visit_seq(LooseSeq {
548 node: self.0,
549 line: self.1,
550 at: 0,
551 }),
552 ONE_OF => v.visit_seq(OneOfSeq {
553 node: self.0,
554 line: self.1,
555 at: 0,
556 }),
557 _ => v.visit_newtype_struct(self),
558 }
559 }
560
561 fn deserialize_seq<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
562 match &self.0.kind {
563 Kind::Seq(items) => v.visit_seq(Items(items.iter())).map_err(|e| e.at(self.0.line)),
564 _ => Err(self.mismatch("a list")),
565 }
566 }
567
568 fn deserialize_tuple<V: Visitor<'a>>(self, _: usize, v: V) -> Result<V::Value, Error> {
569 self.deserialize_seq(v)
570 }
571
572 fn deserialize_tuple_struct<V: Visitor<'a>>(
573 self,
574 _: &'static str,
575 _: usize,
576 v: V,
577 ) -> Result<V::Value, Error> {
578 self.deserialize_seq(v)
579 }
580
581 fn deserialize_map<V: Visitor<'a>>(self, v: V) -> Result<V::Value, Error> {
582 match &self.0.kind {
583 Kind::Map(_) => self.deserialize_any(v),
584 _ => Err(self.mismatch("a map")),
585 }
586 }
587
588 fn deserialize_struct<V: Visitor<'a>>(
589 self,
590 _: &'static str,
591 fields: &'static [&'static str],
592 v: V,
593 ) -> Result<V::Value, Error> {
594 let Kind::Map(entries) = &self.0.kind else {
595 return Err(self.mismatch("a map"));
596 };
597 let collects = fields.contains(&UNKNOWN);
598 v.visit_map(Entries {
599 entries: entries.iter(),
600 value: None,
601 fields: Some(fields),
602 unknown: Vec::new(),
603 unknown_done: !collects,
604 })
605 .map_err(|e| e.at(self.0.line))
606 }
607
608 fn deserialize_enum<V: Visitor<'a>>(
609 self,
610 _: &'static str,
611 _: &'static [&'static str],
612 v: V,
613 ) -> Result<V::Value, Error> {
614 match &self.0.kind {
615 Kind::Str(s) => v.visit_enum(s.as_str().into_deserializer()),
616 _ => Err(self.mismatch("a name")),
617 }
618 }
619}
620
621struct Items<'a>(std::slice::Iter<'a, Node>);
622
623impl<'a> SeqAccess<'a> for Items<'a> {
624 type Error = Error;
625 fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
626 self.0
627 .next()
628 .map(|n| seed.deserialize(NodeDe(n, n.line)))
629 .transpose()
630 }
631 fn size_hint(&self) -> Option<usize> {
632 Some(self.0.len())
633 }
634}
635
636struct Entries<'a> {
637 entries: std::slice::Iter<'a, (Key, Node)>,
638 value: Option<(&'a Node, usize)>,
639 fields: Option<&'static [&'static str]>,
641 unknown: Vec<&'a (Key, Node)>,
642 unknown_done: bool,
643}
644
645enum Pending<'a> {
646 Node(&'a Node, usize),
647 Unknown(Vec<&'a (Key, Node)>),
648}
649
650impl<'a> MapAccess<'a> for Entries<'a> {
651 type Error = Error;
652
653 fn next_key_seed<K: DeserializeSeed<'a>>(&mut self, seed: K) -> Result<Option<K::Value>, Error> {
654 for entry in self.entries.by_ref() {
655 let (k, v) = entry;
656 if let Some(fields) = self.fields
657 && (!fields.contains(&k.name.as_str()) || k.name == UNKNOWN)
658 {
659 self.unknown.push(entry);
660 continue;
661 }
662 self.value = Some((v, k.line));
663 return seed.deserialize(KeyDe(k)).map(Some);
664 }
665 if !self.unknown_done {
666 self.unknown_done = true;
667 self.value = None;
668 return seed.deserialize(UNKNOWN.into_deserializer()).map(Some);
669 }
670 Ok(None)
671 }
672
673 fn next_value_seed<V: DeserializeSeed<'a>>(&mut self, seed: V) -> Result<V::Value, Error> {
674 let pending = match self.value.take() {
675 Some((n, line)) => Pending::Node(n, line),
676 None => Pending::Unknown(std::mem::take(&mut self.unknown)),
677 };
678 match pending {
679 Pending::Node(n, line) => seed.deserialize(NodeDe(n, line)),
680 Pending::Unknown(entries) => seed.deserialize(Rest(entries)),
681 }
682 }
683}
684
685struct Rest<'a>(Vec<&'a (Key, Node)>);
687
688impl<'de> Deserializer<'de> for Rest<'de> {
689 type Error = Error;
690 fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Error> {
691 v.visit_map(RestEntries {
692 entries: self.0.into_iter(),
693 value: None,
694 })
695 }
696 serde::forward_to_deserialize_any! {
697 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option
698 unit unit_struct newtype_struct seq tuple tuple_struct map struct enum identifier ignored_any
699 }
700}
701
702struct RestEntries<'a> {
703 entries: std::vec::IntoIter<&'a (Key, Node)>,
704 value: Option<&'a (Key, Node)>,
705}
706
707impl<'de> MapAccess<'de> for RestEntries<'de> {
708 type Error = Error;
709 fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>, Error> {
710 let Some(entry) = self.entries.next() else {
711 return Ok(None);
712 };
713 self.value = Some(entry);
714 seed.deserialize(KeyDe(&entry.0)).map(Some)
715 }
716 fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
717 let (k, v) = self.value.take().expect("a value follows its key");
718 seed.deserialize(NodeDe(v, k.line))
719 }
720}
721
722struct OneOfSeq<'a> {
724 node: &'a Node,
725 line: usize,
726 at: usize,
727}
728
729impl<'a> SeqAccess<'a> for OneOfSeq<'a> {
730 type Error = Error;
731 fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
732 self.at += 1;
733 match self.at {
734 1 | 2 => seed.deserialize(NodeDe(self.node, self.line)).map(Some),
735 _ => Ok(None),
736 }
737 }
738}
739
740struct LocatedSeq<'a> {
742 node: &'a Node,
743 line: usize,
744 at: usize,
745}
746
747impl<'a> SeqAccess<'a> for LocatedSeq<'a> {
748 type Error = Error;
749 fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
750 self.at += 1;
751 match self.at {
752 1 => seed.deserialize(self.line.into_deserializer()).map(Some),
753 2 => seed.deserialize(self.node.column.into_deserializer()).map(Some),
754 3 => seed.deserialize(NodeDe(self.node, self.line)).map(Some),
755 _ => Ok(None),
756 }
757 }
758}
759
760struct LooseSeq<'a> {
762 node: &'a Node,
763 line: usize,
764 at: usize,
765}
766
767impl<'a> SeqAccess<'a> for LooseSeq<'a> {
768 type Error = Error;
769 fn next_element_seed<T: DeserializeSeed<'a>>(&mut self, seed: T) -> Result<Option<T::Value>, Error> {
770 self.at += 1;
771 match self.at {
772 1 => seed.deserialize(NodeDe(self.node, self.line)).map(Some),
773 2 => seed.deserialize(self.line.into_deserializer()).map(Some),
774 3 => seed
775 .deserialize(self.node.kind.name().into_deserializer())
776 .map(Some),
777 _ => Ok(None),
778 }
779 }
780}
781
782#[cfg(test)]
783mod tests {
784 use std::collections::BTreeMap;
785
786 use serde::Deserialize;
787
788 use super::*;
789 use crate::config::node::parse;
790
791 #[derive(Debug, Deserialize)]
792 struct Profile {
793 target: Option<Located<Loose<String>>>,
794 targets: Option<Loose<BTreeMap<String, Located<serde_json::Value>>>>,
795 #[serde(rename = "$unknown", default)]
796 unknown: UnknownKeys,
797 }
798
799 #[test]
800 fn values_keep_their_lines_and_unknown_keys_are_collected() {
801 let n = parse("target: prod\nwat: 1\ntargets:\n dev: {type: duckdb}\nalso: 2\n").unwrap();
802 let p: Profile = from_node(&n).unwrap();
803 let t = p.target.unwrap();
804 assert_eq!((t.value.ok().map(String::as_str), t.line), (Some("prod"), 1));
805 let targets = p.targets.unwrap();
806 let dev = &targets.ok().unwrap()["dev"];
807 assert_eq!(dev.line, 4);
808 assert_eq!(dev.value["type"], "duckdb");
809 let unknown: Vec<_> = p.unknown.0.iter().map(|k| (k.name.as_str(), k.line)).collect();
810 assert_eq!(unknown, [("wat", 2), ("also", 5)]);
811 }
812
813 #[test]
814 fn a_wrong_shape_is_kept_with_its_line_and_the_rest_still_reads() {
815 let n = parse("target: [a]\ntargets: x\n").unwrap();
816 let p: Profile = from_node(&n).unwrap();
817 let Loose::Bad(f) = p.target.unwrap().value else {
818 panic!()
819 };
820 assert_eq!((f.kind, f.line), ("a list", 1));
821 let Loose::Bad(f) = p.targets.unwrap() else {
822 panic!()
823 };
824 assert_eq!((f.kind, f.line), ("a string", 2));
825 }
826
827 #[test]
828 fn the_unknown_field_can_read_the_other_keys_values() {
829 #[derive(Debug, Deserialize)]
830 struct Folder {
831 #[serde(rename = "+tags", default)]
832 tags: Vec<String>,
833 #[serde(rename = "$unknown", default)]
834 folders: Map<Folder>,
835 }
836 let n = parse("+tags: [a]\nsales:\n +tags: [b]\n eu: {}\n").unwrap();
837 let f: Folder = from_node(&n).unwrap();
838 let (name, sales) = f.folders.iter().next().unwrap();
839 assert_eq!(
840 (name.value.as_str(), name.line, &sales.tags[..]),
841 ("sales", 2, &["b".to_string()][..])
842 );
843 assert_eq!(sales.folders.iter().next().unwrap().0.value, "eu");
844 assert_eq!(f.tags, ["a"]);
845 }
846
847 #[test]
848 fn one_of_reads_either_shape_and_keeps_lines() {
849 #[derive(Debug, Deserialize)]
850 struct Entry {
851 query: Located<String>,
852 #[serde(rename = "$unknown", default)]
853 unknown: UnknownKeys,
854 }
855 let n = parse("- a\n- {query: b, x: 1}\n- [c]\n").unwrap();
856 let items: Vec<Loose<OneOf<String, Entry>>> = from_node(&n).unwrap();
857 assert!(
858 matches!(&items[0], Loose::Ok(OneOf::A(s)) if s == "a"),
859 "{:?}",
860 items[0]
861 );
862 let Loose::Ok(OneOf::B(e)) = &items[1] else {
863 panic!()
864 };
865 assert_eq!(
866 (e.query.value.as_str(), e.query.line, e.unknown.0[0].name.as_str()),
867 ("b", 2, "x")
868 );
869 assert!(matches!(&items[2], Loose::Bad(f) if f.kind == "a list" && f.line == 3));
870 }
871
872 #[test]
873 fn maps_keep_the_file_order_and_each_keys_line() {
874 let n = parse("b: 1\na: 2\n").unwrap();
875 let m: Map<u32> = from_node(&n).unwrap();
876 let got: Vec<_> = m.iter().map(|(k, v)| (k.value.as_str(), k.line, *v)).collect();
877 assert_eq!(got, [("b", 1, 1), ("a", 2, 2)]);
878 }
879
880 #[test]
881 fn errors_outside_loose_values_have_a_line() {
882 #[derive(Debug, Deserialize)]
883 #[allow(dead_code)]
884 struct S {
885 n: u32,
886 }
887 let n = parse("n: lots\n").unwrap();
888 let e = from_node::<S>(&n).unwrap_err();
889 assert_eq!(e.line, Some(1));
890 }
891
892 #[test]
893 fn a_struct_without_the_unknown_field_ignores_other_keys() {
894 #[derive(Debug, Deserialize)]
895 struct S {
896 a: u32,
897 }
898 let n = parse("a: 1\nb: 2\n").unwrap();
899 assert_eq!(from_node::<S>(&n).unwrap().a, 1);
900 }
901}