hayro_syntax/object/
ref.rs1use 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#[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 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#[derive(PartialEq, Eq)]
60pub enum MaybeRef<T> {
61 Ref(ObjRef),
63 NotRef(T),
65}
66
67impl<T> MaybeRef<T> {
68 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 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}