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 debug_list.finish()
71 }
72}
73
74object!(Array<'a>, Array);
75
76impl Skippable for Array<'_> {
77 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
78 r.forward_tag(b"[")?;
79
80 loop {
81 r.skip_white_spaces_and_comments();
82
83 if let Some(()) = r.forward_tag(b"]") {
84 return Some(());
85 } else if is_content_stream {
86 r.skip_not_in_content_stream::<Object<'_>>()?;
87 } else {
88 r.skip_not_in_content_stream::<MaybeRef<Object<'_>>>()?;
89 }
90 }
91 }
92}
93
94impl Default for Array<'_> {
95 fn default() -> Self {
96 Self::from_bytes(b"[]").expect("[] is a valid empty array literal")
97 }
98}
99
100impl<'a> Readable<'a> for Array<'a> {
101 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
102 let bytes = r.skip::<Array<'_>>(ctx.in_content_stream())?;
103
104 Some(Self {
105 data: &bytes[1..bytes.len() - 1],
106 ctx: ctx.clone(),
107 })
108 }
109}
110
111pub struct ArrayIter<'a> {
113 reader: Reader<'a>,
114 ctx: ReaderContext<'a>,
115}
116
117impl<'a> ArrayIter<'a> {
118 fn new(data: &'a [u8], ctx: &ReaderContext<'a>) -> Self {
119 Self {
120 reader: Reader::new(data),
121 ctx: ctx.clone(),
122 }
123 }
124}
125
126impl<'a> Iterator for ArrayIter<'a> {
127 type Item = MaybeRef<Object<'a>>;
128
129 fn next(&mut self) -> Option<Self::Item> {
130 self.reader.skip_white_spaces_and_comments();
131
132 if !self.reader.at_end() {
133 let item = self
134 .reader
135 .read_with_context::<MaybeRef<Object<'_>>>(&self.ctx)?;
136 return Some(item);
137 }
138
139 None
140 }
141}
142
143pub struct ResolvedArrayIter<'a, T> {
145 flex_iter: FlexArrayIter<'a>,
146 phantom_data: PhantomData<T>,
147}
148
149impl<'a, T> ResolvedArrayIter<'a, T> {
150 fn new(data: &'a [u8], ctx: &ReaderContext<'a>) -> Self {
151 Self {
152 flex_iter: FlexArrayIter::new(data, ctx),
153 phantom_data: PhantomData,
154 }
155 }
156}
157
158impl<'a, T> Iterator for ResolvedArrayIter<'a, T>
159where
160 T: ObjectLike<'a>,
161{
162 type Item = T;
163
164 fn next(&mut self) -> Option<Self::Item> {
165 self.flex_iter.next::<T>()
166 }
167}
168
169pub struct FlexArrayIter<'a> {
171 reader: Reader<'a>,
172 ctx: ReaderContext<'a>,
173}
174
175impl<'a> FlexArrayIter<'a> {
176 fn new(data: &'a [u8], ctx: &ReaderContext<'a>) -> Self {
177 Self {
178 reader: Reader::new(data),
179 ctx: ctx.clone(),
180 }
181 }
182
183 #[allow(
184 private_bounds,
185 reason = "users shouldn't be able to implement `ObjectLike` for custom objects."
186 )]
187 #[allow(clippy::should_implement_trait)]
188 pub fn next<T: ObjectLike<'a>>(&mut self) -> Option<T> {
190 self.reader.skip_white_spaces_and_comments();
191
192 if !self.reader.at_end() {
193 return match self.reader.read_with_context::<MaybeRef<T>>(&self.ctx)? {
194 MaybeRef::Ref(r) => self.ctx.xref().get_with::<T>(r.into(), &self.ctx),
195 MaybeRef::NotRef(i) => Some(i),
196 };
197 }
198
199 None
200 }
201}
202
203impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> TryFrom<Array<'a>> for [T; C] {
204 type Error = ();
205
206 fn try_from(value: Array<'a>) -> Result<Self, Self::Error> {
207 let mut iter = value.iter::<T>();
208
209 let mut val = [T::default(); C];
210
211 for i in 0..C {
212 val[i] = iter.next().ok_or(())?;
213 }
214
215 if iter.next().is_some() {
216 warn!("found excess elements in array");
217
218 return Err(());
219 }
220
221 Ok(val)
222 }
223}
224
225impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> TryFrom<Object<'a>> for [T; C]
226where
227 [T; C]: TryFrom<Array<'a>, Error = ()>,
228{
229 type Error = ();
230
231 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
232 match value {
233 Object::Array(a) => a.try_into(),
234 _ => Err(()),
235 }
236 }
237}
238
239impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> Readable<'a> for [T; C] {
240 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
241 let array = Array::read(r, ctx)?;
242 array.try_into().ok()
243 }
244}
245
246impl<'a, T: ObjectLike<'a> + Copy + Default, const C: usize> ObjectLike<'a> for [T; C] {}
247
248impl<'a, T: ObjectLike<'a>> TryFrom<Array<'a>> for Vec<T> {
249 type Error = ();
250
251 fn try_from(value: Array<'a>) -> Result<Self, Self::Error> {
252 Ok(value.iter::<T>().collect())
253 }
254}
255
256impl<'a, T: ObjectLike<'a>> TryFrom<Object<'a>> for Vec<T> {
257 type Error = ();
258
259 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
260 match value {
261 Object::Array(a) => a.try_into(),
262 _ => Err(()),
263 }
264 }
265}
266
267impl<'a, T: ObjectLike<'a>> Readable<'a> for Vec<T> {
268 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
269 let array = Array::read(r, ctx)?;
270 array.try_into().ok()
271 }
272}
273
274impl<'a, T: ObjectLike<'a>> ObjectLike<'a> for Vec<T> {}
275
276impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> TryFrom<Array<'a>>
277 for SmallVec<T>
278{
279 type Error = ();
280
281 fn try_from(value: Array<'a>) -> Result<Self, Self::Error> {
282 Ok(value.iter::<U>().collect())
283 }
284}
285
286impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> TryFrom<Object<'a>>
287 for SmallVec<T>
288{
289 type Error = ();
290
291 fn try_from(value: Object<'a>) -> Result<Self, Self::Error> {
292 match value {
293 Object::Array(a) => a.try_into(),
294 _ => Err(()),
295 }
296 }
297}
298
299impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> Readable<'a>
300 for SmallVec<T>
301{
302 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
303 let array = Array::read(r, ctx)?;
304 array.try_into().ok()
305 }
306}
307
308impl<'a, U: ObjectLike<'a>, T: ObjectLike<'a> + smallvec::Array<Item = U>> ObjectLike<'a>
309 for SmallVec<T>
310where
311 U: Clone,
312 U: Debug,
313{
314}
315
316#[cfg(test)]
317mod tests {
318 use crate::object::Array;
319 use crate::object::Object;
320 use crate::object::r#ref::{MaybeRef, ObjRef};
321 use crate::reader::Reader;
322 use crate::reader::{ReaderContext, ReaderExt};
323 use crate::xref::XRef;
324
325 fn array_impl(data: &[u8]) -> Option<Vec<Object<'_>>> {
326 Reader::new(data)
327 .read_with_context::<Array<'_>>(&ReaderContext::new(XRef::dummy(), false))
328 .map(|a| a.iter::<Object<'_>>().collect::<Vec<_>>())
329 }
330
331 fn array_ref_impl(data: &[u8]) -> Option<Vec<MaybeRef<Object<'_>>>> {
332 Reader::new(data)
333 .read_with_context::<Array<'_>>(&ReaderContext::new(XRef::dummy(), false))
334 .map(|a| a.raw_iter().collect::<Vec<_>>())
335 }
336
337 #[test]
338 fn empty_array_1() {
339 let res = array_impl(b"[]").unwrap();
340 assert!(res.is_empty());
341 }
342
343 #[test]
344 fn empty_array_2() {
345 let res = array_impl(b"[ \n]").unwrap();
346 assert!(res.is_empty());
347 }
348
349 #[test]
350 fn array_1() {
351 let res = array_impl(b"[34]").unwrap();
352 assert!(matches!(res[0], Object::Number(_)));
353 }
354
355 #[test]
356 fn array_2() {
357 let res = array_impl(b"[true ]").unwrap();
358 assert!(matches!(res[0], Object::Boolean(_)));
359 }
360
361 #[test]
362 fn array_3() {
363 let res = array_impl(b"[true \n false 34.564]").unwrap();
364 assert!(matches!(res[0], Object::Boolean(_)));
365 assert!(matches!(res[1], Object::Boolean(_)));
366 assert!(matches!(res[2], Object::Number(_)));
367 }
368
369 #[test]
370 fn array_4() {
371 let res = array_impl(b"[(A string.) << /Hi 34.35 >>]").unwrap();
372 assert!(matches!(res[0], Object::String(_)));
373 assert!(matches!(res[1], Object::Dict(_)));
374 }
375
376 #[test]
377 fn array_5() {
378 let res = array_impl(b"[[32] 345.6]").unwrap();
379 assert!(matches!(res[0], Object::Array(_)));
380 assert!(matches!(res[1], Object::Number(_)));
381 }
382
383 #[test]
384 fn array_with_ref() {
385 let res = array_ref_impl(b"[345 34 5 R 34.0]").unwrap();
386 assert!(matches!(res[0], MaybeRef::NotRef(Object::Number(_))));
387 assert!(matches!(
388 res[1],
389 MaybeRef::Ref(ObjRef {
390 obj_number: 34,
391 gen_number: 5
392 })
393 ));
394 assert!(matches!(res[2], MaybeRef::NotRef(Object::Number(_))));
395 }
396
397 #[test]
398 fn array_with_comment() {
399 let res = array_impl(b"[true % A comment \n false]").unwrap();
400 assert!(matches!(res[0], Object::Boolean(_)));
401 assert!(matches!(res[1], Object::Boolean(_)));
402 }
403
404 #[test]
405 fn array_with_trailing() {
406 let res = array_impl(b"[(Hi) /Test]trialing data").unwrap();
407 assert!(matches!(res[0], Object::String(_)));
408 assert!(matches!(res[1], Object::Name(_)));
409 }
410
411 #[test]
420 fn a_reference_missing_its_space_is_not_an_array_of_integers() {
421 assert!(array_ref_impl(b"[8 0R]").is_none());
422 }
423
424 #[test]
426 fn a_single_large_number_is_still_an_array() {
427 assert!(array_ref_impl(b"[345345345]").is_some());
428 }
429
430 #[test]
432 fn a_well_formed_reference_still_reads() {
433 assert!(array_ref_impl(b"[8 0 R]").is_some());
434 }
435
436 #[test]
441 fn the_debug_output_is_the_array() {
442 let array = Reader::new(b"[34]")
446 .read_with_context::<Array<'_>>(&ReaderContext::new(XRef::dummy(), false))
447 .unwrap();
448 let rendered = format!("{array:?}");
449 assert!(
450 rendered.starts_with('[') && rendered.ends_with(']'),
451 "expected a bracketed list, got {rendered:?}"
452 );
453 assert!(
454 rendered.contains("34"),
455 "the value is missing from {rendered:?}"
456 );
457 }
458}