1use alloc::vec::Vec;
2use core::cmp::Ordering;
3
4use miden_objects::{Felt, LexicographicWord, Word, ZERO};
5use miden_processor::{AdviceMutation, ContextId, EventError, ProcessState};
6
7#[derive(Debug, Clone, Copy)]
21pub struct LinkMap<'process> {
22 map_ptr: u32,
23 process: &'process ProcessState<'process>,
24}
25
26impl<'process> LinkMap<'process> {
27 pub fn new(map_ptr: Felt, process: &'process ProcessState<'process>) -> Self {
32 let map_ptr: u32 = map_ptr.try_into().expect("map_ptr must be a valid u32");
33
34 Self { map_ptr, process }
35 }
36
37 pub fn handle_set_event(process: &ProcessState<'_>) -> Result<Vec<AdviceMutation>, EventError> {
45 let map_ptr = process.get_stack_item(0);
46 let map_key = Word::from([
47 process.get_stack_item(4),
48 process.get_stack_item(3),
49 process.get_stack_item(2),
50 process.get_stack_item(1),
51 ]);
52
53 let link_map = LinkMap::new(map_ptr, process);
54
55 let (set_op, entry_ptr) = link_map.compute_set_operation(LexicographicWord::from(map_key));
56
57 Ok(vec![AdviceMutation::extend_stack([
58 Felt::from(set_op as u8),
59 Felt::from(entry_ptr),
60 ])])
61 }
62
63 pub fn handle_get_event(process: &ProcessState<'_>) -> Result<Vec<AdviceMutation>, EventError> {
68 let map_ptr = process.get_stack_item(0);
69 let map_key = Word::from([
70 process.get_stack_item(4),
71 process.get_stack_item(3),
72 process.get_stack_item(2),
73 process.get_stack_item(1),
74 ]);
75
76 let link_map = LinkMap::new(map_ptr, process);
77 let (get_op, entry_ptr) = link_map.compute_get_operation(LexicographicWord::from(map_key));
78
79 Ok(vec![AdviceMutation::extend_stack([
80 Felt::from(get_op as u8),
81 Felt::from(entry_ptr),
82 ])])
83 }
84
85 pub fn is_empty(&self) -> bool {
87 self.head().is_none()
88 }
89
90 pub fn iter(&self) -> impl Iterator<Item = Entry> {
92 LinkMapIter {
93 current_entry_ptr: self.head().unwrap_or(0),
94 map: *self,
95 }
96 }
97
98 fn head(&self) -> Option<u32> {
103 self.get_kernel_mem_value(self.map_ptr).and_then(|head_ptr| {
107 if head_ptr == ZERO {
108 None
109 } else {
110 Some(u32::try_from(head_ptr).expect("head ptr should be a valid ptr"))
111 }
112 })
113 }
114
115 fn entry(&self, entry_ptr: u32) -> Entry {
117 let key = self.key(entry_ptr);
118 let (value0, value1) = self.value(entry_ptr);
119 let metadata = self.metadata(entry_ptr);
120
121 Entry {
122 ptr: entry_ptr,
123 metadata,
124 key,
125 value0,
126 value1,
127 }
128 }
129
130 fn key(&self, entry_ptr: u32) -> LexicographicWord {
132 LexicographicWord::from(
133 self.get_kernel_mem_word(entry_ptr + 4).expect("entry pointer should be valid"),
134 )
135 }
136
137 fn value(&self, entry_ptr: u32) -> (Word, Word) {
139 let value0 =
140 self.get_kernel_mem_word(entry_ptr + 8).expect("entry pointer should be valid");
141 let value1 =
142 self.get_kernel_mem_word(entry_ptr + 12).expect("entry pointer should be valid");
143 (value0, value1)
144 }
145
146 fn metadata(&self, entry_ptr: u32) -> EntryMetadata {
148 let entry_metadata =
149 self.get_kernel_mem_word(entry_ptr).expect("entry pointer should be valid");
150
151 let map_ptr = entry_metadata[0];
152 let map_ptr = map_ptr.try_into().expect("entry_ptr should point to a u32 map_ptr");
153
154 let prev_entry_ptr = entry_metadata[1];
155 let prev_entry_ptr = prev_entry_ptr
156 .try_into()
157 .expect("entry_ptr should point to a u32 prev_entry_ptr");
158
159 let next_entry_ptr = entry_metadata[2];
160 let next_entry_ptr = next_entry_ptr
161 .try_into()
162 .expect("entry_ptr should point to a u32 next_entry_ptr");
163
164 EntryMetadata { map_ptr, prev_entry_ptr, next_entry_ptr }
165 }
166
167 fn compute_set_operation(&self, key: LexicographicWord) -> (SetOperation, u32) {
179 let Some(current_head) = self.head() else {
180 return (SetOperation::InsertAtHead, 0);
181 };
182
183 let mut last_entry_ptr: u32 = current_head;
184
185 for entry in self.iter() {
186 match key.cmp(&entry.key) {
187 Ordering::Equal => {
188 return (SetOperation::Update, entry.ptr);
189 },
190 Ordering::Less => {
191 if entry.ptr == current_head {
192 return (SetOperation::InsertAtHead, entry.ptr);
193 }
194
195 break;
196 },
197 Ordering::Greater => {
198 last_entry_ptr = entry.ptr;
199 },
200 }
201 }
202
203 (SetOperation::InsertAfterEntry, last_entry_ptr)
204 }
205
206 fn compute_get_operation(&self, key: LexicographicWord) -> (GetOperation, u32) {
217 let (set_op, entry_ptr) = self.compute_set_operation(key);
218 let get_op = match set_op {
219 SetOperation::Update => GetOperation::Found,
220 SetOperation::InsertAtHead => GetOperation::AbsentAtHead,
221 SetOperation::InsertAfterEntry => GetOperation::AbsentAfterEntry,
222 };
223 (get_op, entry_ptr)
224 }
225
226 fn get_kernel_mem_value(&self, addr: u32) -> Option<Felt> {
230 self.process.get_mem_value(ContextId::root(), addr)
231 }
232
233 fn get_kernel_mem_word(&self, addr: u32) -> Option<Word> {
234 self.process
235 .get_mem_word(ContextId::root(), addr)
236 .expect("address should be word-aligned")
237 }
238}
239
240struct LinkMapIter<'process> {
245 current_entry_ptr: u32,
246 map: LinkMap<'process>,
247}
248
249impl<'process> Iterator for LinkMapIter<'process> {
250 type Item = Entry;
251
252 fn next(&mut self) -> Option<Self::Item> {
253 if self.current_entry_ptr == 0 {
254 return None;
255 }
256
257 let current_entry = self.map.entry(self.current_entry_ptr);
258
259 self.current_entry_ptr = current_entry.metadata.next_entry_ptr;
260
261 Some(current_entry)
262 }
263}
264
265#[derive(Debug, Clone, Copy)]
272pub struct Entry {
273 pub ptr: u32,
274 pub metadata: EntryMetadata,
275 pub key: LexicographicWord,
276 pub value0: Word,
277 pub value1: Word,
278}
279
280#[derive(Debug, Clone, Copy)]
284pub struct EntryMetadata {
285 pub map_ptr: u32,
286 pub prev_entry_ptr: u32,
287 pub next_entry_ptr: u32,
288}
289
290#[derive(Debug, Clone, Copy)]
295#[repr(u8)]
296enum GetOperation {
297 Found = 0,
298 AbsentAtHead = 1,
299 AbsentAfterEntry = 2,
300}
301
302#[derive(Debug, Clone, Copy)]
304#[repr(u8)]
305enum SetOperation {
306 Update = 0,
307 InsertAtHead = 1,
308 InsertAfterEntry = 2,
309}