hayro_syntax/object/
ref.rs

1//! Object references.
2
3use crate::object::ObjectIdentifier;
4use crate::object::ObjectLike;
5use crate::reader::Reader;
6use crate::reader::{Readable, ReaderContext, ReaderExt, Skippable};
7use std::fmt::{Debug, Formatter};
8
9/// A reference to an object.
10#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)]
11pub struct ObjRef {
12    /// The object number.
13    pub obj_number: i32,
14    /// The generation number.
15    pub gen_number: i32,
16}
17
18impl ObjRef {
19    /// Create a new object reference.
20    pub fn new(obj_number: i32, gen_number: i32) -> Self {
21        Self {
22            obj_number,
23            gen_number,
24        }
25    }
26}
27
28impl From<ObjRef> for ObjectIdentifier {
29    fn from(value: ObjRef) -> Self {
30        Self::new(value.obj_number, value.gen_number)
31    }
32}
33
34impl Skippable for ObjRef {
35    fn skip(r: &mut Reader<'_>, _: bool) -> Option<()> {
36        r.skip_not_in_content_stream::<i32>()?;
37        r.skip_white_spaces();
38        r.skip_not_in_content_stream::<i32>()?;
39        r.skip_white_spaces();
40        r.forward_tag(b"R")?;
41
42        Some(())
43    }
44}
45
46impl Readable<'_> for ObjRef {
47    fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
48        let obj_ref = r.read_without_context::<i32>()?;
49        r.skip_white_spaces();
50        let gen_num = r.read_without_context::<i32>()?;
51        r.skip_white_spaces();
52        r.forward_tag(b"R")?;
53
54        Some(Self::new(obj_ref, gen_num))
55    }
56}
57
58/// A struct that is either an object or a reference to an object.
59#[derive(PartialEq, Eq)]
60pub enum MaybeRef<T> {
61    /// A reference to an object.
62    Ref(ObjRef),
63    /// An object.
64    NotRef(T),
65}
66
67impl<T> MaybeRef<T> {
68    /// If the object is an object reference, return it.
69    pub fn as_obj_ref(&self) -> Option<ObjRef> {
70        match self {
71            Self::Ref(r) => Some(*r),
72            Self::NotRef(_) => None,
73        }
74    }
75}
76
77#[allow(private_bounds)]
78impl<'a, T> MaybeRef<T>
79where
80    T: ObjectLike<'a>,
81{
82    /// Resolve the `MaybeRef` object with the given xref table.
83    pub(crate) fn resolve(self, ctx: &ReaderContext<'a>) -> Option<T> {
84        match self {
85            Self::Ref(r) => ctx.xref.get_with::<T>(r.into(), ctx),
86            Self::NotRef(t) => Some(t),
87        }
88    }
89}
90
91impl<T> TryFrom<MaybeRef<T>> for ObjRef {
92    type Error = ();
93
94    fn try_from(value: MaybeRef<T>) -> Result<Self, Self::Error> {
95        match value {
96            MaybeRef::Ref(r) => Ok(r),
97            MaybeRef::NotRef(_) => Err(()),
98        }
99    }
100}
101
102impl<T> Debug for MaybeRef<T>
103where
104    T: Debug,
105{
106    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107        match self {
108            Self::Ref(r) => write!(f, "{r:?}"),
109            Self::NotRef(nr) => write!(f, "{nr:?}"),
110        }
111    }
112}
113
114impl<T> Skippable for MaybeRef<T>
115where
116    T: Skippable,
117{
118    fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
119        r.skip::<ObjRef>(is_content_stream)
120            .or_else(|| r.skip::<T>(is_content_stream))
121            .map(|_| {})
122    }
123}
124
125impl<'a, T> Readable<'a> for MaybeRef<T>
126where
127    T: Readable<'a>,
128{
129    fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
130        if let Some(obj) = r.read::<ObjRef>(ctx) {
131            Some(Self::Ref(obj))
132        } else {
133            Some(Self::NotRef(r.read::<T>(ctx)?))
134        }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use crate::object::ObjRef;
141    use crate::reader::Reader;
142    use crate::reader::ReaderExt;
143
144    #[test]
145    fn ref_1() {
146        assert_eq!(
147            Reader::new("34 1 R".as_bytes())
148                .read_without_context::<ObjRef>()
149                .unwrap(),
150            ObjRef::new(34, 1)
151        );
152    }
153
154    #[test]
155    fn ref_trailing() {
156        assert_eq!(
157            Reader::new("256 0 R (hi)".as_bytes())
158                .read_without_context::<ObjRef>()
159                .unwrap(),
160            ObjRef::new(256, 0)
161        );
162    }
163
164    #[test]
165    fn ref_invalid_1() {
166        assert!(
167            Reader::new("256 R".as_bytes())
168                .read_without_context::<ObjRef>()
169                .is_none()
170        );
171    }
172
173    #[test]
174    fn ref_invalid_2() {
175        assert!(
176            Reader::new("256 257".as_bytes())
177                .read_without_context::<ObjRef>()
178                .is_none()
179        );
180    }
181}