1use crate::objects::{self, FieldSlot};
16use std::sync::{Mutex, OnceLock};
17
18pub const WIN_BIT: u64 = 1 << 62;
20
21#[derive(Clone, Copy)]
22enum Root {
23 Mem(usize),
25 Field(u64, FieldSlot),
27}
28
29#[derive(Clone, Copy)]
30struct Win {
31 root: Root,
32 two_state: bool,
34}
35
36#[derive(Default)]
37struct Wins {
38 slots: Vec<Option<Win>>,
39 free: Vec<u32>,
40}
41
42fn table() -> &'static Mutex<Wins> {
43 static T: OnceLock<Mutex<Wins>> = OnceLock::new();
44 T.get_or_init(|| Mutex::new(Wins::default()))
45}
46
47pub fn is_window(id: u64) -> bool {
49 id & WIN_BIT != 0
50}
51
52fn push(w: Win) -> u64 {
53 let mut t = table().lock().unwrap_or_else(|e| e.into_inner());
54 let k = match t.free.pop() {
55 Some(k) => {
56 t.slots[k as usize] = Some(w);
57 k
58 }
59 None => {
60 t.slots.push(Some(w));
61 (t.slots.len() - 1) as u32
62 }
63 };
64 WIN_BIT | (u64::from(k) + 1)
65}
66
67fn lookup(id: u64) -> Option<Win> {
68 let t = table().lock().unwrap_or_else(|e| e.into_inner());
69 let k = (id & !WIN_BIT).checked_sub(1)? as usize;
70 t.slots.get(k).copied().flatten()
71}
72
73pub unsafe fn open_mem(addr: usize, two_state: bool) -> u64 {
79 push(Win {
80 root: Root::Mem(addr),
81 two_state,
82 })
83}
84
85pub fn open_field(h: u64, slot: FieldSlot, two_state: bool) -> u64 {
87 push(Win {
88 root: Root::Field(h, slot),
89 two_state,
90 })
91}
92
93pub fn close(id: u64) {
95 let mut t = table().lock().unwrap_or_else(|e| e.into_inner());
96 if let Some(k) = (id & !WIN_BIT).checked_sub(1).map(|k| k as usize)
97 && t.slots.get_mut(k).and_then(Option::take).is_some()
98 {
99 t.free.push(k as u32);
100 }
101}
102
103fn bit_at(words: &[u64], i: usize) -> bool {
104 words.get(i / 64).is_some_and(|w| w >> (i % 64) & 1 != 0)
105}
106
107fn set_bit(words: &mut [u64], i: usize, v: bool) {
108 if let Some(w) = words.get_mut(i / 64) {
109 if v {
110 *w |= 1 << (i % 64);
111 } else {
112 *w &= !(1 << (i % 64));
113 }
114 }
115}
116
117fn image_bits(win: Win, big_w: u32) -> usize {
119 if win.two_state {
120 big_w as usize
121 } else {
122 2 * big_w as usize
123 }
124}
125
126fn load(win: Win, big_w: u32) -> Option<Vec<u64>> {
128 let bits = image_bits(win, big_w);
129 match win.root {
130 Root::Mem(addr) => {
131 let mut words = vec![0u64; bits.div_ceil(64).max(1)];
132 let bytes = unsafe { std::slice::from_raw_parts(addr as *const u8, bits.div_ceil(8)) };
134 for (i, b) in bytes.iter().enumerate() {
135 words[i / 8] |= u64::from(*b) << (8 * (i % 8));
136 }
137 Some(words)
138 }
139 Root::Field(h, slot) => {
140 let mut words = vec![0u64; slot.words.max(1)];
141 objects::field_get(h, slot, &mut words).then_some(words)
142 }
143 }
144}
145
146fn store(win: Win, big_w: u32, words: &[u64]) {
148 let bits = image_bits(win, big_w);
149 match win.root {
150 Root::Mem(addr) => {
151 let bytes =
153 unsafe { std::slice::from_raw_parts_mut(addr as *mut u8, bits.div_ceil(8)) };
154 for (i, b) in bytes.iter_mut().enumerate() {
155 *b = (words[i / 8] >> (8 * (i % 8))) as u8;
156 }
157 }
158 Root::Field(h, slot) => {
159 objects::field_set(h, slot, words);
160 }
161 }
162}
163
164pub fn get_part(id: u64, lo: u64, w: u32, big_w: u32, out: &mut [u64]) -> bool {
169 let Some(win) = lookup(id) else { return false };
170 let Some(img) = load(win, big_w) else {
171 return false;
172 };
173 out.fill(0);
174 for k in 0..w as usize {
175 let i = lo as usize + k;
176 if i < big_w as usize {
177 set_bit(out, k, bit_at(&img, i));
178 if !win.two_state {
179 set_bit(out, w as usize + k, bit_at(&img, big_w as usize + i));
180 }
181 }
182 }
183 true
184}
185
186pub fn put_part(id: u64, lo: u64, w: u32, big_w: u32, val: &[u64]) {
189 let Some(win) = lookup(id) else { return };
190 let Some(mut img) = load(win, big_w) else {
191 return;
192 };
193 for k in 0..w as usize {
194 let i = lo as usize + k;
195 if i < big_w as usize {
196 set_bit(&mut img, i, bit_at(val, k));
197 if !win.two_state {
198 set_bit(&mut img, big_w as usize + i, bit_at(val, w as usize + k));
199 }
200 }
201 }
202 store(win, big_w, &img);
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn a_window_reads_and_writes_only_its_bits() {
211 let mut img: u32 = 0xABCD;
213 let id = unsafe { open_mem(&mut img as *mut u32 as usize, false) };
215 assert!(is_window(id));
216 let mut out = [0u64; 1];
217 assert!(get_part(id, 4, 8, 16, &mut out));
218 assert_eq!(out[0], 0xBC);
219 put_part(id, 4, 8, 16, &[0x5A]);
220 close(id);
221 assert_eq!(img, 0xA5AD);
222 assert!(!get_part(id, 0, 8, 16, &mut out));
223 }
224}