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
43/// A body-owned temporary memory value.
44#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
45pub struct Temp<'str> {
46    pub(crate) name: Option<Cow<'str, str>>,
47    pub(crate) label: Option<u32>,
48    pub(crate) address: i64,
49    pub(crate) size: usize,
50    pub(crate) space: LocalTempSpaceId,
51}
52
53impl<'str> Temp<'str> {
54    pub fn new(address: i64, size: usize, space: LocalTempSpaceId) -> Self {
55        Self {
56            name: None,
57            label: None,
58            address,
59            size,
60            space,
61        }
62    }
63
64    /// Attaches the function-local name registered when this temporary is
65    /// inserted into its owning body.
66    pub fn with_name(mut self, name: Cow<'str, str>) -> Self {
67        self.name = Some(name);
68        self
69    }
70}
71
72/// Immutable temporary-space reference over any [`QCodeView`] provider.
73#[derive(Clone, Copy)]
74pub struct TempSpaceRef<'str, 'ctx, R = ModuleView<'ctx, 'str>> {
75    pub id: TempSpaceId,
76    view: R,
77    marker: PhantomData<&'ctx &'str ()>,
78}
79
80impl<'str, 'ctx, R> TempSpaceRef<'str, 'ctx, R> {
81    pub fn new(view: R, id: TempSpaceId) -> Self {
82        Self {
83            id,
84            view,
85            marker: PhantomData,
86        }
87    }
88}
89
90impl<'str: 'ctx, 'ctx, R> TempSpaceRef<'str, 'ctx, R>
91where
92    R: QCodeView<'ctx, 'str>,
93{
94    fn inner(self) -> &'ctx TempSpace {
95        self.view.temp_space(self.id)
96    }
97
98    pub fn name(self) -> Option<&'ctx str> {
99        self.inner().name.as_deref()
100    }
101
102    pub fn word_size(self) -> usize {
103        self.inner().word_size
104    }
105
106    pub fn addr_size(self) -> usize {
107        self.inner().addr_size
108    }
109}
110
111impl<'str: 'ctx, 'ctx, R> Display for TempSpaceRef<'str, 'ctx, R>
112where
113    R: QCodeView<'ctx, 'str>,
114{
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        f.write_str(self.name().unwrap_or("temp"))
117    }
118}
119
120/// Immutable temporary-value reference over any [`QCodeView`] provider.
121#[derive(Clone, Copy)]
122pub struct TempRef<'str, 'ctx, R = ModuleView<'ctx, 'str>> {
123    pub id: TempId,
124    pub(in crate::value) view: R,
125    marker: PhantomData<&'ctx &'str ()>,
126}
127
128impl<'str, 'ctx, R> TempRef<'str, 'ctx, R> {
129    pub fn new(view: R, id: TempId) -> Self {
130        Self {
131            id,
132            view,
133            marker: PhantomData,
134        }
135    }
136}
137
138impl<'str: 'ctx, 'ctx, R> TempRef<'str, 'ctx, R>
139where
140    R: QCodeView<'ctx, 'str>,
141{
142    fn inner(self) -> &'ctx Temp<'str> {
143        self.view.temp(self.id)
144    }
145
146    pub fn name(self) -> Option<&'ctx str> {
147        self.inner().name.as_deref()
148    }
149
150    pub fn label(self) -> Option<u32> {
151        self.inner().label
152    }
153
154    pub fn address(self) -> i64 {
155        self.inner().address
156    }
157
158    pub fn size(self) -> usize {
159        self.inner().size
160    }
161
162    pub fn space(self) -> TempSpaceRef<'str, 'ctx, R> {
163        TempSpaceRef::new(
164            self.view,
165            TempSpaceId::new(self.id.func, self.inner().space),
166        )
167    }
168
169    pub fn memory_space(self) -> crate::space::MemorySpaceId {
170        crate::space::MemorySpaceId::Temp(self.space().id)
171    }
172}
173
174impl<'str: 'ctx, 'ctx, R> Display for TempRef<'str, 'ctx, R>
175where
176    R: QCodeView<'ctx, 'str>,
177{
178    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179        if let Some(name) = self.name() {
180            f.write_str(name)
181        } else if let Some(label) = self.label() {
182            write!(f, "v{label}")
183        } else {
184            write!(f, "[{}]:{} {}", self.space(), self.size(), self.address())
185        }
186    }
187}
188
189impl<'str: 'ctx, 'ctx, R> Named for TempRef<'str, 'ctx, R>
190where
191    R: QCodeView<'ctx, 'str>,
192{
193    fn name(&self) -> Option<&str> {
194        TempRef::name(*self)
195    }
196}
197
198impl<'str: 'ctx, 'ctx, R> Value<'str, 'ctx> for TempRef<'str, 'ctx, R>
199where
200    R: QCodeView<'ctx, 'str>,
201{
202    fn id(&self) -> ValueId {
203        ValueId::Temp(self.id)
204    }
205
206    fn size(&self) -> usize {
207        TempRef::size(*self)
208    }
209}