1use crate::raw_sequence::RawSequence;
2use crate::raw_stack::RawStack;
3use anyhow::Result;
4use std::cmp::max;
5
6type Operation = fn(&RawSequence, usize, &mut RawStack) -> Result<usize>;
7
8pub struct RawSegment {
13 ops: Vec<Operation>,
14 storage: RawSequence,
15 dropper: Vec<fn(&mut RawSequence, usize) -> usize>,
16 base_alignment: usize,
17 frame: Option<(usize, usize)>,
18}
19
20impl Default for RawSegment {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl RawSegment {
27 #[must_use]
29 pub fn new() -> Self {
30 RawSegment {
31 ops: Vec::new(),
32 storage: RawSequence::new(),
33 dropper: Vec::new(),
34 base_alignment: 0,
35 frame: None,
36 }
37 }
38
39 pub(crate) fn base_alignment(&self) -> usize {
41 self.base_alignment
42 }
43
44 pub(crate) fn update_base_alignment(&mut self, alignment: usize) {
46 debug_assert!(alignment.is_power_of_two());
47 self.base_alignment = max(self.base_alignment, alignment);
48 }
49
50 pub(crate) fn set_frame(&mut self, origin: usize, owned_inputs: usize) {
52 self.frame = Some((origin, owned_inputs));
53 }
54
55 pub(crate) fn bind_frame(&mut self, origin: usize, owned_inputs: usize) {
57 self.frame.get_or_insert((origin, owned_inputs));
58 }
59
60 #[cfg(test)]
62 pub(crate) fn storage_size(&self) -> usize {
63 self.storage.len()
64 }
65
66 fn push_storage<T>(&mut self, value: T)
68 where
69 T: 'static,
70 {
71 self.storage.push(value);
72 self.dropper
73 .push(|storage, p| unsafe { storage.drop_in_place::<T>(p) });
74 }
75
76 pub fn raw0_<F>(&mut self, op: F)
78 where
79 F: Fn(&mut RawStack) -> Result<()> + 'static,
80 {
81 self.push_storage(op);
82 self.ops.push(|storage, p, stack| {
83 let (f, r) = unsafe { storage.next::<F>(p) };
84 f(stack)?;
85 Ok(r)
86 });
87 }
88
89 pub fn raw0<R, F>(&mut self, op: F)
91 where
92 F: Fn(&mut RawStack) -> Result<R> + 'static,
93 R: 'static,
94 {
95 self.push_storage(op);
96 self.ops.push(|storage, p, stack| {
97 let (f, r) = unsafe { storage.next::<F>(p) };
98 let result = f(stack)?;
99 stack.push(result);
100 Ok(r)
101 });
102 self.base_alignment = max(self.base_alignment, align_of::<R>());
103 }
104
105 pub fn push_op0<R, F>(&mut self, op: F)
107 where
108 F: Fn() -> R + 'static,
109 R: 'static,
110 {
111 self.push_storage(op);
112 self.ops.push(|storage, p, stack| {
113 let (f, r) = unsafe { storage.next::<F>(p) };
114 stack.push(f());
115 Ok(r)
116 });
117 self.base_alignment = max(self.base_alignment, align_of::<R>());
118 }
119
120 fn push_op1_<const PADDING0: bool, T, R, F>(&mut self)
122 where
123 F: Fn(T) -> R + 'static,
124 T: 'static,
125 R: 'static,
126 {
127 self.ops.push(|storage, p, stack| {
128 let (f, r) = unsafe { storage.next::<F>(p) };
129 let x: T = unsafe { stack.pop(PADDING0) };
130 stack.push(f(x));
131 Ok(r)
132 });
133 }
134
135 fn push_op1r_<const PADDING0: bool, T, R, F>(&mut self)
137 where
138 F: Fn(&mut RawStack, T) -> Result<R> + 'static,
139 T: 'static,
140 R: 'static,
141 {
142 self.ops.push(|storage, p, stack| {
143 let (f, r) = unsafe { storage.next::<F>(p) };
144 let x: T = unsafe { stack.pop(PADDING0) };
145 let result = f(stack, x)?;
146 stack.push(result);
147 Ok(r)
148 });
149 }
150
151 pub fn push_op1<T, R, F>(&mut self, op: F, padding0: bool)
153 where
154 F: Fn(T) -> R + 'static,
155 T: 'static,
156 R: 'static,
157 {
158 self.push_storage(op);
159 if padding0 {
160 self.push_op1_::<true, T, R, F>();
161 } else {
162 self.push_op1_::<false, T, R, F>();
163 }
164 self.base_alignment = max(self.base_alignment, align_of::<R>());
165 }
166
167 pub fn raw1<T, R, F>(&mut self, op: F, padding0: bool)
169 where
170 F: Fn(&mut RawStack, T) -> Result<R> + 'static,
171 T: 'static,
172 R: 'static,
173 {
174 self.push_storage(op);
175 if padding0 {
176 self.push_op1r_::<true, T, R, F>();
177 } else {
178 self.push_op1r_::<false, T, R, F>();
179 }
180 self.base_alignment = max(self.base_alignment, align_of::<R>());
181 }
182
183 fn drop1_<const PADDING0: bool, T, F>(&mut self)
185 where
186 F: Fn(T) + 'static,
187 T: 'static,
188 {
189 self.ops.push(|storage, p, stack| {
190 let (f, r) = unsafe { storage.next::<F>(p) };
191 let x: T = unsafe { stack.pop(PADDING0) };
192 f(x); Ok(r)
194 });
195 }
196
197 pub fn drop1<T, F>(&mut self, op: F, padding0: bool)
199 where
200 F: Fn(T) + 'static,
201 T: 'static,
202 {
203 self.push_storage(op);
204 if padding0 {
205 self.drop1_::<true, T, F>();
206 } else {
207 self.drop1_::<false, T, F>();
208 }
209 }
210
211 fn push_op2_<const PADDING0: bool, const PADDING1: bool, T, U, R, F>(&mut self)
213 where
214 F: Fn(T, U) -> R + 'static,
215 T: 'static,
216 U: 'static,
217 R: 'static,
218 {
219 self.ops.push(|storage, p, stack| {
220 let (f, r) = unsafe { storage.next::<F>(p) };
221 let y: U = unsafe { stack.pop(PADDING1) };
222 let x: T = unsafe { stack.pop(PADDING0) };
223 stack.push(f(x, y));
224 Ok(r)
225 });
226 }
227
228 pub fn push_op2<T, U, R, F>(&mut self, op: F, padding0: bool, padding1: bool)
231 where
232 F: Fn(T, U) -> R + 'static,
233 T: 'static,
234 U: 'static,
235 R: 'static,
236 {
237 self.push_storage(op);
238 match (padding0, padding1) {
239 (false, false) => self.push_op2_::<false, false, T, U, R, F>(),
240 (false, true) => self.push_op2_::<false, true, T, U, R, F>(),
241 (true, false) => self.push_op2_::<true, false, T, U, R, F>(),
242 (true, true) => self.push_op2_::<true, true, T, U, R, F>(),
243 }
244 self.base_alignment = max(self.base_alignment, align_of::<R>());
245 }
246
247 fn push_op2r_<const PADDING0: bool, const PADDING1: bool, T, U, R, F>(&mut self)
249 where
250 F: Fn(&mut RawStack, T, U) -> Result<R> + 'static,
251 T: 'static,
252 U: 'static,
253 R: 'static,
254 {
255 self.ops.push(|storage, p, stack| {
256 let (f, r) = unsafe { storage.next::<F>(p) };
257 let y: U = unsafe { stack.pop(PADDING1) };
258 let x: T = unsafe { stack.pop(PADDING0) };
259 let result = f(stack, x, y)?;
260 stack.push(result);
261 Ok(r)
262 });
263 }
264
265 pub fn raw2<T, U, R, F>(&mut self, op: F, padding0: bool, padding1: bool)
267 where
268 F: Fn(&mut RawStack, T, U) -> Result<R> + 'static,
269 T: 'static,
270 U: 'static,
271 R: 'static,
272 {
273 self.push_storage(op);
274 match (padding0, padding1) {
275 (false, false) => self.push_op2r_::<false, false, T, U, R, F>(),
276 (false, true) => self.push_op2r_::<false, true, T, U, R, F>(),
277 (true, false) => self.push_op2r_::<true, false, T, U, R, F>(),
278 (true, true) => self.push_op2r_::<true, true, T, U, R, F>(),
279 }
280 self.base_alignment = max(self.base_alignment, align_of::<R>());
281 }
282
283 #[expect(clippy::many_single_char_names, reason = "patterned code")]
286 fn push_op3_<const PADDING0: bool, const PADDING1: bool, const PADDING2: bool, T, U, V, R, F>(
287 &mut self,
288 ) where
289 F: Fn(T, U, V) -> R + 'static,
290 T: 'static,
291 U: 'static,
292 V: 'static,
293 R: 'static,
294 {
295 self.ops.push(|storage, p, stack| {
296 let (f, r) = unsafe { storage.next::<F>(p) };
297 let z: V = unsafe { stack.pop(PADDING2) };
298 let y: U = unsafe { stack.pop(PADDING1) };
299 let x: T = unsafe { stack.pop(PADDING0) };
300 stack.push(f(x, y, z));
301 Ok(r)
302 });
303 }
304
305 pub fn push_op3<T, U, V, R, F>(&mut self, op: F, padding0: bool, padding1: bool, padding2: bool)
307 where
308 F: Fn(T, U, V) -> R + 'static,
309 T: 'static,
310 U: 'static,
311 V: 'static,
312 R: 'static,
313 {
314 self.push_storage(op);
315
316 match (padding0, padding1, padding2) {
317 (false, false, false) => self.push_op3_::<false, false, false, T, U, V, R, F>(),
318 (false, false, true) => self.push_op3_::<false, false, true, T, U, V, R, F>(),
319 (false, true, false) => self.push_op3_::<false, true, false, T, U, V, R, F>(),
320 (false, true, true) => self.push_op3_::<false, true, true, T, U, V, R, F>(),
321 (true, false, false) => self.push_op3_::<true, false, false, T, U, V, R, F>(),
322 (true, false, true) => self.push_op3_::<true, false, true, T, U, V, R, F>(),
323 (true, true, false) => self.push_op3_::<true, true, false, T, U, V, R, F>(),
324 (true, true, true) => self.push_op3_::<true, true, true, T, U, V, R, F>(),
325 }
326 self.base_alignment = max(self.base_alignment, align_of::<R>());
327 }
328
329 #[expect(clippy::many_single_char_names, reason = "patterned code")]
331 fn push_op3r_<const PADDING0: bool, const PADDING1: bool, const PADDING2: bool, T, U, V, R, F>(
332 &mut self,
333 ) where
334 F: Fn(&mut RawStack, T, U, V) -> Result<R> + 'static,
335 T: 'static,
336 U: 'static,
337 V: 'static,
338 R: 'static,
339 {
340 self.ops.push(|storage, p, stack| {
341 let (f, r) = unsafe { storage.next::<F>(p) };
342 let z: V = unsafe { stack.pop(PADDING2) };
343 let y: U = unsafe { stack.pop(PADDING1) };
344 let x: T = unsafe { stack.pop(PADDING0) };
345 let result = f(stack, x, y, z)?;
346 stack.push(result);
347 Ok(r)
348 });
349 }
350
351 pub fn raw3<T, U, V, R, F>(&mut self, op: F, padding0: bool, padding1: bool, padding2: bool)
353 where
354 F: Fn(&mut RawStack, T, U, V) -> Result<R> + 'static,
355 T: 'static,
356 U: 'static,
357 V: 'static,
358 R: 'static,
359 {
360 self.push_storage(op);
361 match (padding0, padding1, padding2) {
362 (false, false, false) => self.push_op3r_::<false, false, false, T, U, V, R, F>(),
363 (false, false, true) => self.push_op3r_::<false, false, true, T, U, V, R, F>(),
364 (false, true, false) => self.push_op3r_::<false, true, false, T, U, V, R, F>(),
365 (false, true, true) => self.push_op3r_::<false, true, true, T, U, V, R, F>(),
366 (true, false, false) => self.push_op3r_::<true, false, false, T, U, V, R, F>(),
367 (true, false, true) => self.push_op3r_::<true, false, true, T, U, V, R, F>(),
368 (true, true, false) => self.push_op3r_::<true, true, false, T, U, V, R, F>(),
369 (true, true, true) => self.push_op3r_::<true, true, true, T, U, V, R, F>(),
370 }
371 self.base_alignment = max(self.base_alignment, align_of::<R>());
372 }
373
374 pub unsafe fn call0_stack(&self, stack: &mut RawStack) -> Result<()> {
384 let (origin, depth) = self.frame.map_or((0, 0), |(origin, inputs)| {
385 (
386 origin,
387 stack
388 .depth()
389 .checked_sub(inputs)
390 .expect("valid input frame"),
391 )
392 });
393 stack.with_unwind(origin, depth, |stack| {
394 let mut p = 0;
395 for op in &self.ops {
396 p = op(&self.storage, p, stack)?;
397 }
398 Ok(())
399 })
400 }
401
402 pub unsafe fn call0<T>(&self) -> Result<T>
411 where
412 T: 'static,
413 {
414 let mut stack = RawStack::with_base_alignment(self.base_alignment);
415 unsafe {
416 self.call0_stack(&mut stack)?;
417 }
418 Ok(unsafe { stack.pop(false) })
419 }
420
421 pub unsafe fn call1<A: 'static, T>(&self, arg: A) -> Result<T>
431 where
432 T: 'static,
433 {
434 let mut stack = RawStack::with_base_alignment(self.base_alignment);
435 stack.push(arg);
436 unsafe { self.call0_stack(&mut stack)? };
437 Ok(unsafe { stack.pop(false) })
438 }
439
440 pub unsafe fn call2<A: 'static, B: 'static, T>(&self, arg: (A, B)) -> Result<T>
450 where
451 T: 'static,
452 {
453 let mut stack = RawStack::with_base_alignment(self.base_alignment);
454 stack.push(arg.0);
455 stack.push(arg.1);
456 unsafe { self.call0_stack(&mut stack)? };
457 Ok(unsafe { stack.pop(false) })
458 }
459}
460
461impl Drop for RawSegment {
462 fn drop(&mut self) {
463 let mut p = 0;
464 for e in &self.dropper {
465 p = e(&mut self.storage, p);
466 }
467 }
468}
469
470#[cfg(test)]
471mod tests {
472 use super::*;
473
474 #[test]
475 fn nullary_operation() {
476 let mut segment = RawSegment::new();
477 segment.push_op0(|| 42);
478 unsafe {
479 assert_eq!(segment.call0::<i32>().unwrap(), 42);
480 }
481 }
482
483 #[test]
484 fn unary_operation() {
485 let mut segment = RawSegment::new();
486 segment.push_op0(|| 42);
487 segment.push_op1(|x: i32| x * 2, false);
488 unsafe {
489 assert_eq!(segment.call0::<i32>().unwrap(), 84);
490 }
491 }
492
493 #[test]
494 fn binary_operation() {
495 let mut segment = RawSegment::new();
496 segment.push_op0(|| 10);
497 segment.push_op0(|| 5);
498 segment.push_op2(|x: i32, y: i32| x + y, false, false);
499 unsafe {
500 assert_eq!(segment.call0::<i32>().unwrap(), 15);
501 }
502 }
503
504 #[test]
505 fn ternary_operation() {
506 let mut segment = RawSegment::new();
507 segment.push_op0(|| 2);
508 segment.push_op0(|| 3);
509 segment.push_op0(|| 4);
510 segment.push_op3(|x: i32, y: i32, z: i32| x + y + z, false, false, false);
511 unsafe {
512 assert_eq!(segment.call0::<i32>().unwrap(), 9);
513 }
514 }
515
516 #[test]
517 fn complex_chain() {
518 let mut segment = RawSegment::new();
519 segment.push_op0(|| 10);
520 segment.push_op1(|x: i32| x * 2, false);
521 segment.push_op0(|| 5);
522 segment.push_op2(|x: i32, y: i32| x + y, false, false);
523 unsafe {
524 assert_eq!(segment.call0::<i32>().unwrap(), 25);
525 }
526 }
527}