Guest User

Untitled

a guest
Nov 14th, 2018
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.65 KB | None | 0 0
  1. #![allow(unused_unsafe)]
  2.  
  3. extern crate core;
  4. use core::{
  5. mem::{align_of, size_of},
  6. ptr,
  7. };
  8.  
  9. //Used to keep track information to get things out
  10. #[derive(Copy, Clone, Debug)]
  11. struct BinRefRaw {
  12. start: usize,
  13. offset: usize,
  14. size: usize,
  15. }
  16.  
  17. //A Bin is a struct that acts like a stack, you can push anything inside
  18. //But you have to pop the same type in reversed order.
  19. pub struct BinRaw {
  20. data: Vec<u8>,
  21. allocated: Vec<BinRefRaw>,
  22. }
  23. impl Default for BinRaw {
  24. fn default() -> Self {
  25. Self::new()
  26. }
  27. }
  28. impl BinRaw {
  29. pub fn new() -> Self {
  30. Self {
  31. data: vec![],
  32. allocated: vec![],
  33. }
  34. }
  35. //Although contains unsafe code, pushing anything inside should be safe
  36. pub fn push<T>(&mut self, t: T) {
  37. let (pos, align, size) = (self.data.len(), align_of::<T>(), size_of::<T>());
  38.  
  39. //ZST optimization
  40. if size == 0 {
  41. self.allocated.push(BinRefRaw {
  42. start: pos,
  43. offset: 0,
  44. size: 0,
  45. });
  46. return;
  47. }
  48. self.data.reserve(align + size);
  49.  
  50. let result = unsafe {
  51. self.data.set_len(pos + align + size);
  52. let (offset, v, _) = { &mut self.data[pos..].align_to_mut::<T>() };
  53. if !v.is_empty() {
  54. let offset = offset.len();
  55. ptr::write(&mut v[0], t);
  56. Ok(offset)
  57. } else {
  58. Err(t)
  59. }
  60. };
  61. let offset = unsafe {
  62. match result {
  63. Ok(offset) => {
  64. self.data.set_len(pos + offset + size);
  65. offset
  66. }
  67. Err(t) => {
  68. //Miri does not support align; this is a fallback
  69. ptr::write_unaligned(self.data.get_unchecked_mut(pos) as *mut u8 as *mut T, t);
  70. self.data.set_len(pos + size);
  71. 0
  72. }
  73. }
  74. };
  75.  
  76. self.allocated.push(BinRefRaw {
  77. start: pos,
  78. offset,
  79. size,
  80. });
  81. }
  82. //Highly unsafe! you have to ensure T is the type of object at top
  83. pub unsafe fn pop<T>(&mut self) -> T {
  84. let BinRefRaw {
  85. start: pos,
  86. offset,
  87. size,
  88. } = self.allocated.pop().unwrap();
  89.  
  90. //ZST optimization
  91. if size_of::<T>() == 0 {
  92. assert_eq!(pos, self.data.len());
  93. assert_eq!(offset, 0);
  94. assert_eq!(size, 0);
  95. return unsafe {
  96. //Not sure if we need read_unaligned; but it should be no-op anyways
  97. ptr::read_unaligned(self.data.get_unchecked(pos) as *const u8 as *const T)
  98. };
  99. }
  100.  
  101. assert_eq!(size, size_of::<T>());
  102. let r = {
  103. let (offset_new, v, _) = unsafe { self.data[pos..].align_to::<T>() };
  104. if !v.is_empty() {
  105. assert_eq!(offset, offset_new.len());
  106. unsafe { ptr::read(&v[0]) }
  107. } else {
  108. //Miri does not support align; this is a fallback
  109. assert_eq!(offset, 0);
  110. unsafe {
  111. ptr::read_unaligned(self.data.get_unchecked(pos) as *const u8 as *const T)
  112. }
  113. }
  114. };
  115. self.data.set_len(pos);
  116. r
  117. }
  118. }
  119. fn main() {
  120. let mut b = BinRaw::new();
  121.  
  122. //pushing is safe
  123. b.push(19i32);
  124. b.push("12345");
  125. b.push(20u32);
  126. b.push(());
  127.  
  128. //poping is unsafe
  129. unsafe {
  130. b.pop::<()>();
  131. let s = b.pop::<u32>();
  132. println!("{}", s);
  133. println!("{}", b.pop::<&str>());
  134. println!("{}", b.pop::<i32>());
  135. }
  136. }
Add Comment
Please, Sign In to add comment