Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #![allow(unused_unsafe)]
- extern crate core;
- use core::{
- mem::{align_of, size_of},
- ptr,
- };
- //Used to keep track information to get things out
- #[derive(Copy, Clone, Debug)]
- struct BinRefRaw {
- start: usize,
- offset: usize,
- size: usize,
- }
- //A Bin is a struct that acts like a stack, you can push anything inside
- //But you have to pop the same type in reversed order.
- pub struct BinRaw {
- data: Vec<u8>,
- allocated: Vec<BinRefRaw>,
- }
- impl Default for BinRaw {
- fn default() -> Self {
- Self::new()
- }
- }
- impl BinRaw {
- pub fn new() -> Self {
- Self {
- data: vec![],
- allocated: vec![],
- }
- }
- //Although contains unsafe code, pushing anything inside should be safe
- pub fn push<T>(&mut self, t: T) {
- let (pos, align, size) = (self.data.len(), align_of::<T>(), size_of::<T>());
- //ZST optimization
- if size == 0 {
- self.allocated.push(BinRefRaw {
- start: pos,
- offset: 0,
- size: 0,
- });
- return;
- }
- self.data.reserve(align + size);
- let result = unsafe {
- self.data.set_len(pos + align + size);
- let (offset, v, _) = { &mut self.data[pos..].align_to_mut::<T>() };
- if !v.is_empty() {
- let offset = offset.len();
- ptr::write(&mut v[0], t);
- Ok(offset)
- } else {
- Err(t)
- }
- };
- let offset = unsafe {
- match result {
- Ok(offset) => {
- self.data.set_len(pos + offset + size);
- offset
- }
- Err(t) => {
- //Miri does not support align; this is a fallback
- ptr::write_unaligned(self.data.get_unchecked_mut(pos) as *mut u8 as *mut T, t);
- self.data.set_len(pos + size);
- 0
- }
- }
- };
- self.allocated.push(BinRefRaw {
- start: pos,
- offset,
- size,
- });
- }
- //Highly unsafe! you have to ensure T is the type of object at top
- pub unsafe fn pop<T>(&mut self) -> T {
- let BinRefRaw {
- start: pos,
- offset,
- size,
- } = self.allocated.pop().unwrap();
- //ZST optimization
- if size_of::<T>() == 0 {
- assert_eq!(pos, self.data.len());
- assert_eq!(offset, 0);
- assert_eq!(size, 0);
- return unsafe {
- //Not sure if we need read_unaligned; but it should be no-op anyways
- ptr::read_unaligned(self.data.get_unchecked(pos) as *const u8 as *const T)
- };
- }
- assert_eq!(size, size_of::<T>());
- let r = {
- let (offset_new, v, _) = unsafe { self.data[pos..].align_to::<T>() };
- if !v.is_empty() {
- assert_eq!(offset, offset_new.len());
- unsafe { ptr::read(&v[0]) }
- } else {
- //Miri does not support align; this is a fallback
- assert_eq!(offset, 0);
- unsafe {
- ptr::read_unaligned(self.data.get_unchecked(pos) as *const u8 as *const T)
- }
- }
- };
- self.data.set_len(pos);
- r
- }
- }
- fn main() {
- let mut b = BinRaw::new();
- //pushing is safe
- b.push(19i32);
- b.push("12345");
- b.push(20u32);
- b.push(());
- //poping is unsafe
- unsafe {
- b.pop::<()>();
- let s = b.pop::<u32>();
- println!("{}", s);
- println!("{}", b.pop::<&str>());
- println!("{}", b.pop::<i32>());
- }
- }
Add Comment
Please, Sign In to add comment