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