fugue_ir/
space_manager.rs

1use std::fmt::Debug;
2use std::sync::Arc;
3
4use crate::address::AddressValue;
5use crate::deserialise::Error;
6use crate::disassembly::IRBuilderArena;
7use crate::space::{AddressSpace, AddressSpaceId, Space, SpaceKind, SpaceProperty};
8
9#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
10pub struct SpaceManager {
11    spaces: Vec<Arc<AddressSpace>>,
12    constant_space: usize,
13    default_space: usize,
14    register_space: usize,
15    unique_space: usize,
16}
17
18pub trait FromSpace<'z, T> {
19    fn from_space(t: T, manager: &SpaceManager) -> Self;
20    fn from_space_with(t: T, arena: &'z IRBuilderArena, manager: &SpaceManager) -> Self;
21}
22
23pub trait IntoSpace<'z, T> {
24    fn into_space(self, manager: &SpaceManager) -> T;
25    fn into_space_with(self, arena: &'z IRBuilderArena, manager: &SpaceManager) -> T;
26}
27
28impl<'z, T, U> IntoSpace<'z, T> for U
29where
30    T: FromSpace<'z, U>,
31{
32    fn into_space(self, manager: &SpaceManager) -> T {
33        T::from_space(self, manager)
34    }
35
36    fn into_space_with(self, arena: &'z IRBuilderArena, manager: &SpaceManager) -> T {
37        T::from_space_with(self, arena, manager)
38    }
39}
40
41impl SpaceManager {
42    pub fn address_from<S: AsRef<str>>(&self, space: S, offset: u64) -> Option<AddressValue> {
43        let space = self.space_by_name(space)?;
44        Some(AddressValue::new(space, offset))
45    }
46
47    pub fn address_size(&self) -> usize {
48        unsafe { self.spaces.get_unchecked(self.default_space) }.address_size()
49    }
50
51    pub fn spaces(&self) -> &[Arc<AddressSpace>] {
52        self.spaces.as_ref()
53    }
54
55    pub fn space_by_name<S: AsRef<str>>(&self, name: S) -> Option<Arc<AddressSpace>> {
56        let name = name.as_ref();
57        self.spaces.iter().find_map(|space| {
58            if space.name() == name {
59                Some(space.clone())
60            } else {
61                None
62            }
63        })
64    }
65
66    pub fn space_by_id(&self, id: AddressSpaceId) -> &AddressSpace {
67        &self.spaces[id.index()]
68    }
69
70    pub unsafe fn unchecked_space_by_id(&self, id: AddressSpaceId) -> &AddressSpace {
71        &*self.spaces.get_unchecked(id.index())
72    }
73
74    pub fn constant_space(&self) -> Arc<AddressSpace> {
75        unsafe { self.spaces.get_unchecked(self.constant_space) }.clone()
76    }
77
78    pub fn constant_space_ref(&self) -> &AddressSpace {
79        &*unsafe { self.spaces.get_unchecked(self.constant_space) }
80    }
81
82    pub fn constant_space_id(&self) -> AddressSpaceId {
83        AddressSpaceId::constant_id(self.constant_space)
84    }
85
86    pub fn default_space(&self) -> Arc<AddressSpace> {
87        unsafe { self.spaces.get_unchecked(self.default_space) }.clone()
88    }
89
90    pub fn default_space_ref(&self) -> &AddressSpace {
91        &*unsafe { self.spaces.get_unchecked(self.default_space) }
92    }
93
94    pub fn default_space_id(&self) -> AddressSpaceId {
95        AddressSpaceId::default_id(self.default_space)
96    }
97
98    pub fn register_space(&self) -> Arc<AddressSpace> {
99        unsafe { self.spaces.get_unchecked(self.register_space) }.clone()
100    }
101
102    pub fn register_space_ref(&self) -> &AddressSpace {
103        &*unsafe { self.spaces.get_unchecked(self.register_space) }
104    }
105
106    pub fn register_space_id(&self) -> AddressSpaceId {
107        AddressSpaceId::register_id(self.register_space)
108    }
109
110    pub fn unique_space(&self) -> Arc<AddressSpace> {
111        unsafe { self.spaces.get_unchecked(self.unique_space) }.clone()
112    }
113
114    pub fn unique_space_ref(&self) -> &AddressSpace {
115        &*unsafe { self.spaces.get_unchecked(self.unique_space) }
116    }
117
118    pub fn unique_space_id(&self) -> AddressSpaceId {
119        AddressSpaceId::unique_id(self.unique_space)
120    }
121
122    pub fn add_space<S: AsRef<str>>(
123        &mut self,
124        kind: SpaceKind,
125        name: S,
126        address_size: usize,
127        word_size: usize,
128        properties: Option<SpaceProperty>,
129        delay: usize,
130    ) -> Arc<AddressSpace> {
131        let index = self.spaces.len();
132        let space = Arc::new(AddressSpace::Space(Space::new(
133            kind,
134            name,
135            address_size,
136            word_size,
137            index,
138            properties,
139            delay,
140        )));
141        self.spaces.push(space.clone());
142        space
143    }
144
145    pub fn add_space_like<S: AsRef<str>>(
146        &mut self,
147        name: S,
148        space: &AddressSpace,
149    ) -> Arc<AddressSpace> {
150        self.add_space(
151            space.kind(),
152            name,
153            space.address_size(),
154            space.word_size(),
155            Some(space.properties()),
156            space.delay(),
157        )
158    }
159
160    pub fn from_xml(input: xml::Node) -> Result<Self, Error> {
161        if input.tag_name().name() != "spaces" {
162            return Err(Error::TagUnexpected(input.tag_name().name().to_owned()));
163        }
164
165        let mut spaces = vec![Arc::new(AddressSpace::constant("const", 0))];
166        let mut default_space = 0;
167        let mut register_space = 0;
168        let mut unique_space = 0;
169
170        let default_name = input
171            .attribute("defaultspace")
172            .ok_or_else(|| Error::AttributeExpected("defaultspace"))?;
173
174        for (index, child) in input
175            .children()
176            .filter(xml::Node::is_element)
177            .enumerate()
178            .map(|(i, c)| (i + 1, c))
179        {
180            let mut space = AddressSpace::from_xml(child)?;
181
182            if space.index() != index {
183                return Err(Error::Invariant("space index mismatch"));
184            }
185
186            if space.name() == default_name {
187                default_space = index;
188                space.kind = SpaceKind::Default;
189            }
190
191            if space.name() == "register" {
192                register_space = index;
193                space.kind = SpaceKind::Register;
194            }
195
196            if space.name() == "unique" {
197                unique_space = index;
198            }
199
200            spaces.push(Arc::new(space));
201        }
202
203        if default_space == 0 {
204            return Err(Error::Invariant("non-constant default space not defined"));
205        }
206
207        if register_space == 0 {
208            return Err(Error::Invariant("register space not defined"));
209        }
210
211        if unique_space == 0 {
212            return Err(Error::Invariant("unique space not defined"));
213        }
214
215        Ok(Self {
216            spaces,
217            constant_space: 0,
218            default_space,
219            register_space,
220            unique_space,
221        })
222    }
223}