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