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, Display, 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 Display for ObjRef {
29 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
30 write!(f, "{} {} R", self.obj_number, self.gen_number)
31 }
32}
33
34impl From<ObjRef> for ObjectIdentifier {
35 fn from(value: ObjRef) -> Self {
36 Self::new(value.obj_number, value.gen_number)
37 }
38}
39
40impl From<ObjectIdentifier> for ObjRef {
41 fn from(value: ObjectIdentifier) -> Self {
42 Self::new(value.obj_number, value.gen_number)
43 }
44}
45
46impl Skippable for ObjRef {
47 fn skip(r: &mut Reader<'_>, _: bool) -> Option<()> {
48 r.skip::<i32>(false)?;
49 r.skip_white_spaces();
50 r.skip::<i32>(false)?;
51 r.skip_white_spaces();
52 r.forward_tag(b"R")?;
53
54 Some(())
55 }
56}
57
58impl Readable<'_> for ObjRef {
59 fn read(r: &mut Reader<'_>, _: &ReaderContext<'_>) -> Option<Self> {
60 let obj_ref = r.read_without_context::<i32>()?;
61 r.skip_white_spaces();
62 let gen_num = r.read_without_context::<i32>()?;
63 r.skip_white_spaces();
64 r.forward_tag(b"R")?;
65
66 Some(Self::new(obj_ref, gen_num))
67 }
68}
69
70#[derive(PartialEq, Eq)]
72pub enum MaybeRef<T> {
73 Ref(ObjRef),
75 NotRef(T),
77}
78
79impl<T> MaybeRef<T> {
80 pub fn as_obj_ref(&self) -> Option<ObjRef> {
82 match self {
83 Self::Ref(r) => Some(*r),
84 Self::NotRef(_) => None,
85 }
86 }
87}
88
89#[allow(private_bounds)]
90impl<'a, T> MaybeRef<T>
91where
92 T: ObjectLike<'a>,
93{
94 pub(crate) fn resolve(self, ctx: &ReaderContext<'a>) -> Option<T> {
96 match self {
97 Self::Ref(r) => ctx.xref().get_with::<T>(r.into(), ctx),
98 Self::NotRef(t) => Some(t),
99 }
100 }
101}
102
103impl<T> TryFrom<MaybeRef<T>> for ObjRef {
104 type Error = ();
105
106 fn try_from(value: MaybeRef<T>) -> Result<Self, Self::Error> {
107 match value {
108 MaybeRef::Ref(r) => Ok(r),
109 MaybeRef::NotRef(_) => Err(()),
110 }
111 }
112}
113
114impl<T> Debug for MaybeRef<T>
115where
116 T: Debug,
117{
118 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
119 match self {
120 Self::Ref(r) => write!(f, "{r:?}"),
121 Self::NotRef(nr) => write!(f, "{nr:?}"),
122 }
123 }
124}
125
126impl<T: Display> Display for MaybeRef<T> {
127 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
128 match self {
129 Self::Ref(value) => Display::fmt(value, f),
130 Self::NotRef(value) => Display::fmt(value, f),
131 }
132 }
133}
134
135impl<T> Skippable for MaybeRef<T>
136where
137 T: Skippable,
138{
139 fn skip(r: &mut Reader<'_>, is_content_stream: bool) -> Option<()> {
140 Self::skip_with_depth(r, is_content_stream, 0)
141 }
142
143 fn skip_with_depth(r: &mut Reader<'_>, is_content_stream: bool, depth: usize) -> Option<()> {
144 r.skip::<ObjRef>(is_content_stream)
145 .or_else(|| r.skip_with_depth::<T>(is_content_stream, depth))
146 .map(|_| {})
147 }
148}
149
150impl<'a, T> Readable<'a> for MaybeRef<T>
151where
152 T: Readable<'a>,
153{
154 fn read(r: &mut Reader<'a>, ctx: &ReaderContext<'a>) -> Option<Self> {
155 if let Some(obj) = r.read::<ObjRef>(ctx) {
156 Some(Self::Ref(obj))
157 } else {
158 Some(Self::NotRef(r.read::<T>(ctx)?))
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use crate::object::{MaybeRef, Number, ObjRef};
166 use crate::reader::Reader;
167 use crate::reader::ReaderExt;
168
169 #[test]
170 fn display() {
171 assert_eq!(format!("{}", ObjRef::new(34, 1)), "34 1 R");
172 assert_eq!(format!("{}", MaybeRef::NotRef(Number::from_i32(12))), "12");
173 }
174
175 #[test]
176 fn ref_1() {
177 assert_eq!(
178 Reader::new("34 1 R".as_bytes())
179 .read_without_context::<ObjRef>()
180 .unwrap(),
181 ObjRef::new(34, 1)
182 );
183 }
184
185 #[test]
186 fn ref_trailing() {
187 assert_eq!(
188 Reader::new("256 0 R (hi)".as_bytes())
189 .read_without_context::<ObjRef>()
190 .unwrap(),
191 ObjRef::new(256, 0)
192 );
193 }
194
195 #[test]
196 fn ref_invalid_1() {
197 assert!(
198 Reader::new("256 R".as_bytes())
199 .read_without_context::<ObjRef>()
200 .is_none()
201 );
202 }
203
204 #[test]
205 fn ref_invalid_2() {
206 assert!(
207 Reader::new("256 257".as_bytes())
208 .read_without_context::<ObjRef>()
209 .is_none()
210 );
211 }
212}