Skip to main content

qcode/value/
temp.rs

1//! Function-local temporary spaces and values.
2//!
3//! These arenas are introduced before producers migrate away from shared
4//! [`Varnode`](crate::value::Varnode) storage. Body storage uses the local IDs;
5//! immutable module/API boundaries use the function-qualified IDs.
6
7use std::{borrow::Cow, fmt::Display, marker::PhantomData};
8
9use jstd::Identifier;
10
11use crate::value::{ModuleView, QCodeView, Value, ValueId, util::named::Named};
12
13/// Function-local temporary-space index.
14#[derive(Identifier)]
15pub struct LocalTempSpaceId(usize);
16
17crate::composite_id!(TempSpaceId, LocalTempSpaceId);
18
19/// Function-local temporary-value index.
20#[derive(Identifier)]
21pub struct LocalTempId(usize);
22
23crate::composite_id!(TempId, LocalTempId);
24
25/// A body-owned memory space used only for temporary values.
26#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
27pub struct TempSpace {
28    pub(crate) name: Option<Box<str>>,
29    pub(crate) word_size: usize,
30    pub(crate) addr_size: usize,
31}
32
33impl TempSpace {
34    pub fn new(name: Option<&str>, word_size: usize, addr_size: usize) -> Self {
35        Self {
36            name: name.map(Box::from),
37            word_size,
38            addr_size,
39        }
40    }
41
42    pub fn name(&self) -> Option<&str> {
43        self.name.as_deref()
44    }
45
46    pub fn word_size(&self) -> usize {
47        self.word_size
48    }
49
50    pub fn addr_size(&self) -> usize {
51        self.addr_size
52    }
53}
54
55/// A body-owned temporary memory value.
56#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
57pub struct Temp<'str> {
58    pub(crate) name: Option<Cow<'str, str>>,
59    pub(crate) label: Option<u32>,
60    pub(crate) address: i64,
61    pub(crate) size: usize,
62    pub(crate) space: LocalTempSpaceId,
63}
64
65impl<'str> Temp<'str> {
66    pub fn new(address: i64, size: usize, space: LocalTempSpaceId) -> Self {
67        Self {
68            name: None,
69            label: None,
70            address,
71            size,
72            space,
73        }
74    }
75
76    /// Attaches the function-local name registered when this temporary is
77    /// inserted into its owning body.
78    pub fn with_name(mut self, name: Cow<'str, str>) -> Self {
79        self.name = Some(name);
80        self
81    }
82}
83
84/// Immutable temporary-space reference over any [`QCodeView`] provider.
85#[derive(Clone, Copy)]
86pub struct TempSpaceRef<'str, 'ctx, R = ModuleView<'ctx, 'str>> {
87    pub id: TempSpaceId,
88    view: R,
89    marker: PhantomData<&'ctx &'str ()>,
90}
91
92impl<'str, 'ctx, R> TempSpaceRef<'str, 'ctx, R> {
93    pub fn new(view: R, id: TempSpaceId) -> Self {
94        Self {
95            id,
96            view,
97            marker: PhantomData,
98        }
99    }
100}
101
102impl<'str: 'ctx, 'ctx, R> TempSpaceRef<'str, 'ctx, R>
103where
104    R: QCodeView<'ctx, 'str>,
105{
106    fn inner(self) -> &'ctx TempSpace {
107        self.view.temp_space(self.id)
108    }
109
110    pub fn name(self) -> Option<&'ctx str> {
111        self.inner().name.as_deref()
112    }
113
114    pub fn word_size(self) -> usize {
115        self.inner().word_size
116    }
117
118    pub fn addr_size(self) -> usize {
119        self.inner().addr_size
120    }
121}
122
123impl<'str: 'ctx, 'ctx, R> Display for TempSpaceRef<'str, 'ctx, R>
124where
125    R: QCodeView<'ctx, 'str>,
126{
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        f.write_str(self.name().unwrap_or("temp"))
129    }
130}
131
132/// Immutable temporary-value reference over any [`QCodeView`] provider.
133#[derive(Clone, Copy)]
134pub struct TempRef<'str, 'ctx, R = ModuleView<'ctx, 'str>> {
135    pub id: TempId,
136    pub(in crate::value) view: R,
137    marker: PhantomData<&'ctx &'str ()>,
138}
139
140impl<'str, 'ctx, R> TempRef<'str, 'ctx, R> {
141    pub fn new(view: R, id: TempId) -> Self {
142        Self {
143            id,
144            view,
145            marker: PhantomData,
146        }
147    }
148}
149
150impl<'str: 'ctx, 'ctx, R> TempRef<'str, 'ctx, R>
151where
152    R: QCodeView<'ctx, 'str>,
153{
154    fn inner(self) -> &'ctx Temp<'str> {
155        self.view.temp(self.id)
156    }
157
158    pub fn name(self) -> Option<&'ctx str> {
159        self.inner().name.as_deref()
160    }
161
162    pub fn label(self) -> Option<u32> {
163        self.inner().label
164    }
165
166    pub fn address(self) -> i64 {
167        self.inner().address
168    }
169
170    pub fn size(self) -> usize {
171        self.inner().size
172    }
173
174    pub fn space(self) -> TempSpaceRef<'str, 'ctx, R> {
175        TempSpaceRef::new(
176            self.view,
177            TempSpaceId::new(self.id.func, self.inner().space),
178        )
179    }
180
181    pub fn memory_space(self) -> crate::space::MemorySpaceId {
182        crate::space::MemorySpaceId::Temp(self.space().id)
183    }
184}
185
186impl<'str: 'ctx, 'ctx, R> Display for TempRef<'str, 'ctx, R>
187where
188    R: QCodeView<'ctx, 'str>,
189{
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191        if let Some(name) = self.name() {
192            f.write_str(name)
193        } else if let Some(label) = self.label() {
194            write!(f, "v{label}")
195        } else {
196            write!(f, "[{}]:{} {}", self.space(), self.size(), self.address())
197        }
198    }
199}
200
201impl<'str: 'ctx, 'ctx, R> Named for TempRef<'str, 'ctx, R>
202where
203    R: QCodeView<'ctx, 'str>,
204{
205    fn name(&self) -> Option<&str> {
206        TempRef::name(*self)
207    }
208}
209
210impl<'str: 'ctx, 'ctx, R> Value<'str, 'ctx> for TempRef<'str, 'ctx, R>
211where
212    R: QCodeView<'ctx, 'str>,
213{
214    fn id(&self) -> ValueId {
215        ValueId::Temp(self.id)
216    }
217
218    fn size(&self) -> usize {
219        TempRef::size(*self)
220    }
221}