cbor_data/validated/
indexing.rs1use crate::{constants::TAG_CBOR_ITEM, Cbor, CborOwned, ItemKind, TaggedItem, Visitor};
2use std::borrow::Cow;
3
4pub struct IndexVisitor<'a, I: Iterator> {
5 iter: Option<I>,
6 arr_idx: Option<u64>,
7 dict_idx: Option<PathElement<'a>>,
8}
9
10impl<'a, I: Iterator<Item = PathElement<'a>>> IndexVisitor<'a, I> {
11 pub fn new(iter: I) -> Self {
12 Self {
13 iter: Some(iter),
14 arr_idx: None,
15 dict_idx: None,
16 }
17 }
18
19 fn iter(&mut self) -> &mut I {
20 self.iter.as_mut().unwrap()
21 }
22}
23
24impl<'a, 'b, I: Iterator<Item = PathElement<'b>>> Visitor<'a, Option<Cow<'a, Cbor>>>
25 for IndexVisitor<'b, I>
26{
27 fn visit_simple(&mut self, item: TaggedItem<'a>) -> Result<(), Option<Cow<'a, Cbor>>> {
28 if let (Some(TAG_CBOR_ITEM), ItemKind::Bytes(bytes)) = (item.tags().single(), item.kind()) {
29 return if let Some(cbor) = bytes.as_slice() {
30 Cbor::unchecked(cbor).visit(self)
31 } else {
32 let cbor = CborOwned::unchecked(bytes.to_vec());
33 cbor.visit(self)
34 .map_err(|res| res.map(|cbor| Cow::Owned(cbor.into_owned())))
35 };
36 }
37
38 if self.iter().next().is_some() {
39 Err(None)
40 } else {
41 Err(Some(Cow::Borrowed(item.cbor())))
42 }
43 }
44
45 fn visit_array_begin(
46 &mut self,
47 item: TaggedItem<'a>,
48 size: Option<u64>,
49 ) -> Result<bool, Option<Cow<'a, Cbor>>> {
50 if let Some(idx) = self.iter().next() {
51 let idx = match idx {
52 PathElement::String(_) => return Err(None),
53 PathElement::Number(x) => x,
54 PathElement::Item(_) => return Err(None),
55 };
56 if let Some(size) = size {
57 if size <= idx {
58 return Err(None);
59 }
60 }
61 self.arr_idx = Some(idx);
62 self.dict_idx = None;
63 Ok(true)
64 } else {
65 Err(Some(Cow::Borrowed(item.cbor())))
66 }
67 }
68
69 fn visit_array_index(
70 &mut self,
71 _item: TaggedItem<'a>,
72 index: u64,
73 ) -> Result<bool, Option<Cow<'a, Cbor>>> {
74 Ok(index == self.arr_idx.unwrap())
75 }
76
77 fn visit_array_end(&mut self, _item: TaggedItem<'a>) -> Result<(), Option<Cow<'a, Cbor>>> {
78 Err(None)
80 }
81
82 fn visit_dict_begin(
83 &mut self,
84 item: TaggedItem<'a>,
85 _size: Option<u64>,
86 ) -> Result<bool, Option<Cow<'a, Cbor>>> {
87 if let Some(idx) = self.iter().next() {
88 self.arr_idx = None;
89 self.dict_idx = Some(idx);
90 Ok(true)
91 } else {
92 Err(Some(Cow::Borrowed(item.cbor())))
93 }
94 }
95
96 fn visit_dict_key(
97 &mut self,
98 _item: TaggedItem<'a>,
99 key: TaggedItem<'a>,
100 _is_first: bool,
101 ) -> Result<bool, Option<Cow<'a, Cbor>>> {
102 Ok(match self.dict_idx.as_ref().unwrap() {
103 PathElement::String(idx) => matches!(key.kind(), ItemKind::Str(s) if s == idx),
104 PathElement::Number(idx) => matches!(key.kind(), ItemKind::Pos(p) if p == *idx),
105 PathElement::Item(idx) => &**idx == key.cbor(),
106 })
107 }
108
109 fn visit_dict_end(&mut self, _item: TaggedItem<'a>) -> Result<(), Option<Cow<'a, Cbor>>> {
110 Err(None)
112 }
113}
114
115#[derive(Debug, Clone, PartialEq)]
117pub enum PathElement<'a> {
118 String(Cow<'a, str>),
120 Number(u64),
122 Item(Cow<'a, Cbor>),
124}
125
126#[derive(Debug, Clone, PartialEq)]
128pub struct IndexStr<'a>(&'a str);
129
130impl<'a> IndexStr<'a> {
131 pub fn new(s: &'a str) -> Option<Self> {
132 let mut test = Self(s);
133 (&mut test).count();
134 if test.0.is_empty() {
135 Some(Self(s))
136 } else {
137 None
138 }
139 }
140}
141
142impl<'a> Iterator for IndexStr<'a> {
143 type Item = PathElement<'a>;
144
145 fn next(&mut self) -> Option<Self::Item> {
146 while self.0.starts_with('.') {
147 self.0 = &self.0[1..];
148 }
149 if self.0.is_empty() {
150 return None;
151 }
152
153 if self.0.starts_with('[') {
154 let end = self.0.find(']')?;
155 let idx: u64 = self.0[1..end].parse().ok()?;
156 self.0 = &self.0[end + 1..];
157 Some(PathElement::Number(idx))
158 } else {
159 let mut pos = self.0.len();
160 for (p, ch) in self.0.char_indices() {
161 if ch == '.' || ch == '[' {
162 pos = p;
163 break;
164 }
165 }
166 let ret = PathElement::String(Cow::Borrowed(&self.0[..pos]));
167 self.0 = &self.0[pos..];
168 Some(ret)
169 }
170 }
171}