1use crate::{
4 CrawlerError, CrawlerResult, JsonCrawler, JsonCrawlerBorrowed, JsonCrawlerOwned, JsonPath,
5 PathList,
6};
7use std::{slice::IterMut, sync::Arc, vec::IntoIter};
8
9pub trait JsonCrawlerIterator: Iterator
12where
13 Self::Item: JsonCrawler,
14{
15 fn find_path(self, path: impl AsRef<str>) -> CrawlerResult<Self::Item>;
17 fn try_last(self) -> CrawlerResult<Self::Item>;
19}
20
21pub struct JsonCrawlerArrayIterMut<'a> {
22 pub(crate) source: Arc<String>,
23 pub(crate) array: IterMut<'a, serde_json::Value>,
24 pub(crate) path: PathList,
25 pub(crate) cur_front: usize,
26 pub(crate) cur_back: usize,
27}
28
29#[derive(Clone)]
30pub struct JsonCrawlerArrayIntoIter {
31 pub(crate) source: Arc<String>,
32 pub(crate) array: IntoIter<serde_json::Value>,
33 pub(crate) path: PathList,
34 pub(crate) cur_front: usize,
35 pub(crate) cur_back: usize,
36}
37
38impl<'a> Iterator for JsonCrawlerArrayIterMut<'a> {
39 type Item = JsonCrawlerBorrowed<'a>;
40 fn next(&mut self) -> Option<Self::Item> {
41 let crawler = self.array.next()?;
42 let out = Some(JsonCrawlerBorrowed {
43 source: self.source.clone(),
45 crawler,
46 path: self.path.clone().with(JsonPath::IndexNum(self.cur_front)),
49 });
50 self.cur_front += 1;
51 out
52 }
53 fn size_hint(&self) -> (usize, Option<usize>) {
55 (self.array.len(), Some(self.array.len()))
56 }
57}
58
59impl ExactSizeIterator for JsonCrawlerArrayIterMut<'_> {}
61
62impl DoubleEndedIterator for JsonCrawlerArrayIterMut<'_> {
63 fn next_back(&mut self) -> Option<Self::Item> {
64 let crawler = self.array.next_back()?;
65 let out = Some(JsonCrawlerBorrowed {
66 source: self.source.clone(),
68 crawler,
69 path: self.path.clone().with(JsonPath::IndexNum(self.cur_back)),
72 });
73 self.cur_back = self.cur_back.saturating_sub(1);
74 out
75 }
76}
77
78impl JsonCrawlerIterator for JsonCrawlerArrayIterMut<'_> {
79 fn find_path(mut self, path: impl AsRef<str>) -> CrawlerResult<Self::Item> {
80 self.find_map(|crawler| crawler.navigate_pointer(path.as_ref()).ok())
81 .ok_or_else(|| {
82 CrawlerError::path_not_found_in_array(self.path, self.source, path.as_ref())
83 })
84 }
85 fn try_last(self) -> CrawlerResult<Self::Item> {
86 let Self {
87 source,
88 array,
89 mut path,
90 ..
91 } = self;
92 let len = array.len();
93 path.push(JsonPath::IndexNum(len));
94 let Some(last_item) = array.last() else {
95 return Err(CrawlerError::array_size(path, source, 0));
96 };
97 Ok(Self::Item {
98 source,
99 crawler: last_item,
100 path,
101 })
102 }
103}
104
105impl Iterator for JsonCrawlerArrayIntoIter {
106 type Item = JsonCrawlerOwned;
107 fn next(&mut self) -> Option<Self::Item> {
108 let crawler = self.array.next()?;
109 let out = Some(JsonCrawlerOwned {
110 source: self.source.clone(),
112 crawler,
113 path: self.path.clone().with(JsonPath::IndexNum(self.cur_front)),
116 });
117 self.cur_front += 1;
118 out
119 }
120 fn size_hint(&self) -> (usize, Option<usize>) {
122 (self.array.len(), Some(self.array.len()))
123 }
124}
125impl ExactSizeIterator for JsonCrawlerArrayIntoIter {}
127
128impl DoubleEndedIterator for JsonCrawlerArrayIntoIter {
129 fn next_back(&mut self) -> Option<Self::Item> {
130 let crawler = self.array.next_back()?;
131 let out = Some(JsonCrawlerOwned {
132 source: self.source.clone(),
134 crawler,
135 path: self.path.clone().with(JsonPath::IndexNum(self.cur_back)),
138 });
139 self.cur_back = self.cur_back.saturating_sub(1);
140 out
141 }
142}
143impl JsonCrawlerIterator for JsonCrawlerArrayIntoIter {
144 fn find_path(mut self, path: impl AsRef<str>) -> CrawlerResult<Self::Item> {
145 self.find_map(|crawler| crawler.navigate_pointer(path.as_ref()).ok())
146 .ok_or_else(|| {
147 CrawlerError::path_not_found_in_array(self.path, self.source, path.as_ref())
148 })
149 }
150 fn try_last(self) -> CrawlerResult<Self::Item> {
151 let Self {
152 source,
153 array,
154 mut path,
155 ..
156 } = self;
157 let len = array.len();
158 path.push(JsonPath::IndexNum(len));
159 let Some(last_item) = array.last() else {
160 return Err(CrawlerError::array_size(path, source, 0));
161 };
162 Ok(Self::Item {
163 source,
164 crawler: last_item,
165 path,
166 })
167 }
168}