1use core::marker::PhantomData;
2
3use crate::common::{DebugInfoOffset, Format};
4use crate::read::{parse_debug_info_offset, 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>> {
96        loop {
97            if let Some((ref mut input, ref header)) = self.current_set {
98                if !input.is_empty() {
99                    match Parser::parse_entry(input, header) {
100                        Ok(Some(entry)) => return Ok(Some(entry)),
101                        Ok(None) => {}
102                        Err(e) => {
103                            input.empty();
104                            self.remaining_input.empty();
105                            return Err(e);
106                        }
107                    }
108                }
109            }
110            if self.remaining_input.is_empty() {
111                self.current_set = None;
112                return Ok(None);
113            }
114            match Parser::parse_header(&mut self.remaining_input) {
115                Ok(set) => {
116                    self.current_set = Some(set);
117                }
118                Err(e) => {
119                    self.current_set = None;
120                    self.remaining_input.empty();
121                    return Err(e);
122                }
123            }
124        }
125    }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct PubStuffHeader<T = usize> {
130    format: Format,
131    length: T,
132    version: u16,
133    unit_offset: DebugInfoOffset<T>,
134    unit_length: T,
135}
136
137pub trait PubStuffEntry<R: Reader> {
138    fn new(
139        die_offset: UnitOffset<R::Offset>,
140        name: R,
141        unit_header_offset: DebugInfoOffset<R::Offset>,
142    ) -> Self;
143}
144
145#[derive(Clone, Debug)]
146pub struct PubStuffParser<R, Entry>
147where
148    R: Reader,
149    Entry: PubStuffEntry<R>,
150{
151    phantom: PhantomData<(R, Entry)>,
153}
154
155impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
156where
157    R: Reader,
158    Entry: PubStuffEntry<R>,
159{
160    type Header = PubStuffHeader<R::Offset>;
161    type Entry = Entry;
162
163    fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
166        let (length, format) = input.read_initial_length()?;
167        let mut rest = input.split(length)?;
168
169        let version = rest.read_u16()?;
170        if version != 2 {
171            return Err(Error::UnknownVersion(u64::from(version)));
172        }
173
174        let unit_offset = parse_debug_info_offset(&mut rest, format)?;
175        let unit_length = rest.read_length(format)?;
176
177        let header = PubStuffHeader {
178            format,
179            length,
180            version,
181            unit_offset,
182            unit_length,
183        };
184        Ok((rest, header))
185    }
186
187    fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
189        let offset = input.read_offset(header.format)?;
190        if offset.into_u64() == 0 {
191            input.empty();
192            Ok(None)
193        } else {
194            let name = input.read_null_terminated_slice()?;
195            Ok(Some(Self::Entry::new(
196                UnitOffset(offset),
197                name,
198                header.unit_offset,
199            )))
200        }
201    }
202}