1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::borrow::Cow;

use debugid::DebugId;
use yoke::{Yoke, Yokeable};

use crate::{shared::AddressInfo, Error, FileLocation};

pub struct SymbolMap<FL: FileLocation> {
    debug_file_location: FL,
    pub(crate) inner: Box<dyn SymbolMapTrait>,
}

impl<FL: FileLocation> SymbolMap<FL> {
    pub(crate) fn new(debug_file_location: FL, inner: Box<dyn SymbolMapTrait>) -> Self {
        Self {
            debug_file_location,
            inner,
        }
    }

    pub fn debug_file_location(&self) -> &FL {
        &self.debug_file_location
    }

    pub fn debug_id(&self) -> debugid::DebugId {
        self.inner.debug_id()
    }

    pub fn symbol_count(&self) -> usize {
        self.inner.symbol_count()
    }

    pub fn iter_symbols(&self) -> Box<dyn Iterator<Item = (u32, Cow<'_, str>)> + '_> {
        self.inner.iter_symbols()
    }

    pub fn lookup(&self, address: u32) -> Option<AddressInfo> {
        self.inner.lookup(address)
    }
}

pub trait SymbolMapTrait {
    fn debug_id(&self) -> DebugId;

    fn symbol_count(&self) -> usize;

    fn iter_symbols(&self) -> Box<dyn Iterator<Item = (u32, Cow<'_, str>)> + '_>;

    fn lookup(&self, address: u32) -> Option<AddressInfo>;
}

pub trait SymbolMapDataOuterTrait {
    fn make_symbol_map_data_mid(&self) -> Result<Box<dyn SymbolMapDataMidTrait + '_>, Error>;
}

pub trait SymbolMapDataMidTrait {
    fn make_symbol_map_inner(&self) -> Result<SymbolMapInnerWrapper<'_>, Error>;
}

#[derive(Yokeable)]
pub struct SymbolMapDataMidWrapper<'data>(Box<dyn SymbolMapDataMidTrait + 'data>);

struct SymbolMapDataOuterAndMid<SMDO: SymbolMapDataOuterTrait>(
    Yoke<SymbolMapDataMidWrapper<'static>, Box<SMDO>>,
);

pub struct GenericSymbolMap<SMDO: SymbolMapDataOuterTrait>(
    Yoke<SymbolMapInnerWrapper<'static>, Box<SymbolMapDataOuterAndMid<SMDO>>>,
);

impl<SMDO: SymbolMapDataOuterTrait> GenericSymbolMap<SMDO> {
    pub fn new(outer: SMDO) -> Result<Self, Error> {
        let outer_and_mid = SymbolMapDataOuterAndMid(
            Yoke::<SymbolMapDataMidWrapper<'static>, _>::try_attach_to_cart(
                Box::new(outer),
                |outer| {
                    outer
                        .make_symbol_map_data_mid()
                        .map(SymbolMapDataMidWrapper)
                },
            )?,
        );
        let outer_and_mid_and_inner = Yoke::<SymbolMapInnerWrapper, _>::try_attach_to_cart(
            Box::new(outer_and_mid),
            |outer_and_mid| {
                let mid = outer_and_mid.0.get();
                mid.0.make_symbol_map_inner()
            },
        )?;
        Ok(GenericSymbolMap(outer_and_mid_and_inner))
    }
}

#[derive(Yokeable)]
pub struct SymbolMapInnerWrapper<'data>(pub Box<dyn SymbolMapTrait + 'data>);

impl<SMDO: SymbolMapDataOuterTrait> SymbolMapTrait for GenericSymbolMap<SMDO> {
    fn debug_id(&self) -> debugid::DebugId {
        self.0.get().0.debug_id()
    }

    fn symbol_count(&self) -> usize {
        self.0.get().0.symbol_count()
    }

    fn iter_symbols(&self) -> Box<dyn Iterator<Item = (u32, Cow<'_, str>)> + '_> {
        self.0.get().0.iter_symbols()
    }

    fn lookup(&self, address: u32) -> Option<AddressInfo> {
        self.0.get().0.lookup(address)
    }
}