1use crate::object::macros::object;
4use crate::object::r#ref::MaybeRef;
5use crate::object::{FromBytes, Object, ObjectLike};
6use crate::reader::{Readable, Reader, ReaderContext, Skippable};
7use log::warn;
8use smallvec::SmallVec;
9use std::fmt::{Debug, Formatter};
10use std::marker::PhantomData;
11
12#[derive(Clone)]
14pub struct Array<'a> {
15 data: &'a [u8],
16 ctx: ReaderContext<'a>,
17}
18
19impl PartialEq for Array<'_> {
22 fn eq(&self, other: &Self) -> bool {
23 self.data == other.data
24 }
25}
26
27impl<'a> Array<'a> {
28 pub fn raw_iter(&self) -> ArrayIter<'a> {
30 ArrayIter::new(self.data, &self.ctx)
31 }
32
33 #[allow(
35 private_bounds,
36 reason = "users shouldn't be able to implement `ObjectLike` for custom objects."
37 )]
38 pub fn iter<T>(&self) -> ResolvedArrayIter<'a, T>
39 where
40 T: ObjectLike<'a>,
41 {
42 ResolvedArrayIter::new(self.data, &self.ctx)
43 }
44
45 pub fn flex_iter(&self) -> FlexArrayIter<'a> {
47 FlexArrayIter::new(self.data, &self.ctx)
48 }
49}
50
51impl Debug for Array<'_> {
52 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
53 let mut debug_list = f.debug_list();
54
55 self.raw_iter().for_each(|i| {
56 debug_list.entry(&i);
57 });
58
59 Ok(())
60 }
61}
62
63object!(Array<'a>, Array);
64
65impl Skippable for Array<'_> {
66 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
67 r.forward_tag(b"[")?;
68
69 loop {
70 r.skip_white_spaces_and_comments();
71
72 if let Some(()) = r.forward_tag(b"]") {
73 return Some(());
74 } else if is_content_stream {
75 r.skip_not_in_content_stream::<Object>()?;
76 } else {
77 r.skip_not_in_content_stream::<MaybeRef<Object>>()?;
78 }
79 }
80 }
81}
82
83impl Default for Array<'_> {
84 fn default() -> Self {
85 Self::from_bytes(b"[]").unwrap()
86 }
87}
88
89impl<'a> Readable<'a> for Array<'a> {
90 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
91 let bytes = r.skip::<Array>(ctx.in_content_stream)?;
92
93 Some(Self {
94 data: &bytes[1..bytes.len() - 1],
95 ctx: ctx.clone(),
96 })
97 }
98}
99
100pub struct ArrayIter<'a> {
102 reader: Reader<'a>,
103 ctx: ReaderContext<'a>,
104}
105
106impl<'a> ArrayIter<'a> {
107 fn new(data: &'a [u8], ctx: &ReaderContext<'a>) -> Self {
108 Self {
109 reader: Reader::new(data),
110 ctx: ctx.clone(),
111 }
112 }
113}
114
115impl<'a> Iterator for ArrayIter<'a> {
116 type Item = MaybeRef<Object<'a>>;
117
118 fn next(&mut self) -> Option<Self::Item> {
119 self.reader.skip_white_spaces_and_comments();
120
121 if !self.reader.at_end() {
122 let item = self
124 .reader
125 .read_with_context::<MaybeRef<Object>>(&self.ctx)
126 .unwrap();
127 return Some(item);
128 }
129
130 None
131 }
132}
133
134pub struct ResolvedArrayIter<'a, T> {
136 flex_iter: FlexArrayIter<'a>,
137 phantom_data: PhantomData<T>,
138}
139
140impl<'a, T> ResolvedArrayIter<'a, T> {
141 fn new(data: &'a [u8], ctx: &ReaderContext<'a>) -> Self {
142 Self {
143 flex_iter: FlexArrayIter::new(data, ctx),
144 phantom_data: PhantomData,
145 }
146 }
147}
148
149impl<'a, T> Iterator for ResolvedArrayIter<'a, T>
150where
151 T: ObjectLike<'a>,
152{
153 type Item = T;
154
155 fn next(&mut self) -> Option<Self::Item> {
156 self.flex_iter.next::<T>()
157 }
158}
159
160pub struct FlexArrayIter<'a> {
162 reader: Reader<'a>,
163 ctx: ReaderContext<'a>,
164}
165
166impl<'a> FlexArrayIter<'a> {
167 fn new(data: &'a [u8], ctx: &ReaderContext<'a>) -> Self {
168 Self {
169 reader: Reader::new(data),
170 ctx: ctx.clone(),
171 }
172 }
173
174 #[allow(
175 private_bounds,
176 reason = "users shouldn't be able to implement `ObjectLike` for custom objects."
177 )]
178 #[allow(clippy::should_implement_trait)]
179 pub fn next<T: ObjectLike<'a>>(&mut self) -> Option<T> {
181 self.reader.skip_white_spaces_and_comments();
182
183 if !self.reader.at_end() {
184 return match self.reader.read_with_context::<MaybeRef<T>>(&self.ctx)? {
185 MaybeRef::Ref(r) => self.ctx.xref.get_with::<T>(r.into(), &self.ctx),
186 MaybeRef::NotRef(i) => Some(i),
187 };
188 }
189
190 None
191 }
192}
193
194impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> TryFrom<Array<'a>> for [T; C] {
195 type Error = ();
196
197 fn try_from(value: Array<'a>) -> Result<Self, Self::Error> {
198 let mut iter = value.iter::<T>();
199
200 let mut val = [T::default(); C];
201
202 for i in 0..C {
203 val[i] = iter.next().ok_or(())?;
204 }
205
206 if iter.next().is_some() {
207 warn!("found excess elements in array");
208
209 return Err(());
210 }
211
212 Ok(val)
213 }
214}
215
216impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> TryFrom<Object<'a>> for [T; C]
217where
218 [T; C]: TryFrom<Array<'a>, Error = ()>,
219{
220 type Error = ();
221
222 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
223 match value {
224 Object::Array(a) => a.try_into(),
225 _ => Err(()),
226 }
227 }
228}
229
230impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> Readable<'a> for [T; C] {
231 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
232 let array = Array::read(r, ctx)?;
233 array.try_into().ok()
234 }
235}
236
237impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> ObjectLike<'a> for [T; C] {}
238
239impl<'a, T: ObjectLike<'a>> TryFrom<Array<'a>> for Vec<T> {
240 type Error = ();
241
242 fn try_from(value: Array<'a>) -> Result<Self, Self::Error> {
243 Ok(value.iter::<T>().collect())
244 }
245}
246
247impl<'a, T: ObjectLike<'a>> TryFrom<Object<'a>> for Vec<T> {
248 type Error = ();
249
250 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
251 match value {
252 Object::Array(a) => a.try_into(),
253 _ => Err(()),
254 }
255 }
256}
257
258impl<'a, T: ObjectLike<'a>> Readable<'a> for Vec<T> {
259 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
260 let array = Array::read(r, ctx)?;
261 array.try_into().ok()
262 }
263}
264
265impl<'a, T: ObjectLike<'a>> ObjectLike<'a> for Vec<T> {}
266
267impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> TryFrom<Array<'a>>
268 for SmallVec<T>
269{
270 type Error = ();
271
272 fn try_from(value: Array<'a>) -> Result<Self, Self::Error> {
273 Ok(value.iter::<U>().collect())
274 }
275}
276
277impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> TryFrom<Object<'a>>
278 for SmallVec<T>
279{
280 type Error = ();
281
282 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
283 match value {
284 Object::Array(a) => a.try_into(),
285 _ => Err(()),
286 }
287 }
288}
289
290impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> Readable<'a>
291 for SmallVec<T>
292{
293 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
294 let array = Array::read(r, ctx)?;
295 array.try_into().ok()
296 }
297}
298
299impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> ObjectLike<'a>
300 for SmallVec<T>
301where
302 U: Clone,
303 U: Debug,
304{
305}
306
307#[cfg(test)]
308mod tests {
309 use crate::object::Array;
310 use crate::object::Object;
311 use crate::object::r#ref::{MaybeRef, ObjRef};
312 use crate::reader::{Reader, ReaderContext};
313 use crate::xref::XRef;
314
315 fn array_impl(data: &[u8]) -> Option<Vec<Object<'_>>> {
316 Reader::new(data)
317 .read_with_context::<Array>(&ReaderContext::new(XRef::dummy(), false))
318 .map(|a| a.iter::<Object>().collect::<Vec<_>>())
319 }
320
321 fn array_ref_impl(data: &[u8]) -> Option<Vec<MaybeRef<Object<'_>>>> {
322 Reader::new(data)
323 .read_with_context::<Array>(&ReaderContext::new(XRef::dummy(), false))
324 .map(|a| a.raw_iter().collect::<Vec<_>>())
325 }
326
327 #[test]
328 fn empty_array_1() {
329 let res = array_impl(b"[]").unwrap();
330 assert!(res.is_empty());
331 }
332
333 #[test]
334 fn empty_array_2() {
335 let res = array_impl(b"[ \n]").unwrap();
336 assert!(res.is_empty());
337 }
338
339 #[test]
340 fn array_1() {
341 let res = array_impl(b"[34]").unwrap();
342 assert!(matches!(res[0], Object::Number(_)));
343 }
344
345 #[test]
346 fn array_2() {
347 let res = array_impl(b"[true ]").unwrap();
348 assert!(matches!(res[0], Object::Boolean(_)));
349 }
350
351 #[test]
352 fn array_3() {
353 let res = array_impl(b"[true \n false 34.564]").unwrap();
354 assert!(matches!(res[0], Object::Boolean(_)));
355 assert!(matches!(res[1], Object::Boolean(_)));
356 assert!(matches!(res[2], Object::Number(_)));
357 }
358
359 #[test]
360 fn array_4() {
361 let res = array_impl(b"[(A string.) << /Hi 34.35 >>]").unwrap();
362 assert!(matches!(res[0], Object::String(_)));
363 assert!(matches!(res[1], Object::Dict(_)));
364 }
365
366 #[test]
367 fn array_5() {
368 let res = array_impl(b"[[32] 345.6]").unwrap();
369 assert!(matches!(res[0], Object::Array(_)));
370 assert!(matches!(res[1], Object::Number(_)));
371 }
372
373 #[test]
374 fn array_with_ref() {
375 let res = array_ref_impl(b"[345 34 5 R 34.0]").unwrap();
376 assert!(matches!(res[0], MaybeRef::NotRef(Object::Number(_))));
377 assert!(matches!(
378 res[1],
379 MaybeRef::Ref(ObjRef {
380 obj_number: 34,
381 gen_number: 5
382 })
383 ));
384 assert!(matches!(res[2], MaybeRef::NotRef(Object::Number(_))));
385 }
386
387 #[test]
388 fn array_with_comment() {
389 let res = array_impl(b"[true % A comment \n false]").unwrap();
390 assert!(matches!(res[0], Object::Boolean(_)));
391 assert!(matches!(res[1], Object::Boolean(_)));
392 }
393
394 #[test]
395 fn array_with_trailing() {
396 let res = array_impl(b"[(Hi) /Test]trialing data").unwrap();
397 assert!(matches!(res[0], Object::String(_)));
398 assert!(matches!(res[1], Object::Name(_)));
399 }
400}