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