Guest User

UniqueBox test

a guest
Mar 20th, 2023
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.35 KB | None | 0 0
  1. use core::fmt;
  2. use std::{
  3.     cell::Cell,
  4.     mem,
  5.     ops::Deref,
  6.     ptr::{NonNull, self},
  7. };
  8.  
  9. use roc_std::{RocBox, Storage};
  10.  
  11. use super::{roc_alloc, roc_dealloc};
  12.  
  13. #[repr(C)]
  14. pub struct UniqueBox<T> {
  15.     contents: NonNull<T>,
  16. }
  17.  
  18. impl<T> UniqueBox<T> {
  19.     pub fn new(contents: T) -> Self {
  20.  
  21.         let contents_ptr = Self::alloc_self();
  22.         let contents = unsafe {
  23.             // Write the data to the memory.
  24.             *contents_ptr = contents;
  25.             // No need to check if the ptr is non null it is checked in alloc_self.
  26.             NonNull::new_unchecked(contents_ptr)
  27.         };
  28.  
  29.         Self { contents }
  30.     }
  31.  
  32.     // Make the allocation necessary for the data
  33.     fn alloc_self() -> *mut T {
  34.         let alignment = Self::alloc_alignment();
  35.         let bytes = mem::size_of::<T>() + alignment;
  36.         // Initialize the reference count.
  37.         let refcount_one = Storage::new_reference_counted();
  38.  
  39.         unsafe {
  40.            let ptr = roc_alloc(bytes, alignment as u32);
  41.             if ptr.is_null() {
  42.                 todo!("Call roc_panic with the info that an allocation failed");
  43.             }
  44.             // Write the ref count.
  45.             ptr.cast::<Storage>().write(refcount_one);
  46.             // Return the pointer to the data.
  47.             ptr.cast::<u8>().add(alignment).cast::<T>()
  48.         }
  49.     }
  50.  
  51.     #[inline(always)]
  52.     fn alloc_alignment() -> usize {
  53.         mem::align_of::<T>().max(mem::align_of::<Storage>())
  54.     }
  55.  
  56.     pub fn into_inner(self) -> T {
  57.         unsafe {ptr::read(self.contents.as_ptr() as *const T)}
  58.     }
  59.  
  60.     fn storage(&self) -> &Cell<Storage> {
  61.         let alignment = Self::alloc_alignment();
  62.         unsafe {
  63.             &*self
  64.                 .contents
  65.                 .as_ptr()
  66.                 .cast::<u8>()
  67.                 .sub(alignment)
  68.                 .cast::<Cell<Storage>>()
  69.         }
  70.     }
  71. }
  72.  
  73. unsafe impl<T> Send for UniqueBox<T> {}
  74.  
  75. impl<T> Deref for UniqueBox<T> {
  76.     type Target = T;
  77.  
  78.     fn deref(&self) -> &Self::Target {
  79.         unsafe { self.contents.as_ref() }
  80.     }
  81. }
  82.  
  83. impl<T> Eq for UniqueBox<T> where T: Eq {}
  84.  
  85. impl<T, U> PartialEq<UniqueBox<U>> for UniqueBox<T> where T: PartialEq<U> {
  86.     fn eq(&self, other: &UniqueBox<U>) -> bool {
  87.         self.deref() == other.deref()
  88.     }
  89. }
  90.  
  91. impl<T, U> PartialOrd<UniqueBox<U>> for UniqueBox<T> where T: PartialOrd<U> {
  92.     fn partial_cmp(&self, other: &UniqueBox<U>) -> Option<std::cmp::Ordering> {
  93.         let self_contents = unsafe { self.contents.as_ref() };
  94.         let other_contents = unsafe { other.contents.as_ref() };
  95.         self_contents.partial_cmp(other_contents)
  96.     }
  97. }
  98.  
  99. impl<T> Ord for UniqueBox<T> where T: Ord {
  100.     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
  101.         let self_contents = unsafe { self.contents.as_ref() };
  102.         let other_contents = unsafe { other.contents.as_ref() };
  103.         self_contents.cmp(other_contents)
  104.     }
  105. }
  106.  
  107. impl<T> fmt::Debug for UniqueBox<T>
  108. where
  109.     T: fmt::Debug,
  110. {
  111.     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  112.        self.deref().fmt(f)
  113.    }
  114. }
  115.  
  116. impl<T> Clone for UniqueBox<T> {
  117.    fn clone(&self) -> Self {
  118.        let contents_ptr = Self::alloc_self();
  119.        let contents = unsafe {
  120.            *contents_ptr = ptr::read(self.contents.as_ptr());
  121.            NonNull::new_unchecked(contents_ptr)
  122.        };
  123.        Self { contents }
  124.    }
  125. }
  126.  
  127. impl<T> From<RocBox<T>> for UniqueBox<T> {
  128.    fn from(value: RocBox<T>) -> Self {
  129.        let alignment = Self::alloc_alignment();
  130.        // Get the inner value
  131.        let inner = value.into_inner();
  132.        // Get the storage of the RocBox. (Not sure it works)
  133.        let value_storage: &Cell<Storage> = {
  134.            unsafe {
  135.                &*(&inner as *const T)
  136.                    .cast::<u8>()
  137.                    .sub(alignment)
  138.                    .cast::<Cell<Storage>>()
  139.            }
  140.        };
  141.        let new_storage = value_storage.get();
  142.        // Check the reference count. If it is one we take ownership
  143.        // else we duplicate the value and create a new reference
  144.        // count at one.
  145.        let contents = if new_storage.is_unique() {
  146.            value_storage.set(new_storage);
  147.            NonNull::new(&mut inner as *mut T).unwrap()
  148.        } else {
  149.            let contents_ptr = Self::alloc_self();
  150.            unsafe {
  151.                *contents_ptr = ptr::read(value.deref() as *const T);
  152.                NonNull::new_unchecked(contents_ptr)
  153.            }
  154.        };
  155.  
  156.        Self { contents }
  157.    }
  158. }
  159.  
  160. impl<T> Into<RocBox<T>> for UniqueBox<T> {
  161.    fn into(self) -> RocBox<T> {
  162.        // Intrenal representation is equivalent between the two types
  163.        // so it should be fine.
  164.        unsafe {
  165.            mem::transmute(self)
  166.        }
  167.    }
  168. }
  169.  
  170. impl<T> Drop for UniqueBox<T> {
  171.    fn drop(&mut self) {
  172.        // We don't need to check the reference count because
  173.         // it is assumed that it is one of UniqueBox.
  174.         let contents = self.contents;
  175.         let alignment = Self::alloc_alignment();
  176.         unsafe {
  177.             let contents_ptr = contents.as_ptr();
  178.             mem::drop::<T>(ptr::read(contents_ptr));
  179.             // Release the memory.
  180.             roc_dealloc(contents.as_ptr().cast::<u8>().sub(alignment).cast(), alignment as u32);
  181.         }
  182.     }
  183. }
  184.  
Advertisement
Add Comment
Please, Sign In to add comment