hayro_syntax/object/
array.rs

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