1use crate::errors::Result;
4use crate::mark::Mark;
5#[cfg(test)]
6use crate::scan::parts::ToPart;
7use crate::scan::parts::{IntoPartVec, Part};
8use crate::scan::Scanner;
9use serde::de::{self, DeserializeSeed, Deserializer, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor};
10use toml::Spanned;
11
12pub struct TomlScanner {
13 target: Vec<Part>
14}
15
16impl TomlScanner {
17 pub fn new(target: &str) -> TomlScanner { TomlScanner { target: target.into_part_vec() } }
18
19 #[cfg(test)]
20 pub fn from_parts(target: &[&dyn ToPart]) -> TomlScanner { TomlScanner { target: target.into_part_vec() } }
21}
22
23impl Scanner for TomlScanner {
24 fn build(parts: Vec<Part>) -> TomlScanner { TomlScanner { target: parts } }
25 fn find(&self, data: &str) -> Result<Mark> { scan_toml(data, self.target.clone()) }
26}
27
28fn scan_toml<P: IntoPartVec>(data: &str, loc: P) -> Result<Mark> {
29 let mut parts = loc.into_part_vec();
30 parts.reverse();
31
32 let value = pop(parts).deserialize(toml::Deserializer::new(data))?;
33 let index = value.span().start;
34
35 Ok(Mark::new(value.into_inner(), index + 1))
36}
37
38fn pop(mut parts: Vec<Part>) -> NthElement {
39 let part = parts.pop().unwrap();
40 NthElement::new(part, parts)
41}
42
43pub struct NthElement {
44 part: Part,
45 remains: Vec<Part>
46}
47
48impl NthElement {
49 pub fn new(part: Part, remains: Vec<Part>) -> NthElement { NthElement { part, remains } }
50}
51
52impl<'de> Visitor<'de> for NthElement {
53 type Value = Spanned<String>;
54
55 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
56 write!(formatter, "a part that is {:?}", self.part)
57 }
58
59 fn visit_map<V>(mut self, mut map: V) -> std::result::Result<Self::Value, V::Error>
60 where
61 V: MapAccess<'de>
62 {
63 let expected_key: String = match &self.part {
64 Part::Map(key) => key.clone(),
65 _ => return Err(de::Error::invalid_type(Unexpected::Map, &self))
66 };
67
68 let mut got_val: Option<Spanned<String>> = None;
69
70 while let Some(key) = map.next_key::<String>()? {
71 if key == expected_key {
72 let nth = if self.remains.is_empty() {
73 map.next_value()?
74 } else {
75 let next = pop(std::mem::take(&mut self.remains));
76 map.next_value_seed(next)?
77 };
78
79 got_val = Some(nth);
80 break;
81 } else {
82 map.next_value::<IgnoredAny>()?;
83 }
84 }
85
86 while let Some((IgnoredAny, IgnoredAny)) = map.next_entry()? {}
87
88 let ista = got_val.ok_or_else(|| de::Error::missing_field("<missing field>"))?;
89 Ok(ista)
90 }
91
92 fn visit_seq<V>(mut self, mut seq: V) -> std::result::Result<Self::Value, V::Error>
93 where
94 V: SeqAccess<'de>
95 {
96 let n = match &self.part {
97 Part::Seq(n) => *n,
98 _ => return Err(de::Error::invalid_type(Unexpected::Seq, &self))
99 };
100
101 for i in 0 .. n {
102 if seq.next_element::<IgnoredAny>()?.is_none() {
103 return Err(de::Error::invalid_length(i, &self));
104 }
105 }
106
107 let nth = if self.remains.is_empty() {
108 seq.next_element()?.ok_or_else(|| de::Error::invalid_length(n, &self))?
109 } else {
110 let next = pop(std::mem::take(&mut self.remains));
111 seq.next_element_seed(next)?.ok_or_else(|| de::Error::invalid_length(n, &self))?
112 };
113
114 while let Some(IgnoredAny) = seq.next_element()? {}
115
116 Ok(nth)
117 }
118}
119
120impl<'de> DeserializeSeed<'de> for NthElement {
121 type Value = Spanned<String>;
122
123 fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
124 where
125 D: Deserializer<'de>
126 {
127 deserializer.deserialize_any(self)
128 }
129}
130
131#[cfg(test)]
132mod test {
133 use super::TomlScanner;
134 use crate::scan::Scanner;
135
136 #[test]
137 fn test_toml() {
138 let doc = r#"
139version = "1.2.3""#;
140
141 let mark = TomlScanner::new("version").find(doc).unwrap();
142 assert_eq!("1.2.3", mark.value());
143 assert_eq!(12, mark.start());
144 }
145
146 #[test]
147 fn test_toml_seq() {
148 let doc = r#"
149thing = [ "thing2", "1.2.3" ]"#;
150
151 let mark = TomlScanner::new("thing.1").find(doc).unwrap();
152 assert_eq!("1.2.3", mark.value());
153 assert_eq!(22, mark.start());
154 }
155
156 #[test]
157 fn test_toml_complex() {
158 let doc = r#"
159[version]
160"thing" = [ "2.4.6", { "version" = "1.2.3" } ]"#;
161
162 let mark = TomlScanner::new("version.thing.1.version").find(doc).unwrap();
163 assert_eq!("1.2.3", mark.value());
164 assert_eq!(47, mark.start());
165 }
166
167 #[test]
168 fn test_toml_clever() {
169 let doc = r#"
170[[0]]
171"the.version" = "1.2.3""#;
172
173 let mark = TomlScanner::from_parts(&[&"0", &0, &"the.version"]).find(doc).unwrap();
174 assert_eq!("1.2.3", mark.value());
175 assert_eq!(24, mark.start());
176 }
177
178 #[test]
179 fn test_toml_utf8() {
180 let doc = r#"
181"thíng" = [ "thíng2", "1.2.3" ]"#;
182
183 let mark = TomlScanner::new("thíng.1").find(doc).unwrap();
184 assert_eq!("1.2.3", mark.value());
185 assert_eq!(26, mark.start());
186 }
187}