1use core::marker::PhantomData;
2
3use crate::common::{DebugInfoOffset, Format};
4use crate::read::{Error, Reader, ReaderOffset, Result, UnitOffset};
5
6pub trait LookupParser<R: Reader> {
16 type Header;
18 type Entry;
20
21 fn parse_header(input: &mut R) -> Result<(R, Self::Header)>;
25
26 fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>;
29}
30
31#[derive(Clone, Debug)]
32pub struct DebugLookup<R, Parser>
33where
34 R: Reader,
35 Parser: LookupParser<R>,
36{
37 input_buffer: R,
38 phantom: PhantomData<Parser>,
39}
40
41impl<R, Parser> From<R> for DebugLookup<R, Parser>
42where
43 R: Reader,
44 Parser: LookupParser<R>,
45{
46 fn from(input_buffer: R) -> Self {
47 DebugLookup {
48 input_buffer,
49 phantom: PhantomData,
50 }
51 }
52}
53
54impl<R, Parser> DebugLookup<R, Parser>
55where
56 R: Reader,
57 Parser: LookupParser<R>,
58{
59 pub fn items(&self) -> LookupEntryIter<R, Parser> {
60 LookupEntryIter {
61 current_set: None,
62 remaining_input: self.input_buffer.clone(),
63 }
64 }
65
66 pub fn reader(&self) -> &R {
67 &self.input_buffer
68 }
69}
70
71#[derive(Clone, Debug)]
72pub struct LookupEntryIter<R, Parser>
73where
74 R: Reader,
75 Parser: LookupParser<R>,
76{
77 current_set: Option<(R, Parser::Header)>, remaining_input: R,
79}
80
81impl<R, Parser> LookupEntryIter<R, Parser>
82where
83 R: Reader,
84 Parser: LookupParser<R>,
85{
86 pub fn next(&mut self) -> Result<Option<Parser::Entry>> {
94 loop {
95 if let Some((ref mut input, ref header)) = self.current_set
96 && !input.is_empty()
97 {
98 match Parser::parse_entry(input, header) {
99 Ok(Some(entry)) => return Ok(Some(entry)),
100 Ok(None) => {}
101 Err(e) => {
102 input.empty();
103 self.remaining_input.empty();
104 return Err(e);
105 }
106 }
107 }
108 if self.remaining_input.is_empty() {
109 self.current_set = None;
110 return Ok(None);
111 }
112 match Parser::parse_header(&mut self.remaining_input) {
113 Ok(set) => {
114 self.current_set = Some(set);
115 }
116 Err(e) => {
117 self.current_set = None;
118 self.remaining_input.empty();
119 return Err(e);
120 }
121 }
122 }
123 }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
127pub struct PubStuffHeader<T = usize> {
128 format: Format,
129 length: T,
130 version: u16,
131 unit_offset: DebugInfoOffset<T>,
132 unit_length: T,
133}
134
135pub trait PubStuffEntry<R: Reader> {
136 fn new(
137 die_offset: UnitOffset<R::Offset>,
138 name: R,
139 unit_header_offset: DebugInfoOffset<R::Offset>,
140 ) -> Self;
141}
142
143#[derive(Clone, Debug)]
144pub struct PubStuffParser<R, Entry>
145where
146 R: Reader,
147 Entry: PubStuffEntry<R>,
148{
149 phantom: PhantomData<(R, Entry)>,
151}
152
153impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
154where
155 R: Reader,
156 Entry: PubStuffEntry<R>,
157{
158 type Header = PubStuffHeader<R::Offset>;
159 type Entry = Entry;
160
161 fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
164 let (length, format) = input.read_initial_length()?;
165 let mut rest = input.split(length)?;
166
167 let version = rest.read_u16()?;
168 if version != 2 {
169 return Err(Error::UnknownVersion(u64::from(version)));
170 }
171
172 let unit_offset = rest.read_offset(format).map(DebugInfoOffset)?;
173 let unit_length = rest.read_length(format)?;
174
175 let header = PubStuffHeader {
176 format,
177 length,
178 version,
179 unit_offset,
180 unit_length,
181 };
182 Ok((rest, header))
183 }
184
185 fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
187 let offset = input.read_offset(header.format)?;
188 if offset.into_u64() == 0 {
189 input.empty();
190 Ok(None)
191 } else {
192 let name = input.read_null_terminated_slice()?;
193 Ok(Some(Self::Entry::new(
194 UnitOffset(offset),
195 name,
196 header.unit_offset,
197 )))
198 }
199 }
200}