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