1use crate::{Finalize, pointer_alignment_padding, type_hash::TypeHash};
33use smallvec::SmallVec;
34use std::{
35 alloc::Layout,
36 collections::{HashMap, hash_map::Entry},
37 ops::Range,
38};
39
40#[derive(Debug, Copy, Clone)]
42struct DataStackFinalizer {
43 callback: unsafe fn(*mut ()),
44 layout: Layout,
45}
46
47#[derive(Debug, Copy, Clone)]
53struct DataStackRegisterTag {
54 type_hash: TypeHash,
55 layout: Layout,
56 finalizer: Option<unsafe fn(*mut ())>,
57 padding: u8,
58}
59
60pub struct DataStackToken(usize);
66
67impl DataStackToken {
68 pub unsafe fn new(position: usize) -> Self {
76 Self(position)
77 }
78}
79
80pub struct DataStackRegisterAccess<'a> {
86 stack: &'a mut DataStack,
87 position: usize,
88}
89
90impl<'a> DataStackRegisterAccess<'a> {
91 pub fn type_hash(&self) -> TypeHash {
93 unsafe {
94 self.stack
95 .memory
96 .as_ptr()
97 .add(self.position)
98 .cast::<DataStackRegisterTag>()
99 .read_unaligned()
100 .type_hash
101 }
102 }
103
104 pub fn layout(&self) -> Layout {
106 unsafe {
107 self.stack
108 .memory
109 .as_ptr()
110 .add(self.position)
111 .cast::<DataStackRegisterTag>()
112 .read_unaligned()
113 .layout
114 }
115 }
116
117 pub fn type_hash_layout(&self) -> (TypeHash, Layout) {
119 unsafe {
120 let tag = self
121 .stack
122 .memory
123 .as_ptr()
124 .add(self.position)
125 .cast::<DataStackRegisterTag>()
126 .read_unaligned();
127 (tag.type_hash, tag.layout)
128 }
129 }
130
131 pub fn has_value(&self) -> bool {
133 unsafe {
134 self.stack
135 .memory
136 .as_ptr()
137 .add(self.position)
138 .cast::<DataStackRegisterTag>()
139 .read_unaligned()
140 .finalizer
141 .is_some()
142 }
143 }
144
145 pub fn read<T: 'static>(&'a self) -> Option<&'a T> {
148 unsafe {
149 let tag = self
150 .stack
151 .memory
152 .as_ptr()
153 .add(self.position)
154 .cast::<DataStackRegisterTag>()
155 .read_unaligned();
156 if tag.type_hash == TypeHash::of::<T>() && tag.finalizer.is_some() {
157 self.stack
158 .memory
159 .as_ptr()
160 .add(self.position - tag.layout.size())
161 .cast::<T>()
162 .as_ref()
163 } else {
164 None
165 }
166 }
167 }
168
169 pub fn write<T: 'static>(&'a mut self) -> Option<&'a mut T> {
172 unsafe {
173 let tag = self
174 .stack
175 .memory
176 .as_ptr()
177 .add(self.position)
178 .cast::<DataStackRegisterTag>()
179 .read_unaligned();
180 if tag.type_hash == TypeHash::of::<T>() && tag.finalizer.is_some() {
181 self.stack
182 .memory
183 .as_mut_ptr()
184 .add(self.position - tag.layout.size())
185 .cast::<T>()
186 .as_mut()
187 } else {
188 None
189 }
190 }
191 }
192
193 pub fn take<T: 'static>(&mut self) -> Option<T> {
197 unsafe {
198 let mut tag = self
199 .stack
200 .memory
201 .as_ptr()
202 .add(self.position)
203 .cast::<DataStackRegisterTag>()
204 .read_unaligned();
205 if tag.type_hash == TypeHash::of::<T>() && tag.finalizer.is_some() {
206 tag.finalizer = None;
207 self.stack
208 .memory
209 .as_mut_ptr()
210 .add(self.position)
211 .cast::<DataStackRegisterTag>()
212 .write_unaligned(tag);
213 Some(
214 self.stack
215 .memory
216 .as_ptr()
217 .add(self.position - tag.layout.size())
218 .cast::<T>()
219 .read_unaligned(),
220 )
221 } else {
222 None
223 }
224 }
225 }
226
227 pub fn free(&mut self) -> bool {
231 unsafe {
232 let mut tag = self
233 .stack
234 .memory
235 .as_ptr()
236 .add(self.position)
237 .cast::<DataStackRegisterTag>()
238 .read_unaligned();
239 if let Some(finalizer) = tag.finalizer {
240 (finalizer)(
241 self.stack
242 .memory
243 .as_mut_ptr()
244 .add(self.position - tag.layout.size())
245 .cast::<()>(),
246 );
247 tag.finalizer = None;
248 self.stack
249 .memory
250 .as_mut_ptr()
251 .add(self.position)
252 .cast::<DataStackRegisterTag>()
253 .write_unaligned(tag);
254 true
255 } else {
256 false
257 }
258 }
259 }
260
261 pub fn set<T: Finalize + 'static>(&mut self, value: T) {
265 unsafe {
266 let mut tag = self
267 .stack
268 .memory
269 .as_ptr()
270 .add(self.position)
271 .cast::<DataStackRegisterTag>()
272 .read_unaligned();
273 if tag.type_hash == TypeHash::of::<T>() {
274 if let Some(finalizer) = tag.finalizer {
275 (finalizer)(
276 self.stack
277 .memory
278 .as_mut_ptr()
279 .add(self.position - tag.layout.size())
280 .cast::<()>(),
281 );
282 } else {
283 tag.finalizer = Some(T::finalize_raw);
284 }
285 self.stack
286 .memory
287 .as_mut_ptr()
288 .add(self.position - tag.layout.size())
289 .cast::<T>()
290 .write_unaligned(value);
291 self.stack
292 .memory
293 .as_mut_ptr()
294 .add(self.position)
295 .cast::<DataStackRegisterTag>()
296 .write_unaligned(tag);
297 }
298 }
299 }
300
301 pub fn move_to(&mut self, other: &mut Self) {
306 if self.position == other.position {
307 return;
308 }
309 unsafe {
310 let mut tag = self
311 .stack
312 .memory
313 .as_ptr()
314 .add(self.position)
315 .cast::<DataStackRegisterTag>()
316 .read_unaligned();
317 let other_tag = other
318 .stack
319 .memory
320 .as_ptr()
321 .add(self.position)
322 .cast::<DataStackRegisterTag>()
323 .read_unaligned();
324 if tag.type_hash == other_tag.type_hash && tag.layout == other_tag.layout {
325 if let Some(finalizer) = other_tag.finalizer {
326 (finalizer)(
327 self.stack
328 .memory
329 .as_mut_ptr()
330 .add(other.position - other_tag.layout.size())
331 .cast::<()>(),
332 );
333 }
334 tag.finalizer = None;
335 let source = self
336 .stack
337 .memory
338 .as_ptr()
339 .add(self.position - tag.layout.size());
340 let target = self
341 .stack
342 .memory
343 .as_mut_ptr()
344 .add(other.position - other_tag.layout.size());
345 target.copy_from(source, tag.layout.size());
346 self.stack
347 .memory
348 .as_mut_ptr()
349 .add(self.position)
350 .cast::<DataStackRegisterTag>()
351 .write_unaligned(tag);
352 }
353 }
354 }
355}
356
357#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
362pub enum DataStackMode {
363 Values,
365 Registers,
367 #[default]
368 Mixed,
370}
371
372impl DataStackMode {
373 pub fn allows_values(self) -> bool {
375 matches!(self, Self::Values | Self::Mixed)
376 }
377
378 pub fn allows_registers(self) -> bool {
380 matches!(self, Self::Registers | Self::Mixed)
381 }
382}
383
384pub enum DataStackVisitedItem<'a> {
389 Value {
391 type_hash: TypeHash,
392 layout: Layout,
393 data: &'a [u8],
394 range: Range<usize>,
395 },
396 Register {
398 type_hash: TypeHash,
399 layout: Layout,
400 data: &'a [u8],
401 range: Range<usize>,
402 valid: bool,
403 },
404}
405
406pub struct DataStack {
413 memory: Vec<u8>,
414 position: usize,
415 mode: DataStackMode,
416 finalizers: HashMap<TypeHash, DataStackFinalizer>,
417 registers: Vec<usize>,
418 drop: bool,
419}
420
421impl Drop for DataStack {
422 fn drop(&mut self) {
423 if self.drop {
424 self.restore(DataStackToken(0));
425 }
426 }
427}
428
429impl DataStack {
430 pub fn new(mut capacity: usize, mode: DataStackMode) -> Self {
433 capacity = capacity.next_power_of_two();
434 Self {
435 memory: vec![0; capacity],
436 position: 0,
437 mode,
438 finalizers: Default::default(),
439 registers: vec![],
440 drop: true,
441 }
442 }
443
444 pub fn position(&self) -> usize {
446 self.position
447 }
448
449 pub fn size(&self) -> usize {
451 self.memory.len()
452 }
453
454 pub fn available(&self) -> usize {
456 self.size().saturating_sub(self.position)
457 }
458
459 pub fn as_bytes(&self) -> &[u8] {
461 &self.memory[0..self.position]
462 }
463
464 pub fn visit(&self, mut f: impl FnMut(DataStackVisitedItem) -> bool) {
468 let type_layout = Layout::new::<TypeHash>().pad_to_align();
469 let tag_layout = Layout::new::<DataStackRegisterTag>().pad_to_align();
470 let mut position = self.position;
471 while position > 0 {
472 if position < type_layout.size() {
473 return;
474 }
475 position -= type_layout.size();
476 let type_hash = unsafe {
477 self.memory
478 .as_ptr()
479 .add(position)
480 .cast::<TypeHash>()
481 .read_unaligned()
482 };
483 if type_hash == TypeHash::of::<DataStackRegisterTag>() {
484 if position < tag_layout.size() {
485 return;
486 }
487 position -= tag_layout.size();
488 let tag = unsafe {
489 self.memory
490 .as_ptr()
491 .add(position)
492 .cast::<DataStackRegisterTag>()
493 .read_unaligned()
494 };
495 if position < tag.layout.size() {
496 return;
497 }
498 position -= tag.layout.size();
499 let range = position..(position + tag.layout.size());
500 let status = f(DataStackVisitedItem::Register {
501 type_hash: tag.type_hash,
502 layout: tag.layout,
503 data: &self.memory[range.clone()],
504 range,
505 valid: tag.finalizer.is_some(),
506 });
507 if !status {
508 return;
509 }
510 position -= tag.padding as usize;
511 } else if let Some(finalizer) = self.finalizers.get(&type_hash) {
512 if position < finalizer.layout.size() {
513 return;
514 }
515 position -= finalizer.layout.size();
516 let range = position..(position + finalizer.layout.size());
517 let status = f(DataStackVisitedItem::Value {
518 type_hash,
519 layout: finalizer.layout,
520 data: &self.memory[range.clone()],
521 range,
522 });
523 if !status {
524 return;
525 }
526 }
527 }
528 }
529
530 pub fn push<T: Finalize + Sized + 'static>(&mut self, value: T) -> bool {
535 if !self.mode.allows_values() {
536 return false;
537 }
538 let value_layout = Layout::new::<T>().pad_to_align();
539 let type_layout = Layout::new::<TypeHash>().pad_to_align();
540 if self.position + value_layout.size() + type_layout.size() > self.size() {
541 return false;
542 }
543 let type_hash = TypeHash::of::<T>();
544 self.finalizers
545 .entry(type_hash)
546 .or_insert(DataStackFinalizer {
547 callback: T::finalize_raw,
548 layout: value_layout,
549 });
550 unsafe {
551 self.memory
552 .as_mut_ptr()
553 .add(self.position)
554 .cast::<T>()
555 .write_unaligned(value);
556 self.position += value_layout.size();
557 self.memory
558 .as_mut_ptr()
559 .add(self.position)
560 .cast::<TypeHash>()
561 .write_unaligned(type_hash);
562 self.position += type_layout.size();
563 }
564 true
565 }
566
567 pub unsafe fn push_raw(
576 &mut self,
577 layout: Layout,
578 type_hash: TypeHash,
579 finalizer: unsafe fn(*mut ()),
580 data: &[u8],
581 ) -> bool {
582 if !self.mode.allows_values() {
583 return false;
584 }
585 let value_layout = layout.pad_to_align();
586 let type_layout = Layout::new::<TypeHash>().pad_to_align();
587 if data.len() != value_layout.size()
588 && self.position + value_layout.size() + type_layout.size() > self.size()
589 {
590 return false;
591 }
592 self.finalizers
593 .entry(type_hash)
594 .or_insert(DataStackFinalizer {
595 callback: finalizer,
596 layout: value_layout,
597 });
598 self.memory[self.position..(self.position + value_layout.size())].copy_from_slice(data);
599 self.position += value_layout.size();
600 unsafe {
601 self.memory
602 .as_mut_ptr()
603 .add(self.position)
604 .cast::<TypeHash>()
605 .write_unaligned(type_hash)
606 };
607 self.position += type_layout.size();
608 true
609 }
610
611 pub fn push_register<T: Finalize + 'static>(&mut self) -> Option<usize> {
613 unsafe { self.push_register_raw(TypeHash::of::<T>(), Layout::new::<T>().pad_to_align()) }
614 }
615
616 pub fn push_register_value<T: Finalize + 'static>(&mut self, value: T) -> Option<usize> {
619 let result = self.push_register::<T>()?;
620 let mut access = self.access_register(result)?;
621 access.set(value);
622 Some(result)
623 }
624
625 pub unsafe fn push_register_raw(
633 &mut self,
634 type_hash: TypeHash,
635 value_layout: Layout,
636 ) -> Option<usize> {
637 if !self.mode.allows_registers() {
638 return None;
639 }
640 let tag_layout = Layout::new::<DataStackRegisterTag>().pad_to_align();
641 let type_layout = Layout::new::<TypeHash>().pad_to_align();
642 let padding = unsafe { self.alignment_padding(value_layout.align()) };
643 if self.position + padding + value_layout.size() + tag_layout.size() + type_layout.size()
644 > self.size()
645 {
646 return None;
647 }
648 unsafe {
649 self.position += padding + value_layout.size();
650 let position = self.position;
651 self.memory
652 .as_mut_ptr()
653 .add(self.position)
654 .cast::<DataStackRegisterTag>()
655 .write_unaligned(DataStackRegisterTag {
656 type_hash,
657 layout: value_layout,
658 finalizer: None,
659 padding: padding as u8,
660 });
661 self.position += tag_layout.size();
662 self.memory
663 .as_mut_ptr()
664 .add(self.position)
665 .cast::<TypeHash>()
666 .write_unaligned(TypeHash::of::<DataStackRegisterTag>());
667 self.position += type_layout.size();
668 self.registers.push(position);
669 Some(self.registers.len() - 1)
670 }
671 }
672
673 pub fn push_stack(&mut self, mut other: Self) -> Result<(), Self> {
678 if self.available() < other.position {
679 return Err(other);
680 }
681 self.memory[self.position..(self.position + other.position)]
682 .copy_from_slice(&other.memory[0..other.position]);
683 self.position += other.position;
684 self.finalizers
685 .extend(other.finalizers.iter().map(|(key, value)| {
686 (
687 *key,
688 DataStackFinalizer {
689 callback: value.callback,
690 layout: value.layout,
691 },
692 )
693 }));
694 unsafe { other.prevent_drop() };
695 Ok(())
696 }
697
698 pub fn push_from_register(&mut self, register: &mut DataStackRegisterAccess) -> bool {
702 if !self.mode.allows_values() {
703 return false;
704 }
705 let type_layout = Layout::new::<TypeHash>().pad_to_align();
706 let mut tag = unsafe {
707 register
708 .stack
709 .memory
710 .as_ptr()
711 .add(register.position)
712 .cast::<DataStackRegisterTag>()
713 .read_unaligned()
714 };
715 if self.position + tag.layout.size() + type_layout.size() > self.size() {
716 return false;
717 }
718 if let Entry::Vacant(e) = self.finalizers.entry(tag.type_hash)
719 && let Some(finalizer) = tag.finalizer
720 {
721 e.insert(DataStackFinalizer {
722 callback: finalizer,
723 layout: tag.layout,
724 });
725 }
726 tag.finalizer = None;
727 unsafe {
728 let source = register
729 .stack
730 .memory
731 .as_ptr()
732 .add(register.position - tag.layout.size());
733 let target = self.memory.as_mut_ptr().add(self.position);
734 target.copy_from(source, tag.layout.size());
735 self.position += tag.layout.size();
736 self.memory
737 .as_mut_ptr()
738 .add(self.position)
739 .cast::<TypeHash>()
740 .write_unaligned(tag.type_hash);
741 self.position += type_layout.size();
742 register
743 .stack
744 .memory
745 .as_mut_ptr()
746 .add(register.position)
747 .cast::<DataStackRegisterTag>()
748 .write_unaligned(tag);
749 }
750 true
751 }
752
753 pub fn pop<T: Sized + 'static>(&mut self) -> Option<T> {
758 if !self.mode.allows_values() {
759 return None;
760 }
761 let type_layout = Layout::new::<TypeHash>().pad_to_align();
762 let value_layout = Layout::new::<T>().pad_to_align();
763 if self.position < type_layout.size() + value_layout.size() {
764 return None;
765 }
766 let type_hash = unsafe {
767 self.memory
768 .as_mut_ptr()
769 .add(self.position - type_layout.size())
770 .cast::<TypeHash>()
771 .read_unaligned()
772 };
773 if type_hash != TypeHash::of::<T>() || type_hash == TypeHash::of::<DataStackRegisterTag>() {
774 return None;
775 }
776 self.position -= type_layout.size();
777 let result = unsafe {
778 self.memory
779 .as_ptr()
780 .add(self.position - value_layout.size())
781 .cast::<T>()
782 .read_unaligned()
783 };
784 self.position -= value_layout.size();
785 Some(result)
786 }
787
788 #[allow(clippy::type_complexity)]
797 pub unsafe fn pop_raw(&mut self) -> Option<(Layout, TypeHash, unsafe fn(*mut ()), Vec<u8>)> {
798 if !self.mode.allows_values() {
799 return None;
800 }
801 let type_layout = Layout::new::<TypeHash>().pad_to_align();
802 if self.position < type_layout.size() {
803 return None;
804 }
805 let type_hash = unsafe {
806 self.memory
807 .as_mut_ptr()
808 .add(self.position - type_layout.size())
809 .cast::<TypeHash>()
810 .read_unaligned()
811 };
812 if type_hash == TypeHash::of::<DataStackRegisterTag>() {
813 return None;
814 }
815 let finalizer = self.finalizers.get(&type_hash)?;
816 if self.position < type_layout.size() + finalizer.layout.size() {
817 return None;
818 }
819 self.position -= type_layout.size();
820 let data = self.memory[(self.position - finalizer.layout.size())..self.position].to_vec();
821 self.position -= finalizer.layout.size();
822 Some((finalizer.layout, type_hash, finalizer.callback, data))
823 }
824
825 pub fn drop(&mut self) -> bool {
829 if !self.mode.allows_values() {
830 return false;
831 }
832 let type_layout = Layout::new::<TypeHash>().pad_to_align();
833 self.position -= type_layout.size();
834 let type_hash = unsafe {
835 self.memory
836 .as_ptr()
837 .add(self.position)
838 .cast::<TypeHash>()
839 .read_unaligned()
840 };
841 if type_hash == TypeHash::of::<DataStackRegisterTag>() {
842 return false;
843 }
844 if let Some(finalizer) = self.finalizers.get(&type_hash) {
845 self.position -= finalizer.layout.size();
846 unsafe {
847 (finalizer.callback)(self.memory.as_mut_ptr().add(self.position).cast::<()>());
848 }
849 }
850 true
851 }
852
853 pub fn drop_register(&mut self) -> bool {
857 if !self.mode.allows_registers() {
858 return false;
859 }
860 let tag_layout = Layout::new::<DataStackRegisterTag>().pad_to_align();
861 let type_layout = Layout::new::<TypeHash>().pad_to_align();
862 unsafe {
863 let type_hash = self
864 .memory
865 .as_mut_ptr()
866 .add(self.position - type_layout.size())
867 .cast::<TypeHash>()
868 .read_unaligned();
869 if type_hash != TypeHash::of::<DataStackRegisterTag>() {
870 return false;
871 }
872 self.position -= type_layout.size();
873 self.position -= tag_layout.size();
874 let tag = self
875 .memory
876 .as_ptr()
877 .add(self.position)
878 .cast::<DataStackRegisterTag>()
879 .read_unaligned();
880 self.position -= tag.layout.size() - tag.padding as usize;
881 if let Some(finalizer) = tag.finalizer {
882 (finalizer)(self.memory.as_mut_ptr().add(self.position).cast::<()>());
883 }
884 self.registers.pop();
885 }
886 true
887 }
888
889 pub fn pop_stack(&mut self, mut data_count: usize, capacity: Option<usize>) -> Self {
895 let type_layout = Layout::new::<TypeHash>().pad_to_align();
896 let mut size = 0;
897 let mut position = self.position;
898 let mut finalizers = HashMap::new();
899 while data_count > 0 && position > 0 {
900 data_count -= 1;
901 position -= type_layout.size();
902 size += type_layout.size();
903 let type_hash = unsafe {
904 self.memory
905 .as_mut_ptr()
906 .add(position)
907 .cast::<TypeHash>()
908 .read_unaligned()
909 };
910 if let Some(finalizer) = self.finalizers.get(&type_hash) {
911 position -= finalizer.layout.size();
912 size += finalizer.layout.size();
913 finalizers.insert(
914 type_hash,
915 DataStackFinalizer {
916 callback: finalizer.callback,
917 layout: finalizer.layout,
918 },
919 );
920 }
921 }
922 let mut result = Self::new(capacity.unwrap_or(size).max(size), self.mode);
923 result.memory[0..size].copy_from_slice(&self.memory[position..self.position]);
924 result.finalizers.extend(finalizers);
925 self.position = position;
926 result.position = size;
927 result
928 }
929
930 pub fn pop_to_register(&mut self, register: &mut DataStackRegisterAccess) -> bool {
935 if !self.mode.allows_values() {
936 return false;
937 }
938 let type_layout = Layout::new::<TypeHash>().pad_to_align();
939 if self.position < type_layout.size() {
940 return false;
941 }
942 let type_hash = unsafe {
943 self.memory
944 .as_mut_ptr()
945 .add(self.position - type_layout.size())
946 .cast::<TypeHash>()
947 .read_unaligned()
948 };
949 let mut tag = unsafe {
950 register
951 .stack
952 .memory
953 .as_ptr()
954 .add(register.position)
955 .cast::<DataStackRegisterTag>()
956 .read_unaligned()
957 };
958 if type_hash != tag.type_hash || type_hash == TypeHash::of::<DataStackRegisterTag>() {
959 return false;
960 }
961 if self.position < type_layout.size() + tag.layout.size() {
962 return false;
963 }
964 let finalizer = match self.finalizers.get(&type_hash) {
965 Some(finalizer) => finalizer.callback,
966 None => return false,
967 };
968 unsafe {
969 if let Some(finalizer) = tag.finalizer {
970 (finalizer)(
971 register
972 .stack
973 .memory
974 .as_mut_ptr()
975 .add(register.position - tag.layout.size())
976 .cast::<()>(),
977 );
978 }
979 tag.finalizer = Some(finalizer);
980 let source = self
981 .memory
982 .as_ptr()
983 .add(self.position - type_layout.size() - tag.layout.size());
984 let target = register
985 .stack
986 .memory
987 .as_mut_ptr()
988 .add(register.position - tag.layout.size());
989 target.copy_from(source, tag.layout.size());
990 register
991 .stack
992 .memory
993 .as_mut_ptr()
994 .add(register.position)
995 .cast::<DataStackRegisterTag>()
996 .write_unaligned(tag);
997 }
998 self.position -= type_layout.size();
999 self.position -= tag.layout.size();
1000 true
1001 }
1002
1003 pub fn store(&self) -> DataStackToken {
1005 DataStackToken(self.position)
1006 }
1007
1008 pub fn restore(&mut self, token: DataStackToken) {
1012 let type_layout = Layout::new::<TypeHash>().pad_to_align();
1013 let tag_layout = Layout::new::<DataStackRegisterTag>().pad_to_align();
1014 let tag_type_hash = TypeHash::of::<DataStackRegisterTag>();
1015 while self.position > token.0 {
1016 self.position -= type_layout.size();
1017 let type_hash = unsafe {
1018 self.memory
1019 .as_ptr()
1020 .add(self.position)
1021 .cast::<TypeHash>()
1022 .read_unaligned()
1023 };
1024 if type_hash == tag_type_hash {
1025 unsafe {
1026 let tag = self
1027 .memory
1028 .as_ptr()
1029 .add(self.position - tag_layout.size())
1030 .cast::<DataStackRegisterTag>()
1031 .read_unaligned();
1032 self.position -= tag_layout.size();
1033 self.position -= tag.layout.size();
1034 if let Some(finalizer) = tag.finalizer {
1035 (finalizer)(self.memory.as_mut_ptr().add(self.position).cast::<()>());
1036 }
1037 self.position -= tag.padding as usize;
1038 self.registers.pop();
1039 }
1040 } else if let Some(finalizer) = self.finalizers.get(&type_hash) {
1041 self.position -= finalizer.layout.size();
1042 unsafe {
1043 (finalizer.callback)(self.memory.as_mut_ptr().add(self.position).cast::<()>());
1044 }
1045 }
1046 }
1047 }
1048
1049 pub fn reverse(&mut self, token: DataStackToken) {
1055 let size = self.position.saturating_sub(token.0);
1056 let mut meta_data = SmallVec::<[_; 8]>::with_capacity(8);
1057 let mut meta_registers = 0;
1058 let type_layout = Layout::new::<TypeHash>().pad_to_align();
1059 let tag_layout = Layout::new::<DataStackRegisterTag>().pad_to_align();
1060 let tag_type_hash = TypeHash::of::<DataStackRegisterTag>();
1061 let mut position = self.position;
1062 while position > token.0 {
1063 position -= type_layout.size();
1064 let type_hash = unsafe {
1065 self.memory
1066 .as_mut_ptr()
1067 .add(position)
1068 .cast::<TypeHash>()
1069 .read_unaligned()
1070 };
1071 if type_hash == tag_type_hash {
1072 unsafe {
1073 let tag = self
1074 .memory
1075 .as_ptr()
1076 .add(self.position - tag_layout.size())
1077 .cast::<DataStackRegisterTag>()
1078 .read_unaligned();
1079 position -= tag_layout.size();
1080 position -= tag.layout.size();
1081 meta_data.push((
1082 position - token.0,
1083 type_layout.size() + tag_layout.size() + tag.layout.size(),
1084 ));
1085 meta_registers += 1;
1086 }
1087 } else if let Some(finalizer) = self.finalizers.get(&type_hash) {
1088 position -= finalizer.layout.size();
1089 meta_data.push((
1090 position - token.0,
1091 type_layout.size() + finalizer.layout.size(),
1092 ));
1093 }
1094 }
1095 if meta_data.len() <= 1 {
1096 return;
1097 }
1098 let mut memory = SmallVec::<[_; 256]>::new();
1099 memory.resize(size, 0);
1100 memory.copy_from_slice(&self.memory[token.0..self.position]);
1101 for (source_position, size) in meta_data {
1102 self.memory[position..(position + size)]
1103 .copy_from_slice(&memory[source_position..(source_position + size)]);
1104 position += size;
1105 }
1106 let start = self.registers.len() - meta_registers;
1107 self.registers[start..].reverse();
1108 }
1109
1110 pub fn peek(&self) -> Option<TypeHash> {
1114 if self.position == 0 {
1115 return None;
1116 }
1117 let type_layout = Layout::new::<TypeHash>().pad_to_align();
1118 Some(unsafe {
1119 self.memory
1120 .as_ptr()
1121 .add(self.position - type_layout.size())
1122 .cast::<TypeHash>()
1123 .read_unaligned()
1124 })
1125 }
1126
1127 pub fn registers_count(&self) -> usize {
1129 self.registers.len()
1130 }
1131
1132 pub fn access_register(&'_ mut self, index: usize) -> Option<DataStackRegisterAccess<'_>> {
1134 let position = *self.registers.get(index)?;
1135 Some(DataStackRegisterAccess {
1136 stack: self,
1137 position,
1138 })
1139 }
1140
1141 pub fn access_registers_pair(
1146 &'_ mut self,
1147 a: usize,
1148 b: usize,
1149 ) -> Option<(DataStackRegisterAccess<'_>, DataStackRegisterAccess<'_>)> {
1150 if a == b {
1151 return None;
1152 }
1153 let position_a = *self.registers.get(a)?;
1154 let position_b = *self.registers.get(b)?;
1155 unsafe {
1156 Some((
1157 DataStackRegisterAccess {
1158 stack: (self as *mut Self).as_mut()?,
1159 position: position_a,
1160 },
1161 DataStackRegisterAccess {
1162 stack: (self as *mut Self).as_mut()?,
1163 position: position_b,
1164 },
1165 ))
1166 }
1167 }
1168
1169 pub unsafe fn prevent_drop(&mut self) {
1176 self.drop = false;
1177 }
1178
1179 #[inline]
1187 unsafe fn alignment_padding(&self, alignment: usize) -> usize {
1188 pointer_alignment_padding(
1189 unsafe { self.memory.as_ptr().add(self.position) },
1190 alignment,
1191 )
1192 }
1193}
1194
1195pub trait DataStackPack: Sized {
1201 fn stack_push(self, stack: &mut DataStack);
1203
1204 fn stack_push_reversed(self, stack: &mut DataStack) {
1209 let token = stack.store();
1210 self.stack_push(stack);
1211 stack.reverse(token);
1212 }
1213
1214 fn stack_pop(stack: &mut DataStack) -> Self;
1220
1221 fn pack_types() -> Vec<TypeHash>;
1223}
1224
1225impl DataStackPack for () {
1226 fn stack_push(self, _: &mut DataStack) {}
1227
1228 fn stack_pop(_: &mut DataStack) -> Self {}
1229
1230 fn pack_types() -> Vec<TypeHash> {
1231 vec![]
1232 }
1233}
1234
1235macro_rules! impl_data_stack_tuple {
1237 ($($type:ident),+) => {
1238 impl<$($type: 'static),+> DataStackPack for ($($type,)+) {
1239 #[allow(non_snake_case)]
1240 fn stack_push(self, stack: &mut DataStack) {
1241 let ($( $type, )+) = self;
1242 $( stack.push($type); )+
1243 }
1244
1245 #[allow(non_snake_case)]
1246 fn stack_pop(stack: &mut DataStack) -> Self {
1247 ($(
1248 stack.pop::<$type>().unwrap_or_else(
1249 || panic!("Could not pop data of type: {}", std::any::type_name::<$type>())
1250 ),
1251 )+)
1252 }
1253
1254 #[allow(non_snake_case)]
1255 fn pack_types() -> Vec<TypeHash> {
1256 vec![ $( TypeHash::of::<$type>() ),+ ]
1257 }
1258 }
1259 };
1260}
1261
1262impl_data_stack_tuple!(A);
1263impl_data_stack_tuple!(A, B);
1264impl_data_stack_tuple!(A, B, C);
1265impl_data_stack_tuple!(A, B, C, D);
1266impl_data_stack_tuple!(A, B, C, D, E);
1267impl_data_stack_tuple!(A, B, C, D, E, F);
1268impl_data_stack_tuple!(A, B, C, D, E, F, G);
1269impl_data_stack_tuple!(A, B, C, D, E, F, G, H);
1270impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I);
1271impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J);
1272impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1273impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1274impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1275impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
1276impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
1277impl_data_stack_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
1278
1279#[cfg(test)]
1280mod tests {
1281 use crate::{
1282 data_stack::{DataStack, DataStackMode},
1283 type_hash::TypeHash,
1284 };
1285 use std::{alloc::Layout, cell::RefCell, rc::Rc};
1286
1287 #[test]
1288 fn test_data_stack() {
1289 struct Droppable(Rc<RefCell<bool>>);
1290
1291 impl Drop for Droppable {
1292 fn drop(&mut self) {
1293 *self.0.borrow_mut() = true;
1294 }
1295 }
1296
1297 let dropped = Rc::new(RefCell::new(false));
1298 let mut stack = DataStack::new(10240, DataStackMode::Values);
1299 assert_eq!(stack.size(), 16384);
1300 assert_eq!(stack.position(), 0);
1301 stack.push(Droppable(dropped.clone()));
1302 assert_eq!(
1303 stack.position(),
1304 if cfg!(feature = "typehash_debug_name") {
1305 32
1306 } else {
1307 16
1308 }
1309 );
1310 let token = stack.store();
1311 stack.push(42_usize);
1312 assert_eq!(
1313 stack.position(),
1314 if cfg!(feature = "typehash_debug_name") {
1315 64
1316 } else {
1317 32
1318 }
1319 );
1320 stack.push(true);
1321 assert_eq!(
1322 stack.position(),
1323 if cfg!(feature = "typehash_debug_name") {
1324 89
1325 } else {
1326 41
1327 }
1328 );
1329 stack.push(4.2_f32);
1330 assert_eq!(
1331 stack.position(),
1332 if cfg!(feature = "typehash_debug_name") {
1333 117
1334 } else {
1335 53
1336 }
1337 );
1338 assert!(!*dropped.borrow());
1339 assert!(stack.pop::<()>().is_none());
1340 stack.push(());
1341 assert_eq!(
1342 stack.position(),
1343 if cfg!(feature = "typehash_debug_name") {
1344 141
1345 } else {
1346 61
1347 }
1348 );
1349 stack.reverse(token);
1350 let mut stack2 = stack.pop_stack(2, None);
1351 assert_eq!(
1352 stack.position(),
1353 if cfg!(feature = "typehash_debug_name") {
1354 84
1355 } else {
1356 36
1357 }
1358 );
1359 assert_eq!(
1360 stack2.size(),
1361 if cfg!(feature = "typehash_debug_name") {
1362 64
1363 } else {
1364 32
1365 }
1366 );
1367 assert_eq!(
1368 stack2.position(),
1369 if cfg!(feature = "typehash_debug_name") {
1370 57
1371 } else {
1372 25
1373 }
1374 );
1375 assert_eq!(stack2.pop::<usize>().unwrap(), 42_usize);
1376 assert_eq!(
1377 stack2.position(),
1378 if cfg!(feature = "typehash_debug_name") {
1379 25
1380 } else {
1381 9
1382 }
1383 );
1384 assert!(stack2.pop::<bool>().unwrap());
1385 assert_eq!(stack2.position(), 0);
1386 stack2.push(true);
1387 stack2.push(42_usize);
1388 stack.push_stack(stack2).ok().unwrap();
1389 assert_eq!(
1390 stack.position(),
1391 if cfg!(feature = "typehash_debug_name") {
1392 141
1393 } else {
1394 61
1395 }
1396 );
1397 assert_eq!(stack.pop::<usize>().unwrap(), 42_usize);
1398 assert_eq!(
1399 stack.position(),
1400 if cfg!(feature = "typehash_debug_name") {
1401 109
1402 } else {
1403 45
1404 }
1405 );
1406 assert!(stack.pop::<bool>().unwrap());
1407 assert_eq!(
1408 stack.position(),
1409 if cfg!(feature = "typehash_debug_name") {
1410 84
1411 } else {
1412 36
1413 }
1414 );
1415 assert_eq!(stack.pop::<f32>().unwrap(), 4.2_f32);
1416 assert_eq!(
1417 stack.position(),
1418 if cfg!(feature = "typehash_debug_name") {
1419 56
1420 } else {
1421 24
1422 }
1423 );
1424 stack.pop::<()>().unwrap();
1425 assert_eq!(
1426 stack.position(),
1427 if cfg!(feature = "typehash_debug_name") {
1428 32
1429 } else {
1430 16
1431 }
1432 );
1433 stack.push(42_usize);
1434 unsafe {
1435 let (layout, type_hash, finalizer, data) = stack.pop_raw().unwrap();
1436 assert_eq!(layout, Layout::new::<usize>().pad_to_align());
1437 assert_eq!(type_hash, TypeHash::of::<usize>());
1438 assert!(stack.push_raw(layout, type_hash, finalizer, &data));
1439 assert_eq!(
1440 stack.position(),
1441 if cfg!(feature = "typehash_debug_name") {
1442 64
1443 } else {
1444 32
1445 }
1446 );
1447 assert_eq!(stack.pop::<usize>().unwrap(), 42_usize);
1448 assert_eq!(
1449 stack.position(),
1450 if cfg!(feature = "typehash_debug_name") {
1451 32
1452 } else {
1453 16
1454 }
1455 );
1456 }
1457 drop(stack);
1458 assert!(*dropped.borrow());
1459
1460 let mut stack = DataStack::new(10240, DataStackMode::Registers);
1461 assert_eq!(stack.size(), 16384);
1462 stack.push_register::<bool>().unwrap();
1463 stack.drop_register();
1464 let a = stack.push_register_value(true).unwrap();
1465 assert!(*stack.access_register(a).unwrap().read::<bool>().unwrap());
1466 assert!(stack.access_register(a).unwrap().take::<bool>().unwrap());
1467 assert!(!stack.access_register(a).unwrap().has_value());
1468 let b = stack.push_register_value(0usize).unwrap();
1469 stack.access_register(b).unwrap().set(42usize);
1470 assert_eq!(
1471 *stack.access_register(b).unwrap().read::<usize>().unwrap(),
1472 42
1473 );
1474 }
1475}