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