Skip to content

Instantly share code, notes, and snippets.

@coder0xff
Last active March 13, 2023 20:35
Show Gist options
  • Save coder0xff/016d2e3744610ad56182c4b9b93c290e to your computer and use it in GitHub Desktop.
Save coder0xff/016d2e3744610ad56182c4b9b93c290e to your computer and use it in GitHub Desktop.
Rust counterparts for the Dart abstraction of the Rust memory model
use std::ops;
use std::rc::Rc;
use std::slice;
use std::sync::Arc;
use std::thread;
use crate::DartSafe;
/// Convert any value to bytes. This function makes zero promises about the validity
/// of the result. That's up to the caller.
unsafe fn value_to_wire_data_unchecked<T: Sized>(value: &T) -> Vec<u8> {
let size = std::mem::size_of::<T>();
let pointer = value as *const T as *const u8;
let as_bytes = slice::from_raw_parts(pointer, size);
Vec::from(as_bytes)
}
/// Convert bytes to any value. This function makes zero promises about the validity
/// of the result. That's up to the caller.
unsafe fn value_from_wire_data_unchecked<T: Sized>(data: &[u8]) -> T {
let size = std::mem::size_of::<*const T>();
assert_eq!(
data.len(),
size,
"The data size is incorrect. expected: {}, actual: {}",
size,
data.len()
);
let pointer = &data[0] as *const u8 as *const T;
std::ptr::read(pointer)
}
/// An immutable indirection to a T
pub struct Indirect<T: ?Sized + DartSafe>(*const T);
impl<T: ?Sized + DartSafe> ops::Deref for Indirect<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
// Into causes E0210 in `.. for &'static T`, make our own
pub trait IntoIndirect<T: ?Sized + DartSafe> {
fn into(self) -> Indirect<T>;
}
impl<T: ?Sized + DartSafe> IntoIndirect<T> for &'static T {
fn into(self) -> Indirect<T> {
Indirect(self)
}
}
impl<T: ?Sized + DartSafe> IntoIndirect<T> for *const T {
fn into(self) -> Indirect<T> {
Indirect(self)
}
}
impl<T: ?Sized + DartSafe> Indirect<T> {
pub fn new<U: IntoIndirect<T>>(value: U) -> Self {
value.into()
}
unsafe fn to_wire_data(self) -> Vec<u8> {
value_to_wire_data_unchecked(&self.0)
}
unsafe fn from_wire_data(data: &[u8]) -> Self {
Indirect::<T>::new(value_from_wire_data_unchecked::<*const T>(data))
}
}
/// A mutable indirection to a T
pub enum MutIndirect<T: ?Sized + DartSafe> {
Pointer(*mut T),
Counted {
thread_id: thread::ThreadId,
ptr: *mut Rc<T>,
},
AtomicCounted(*mut Arc<T>),
}
impl<T: ?Sized + DartSafe> ops::Deref for MutIndirect<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
MutIndirect::AtomicCounted(arc_ptr) => unsafe { Arc::as_ref(&mut **arc_ptr) },
MutIndirect::Counted { thread_id, ptr } => {
let current_thread_id = thread::current().id();
assert_eq!(
thread_id.clone(),
current_thread_id,
"std::rc::Rc accessed from the wrong thread {:?}, only thread {:?} permitted",
current_thread_id,
thread_id
);
unsafe { Rc::as_ref(&mut **ptr) }
}
MutIndirect::Pointer(ptr) => unsafe { &mut **ptr },
}
}
}
impl<T: ?Sized + DartSafe> ops::DerefMut for MutIndirect<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
MutIndirect::AtomicCounted(arc_ptr) => unsafe { Arc::get_mut(&mut **arc_ptr).unwrap() },
MutIndirect::Counted { thread_id, ptr } => {
let current_thread_id = thread::current().id();
assert_eq!(
thread_id.clone(),
current_thread_id,
"std::rc::Rc accessed from the wrong thread {:?}, only thread {:?} permitted",
current_thread_id,
thread_id
);
unsafe { Rc::get_mut(&mut **ptr).unwrap() }
}
MutIndirect::Pointer(ptr) => unsafe { &mut **ptr },
}
}
}
// Into causes E0210 in `.. for &'static mut T`, make our own
trait IntoMutIndirect<T: ?Sized + DartSafe> {
fn into(self) -> MutIndirect<T>;
}
impl<T: ?Sized + DartSafe> IntoMutIndirect<T> for &'static mut T {
fn into(self) -> MutIndirect<T> {
MutIndirect::Pointer(self)
}
}
impl<T: ?Sized + DartSafe> IntoMutIndirect<T> for *mut T {
fn into(self) -> MutIndirect<T> {
MutIndirect::Pointer(self)
}
}
impl<T: ?Sized + DartSafe> IntoMutIndirect<T> for Arc<T> {
fn into(self) -> MutIndirect<T> {
MutIndirect::AtomicCounted(Box::into_raw(Box::new(self)))
}
}
impl<T: ?Sized + DartSafe> Into<MutIndirect<T>> for Rc<T> {
fn into(self) -> MutIndirect<T> {
MutIndirect::Counted {
thread_id: thread::current().id(),
ptr: Box::into_raw(Box::new(self)),
}
}
}
impl<T: ?Sized + DartSafe> MutIndirect<T> {
fn new<U: IntoMutIndirect<T>>(value: U) -> Self {
value.into()
}
unsafe fn to_wire_data(self) -> Vec<u8> {
match self {
MutIndirect::Pointer(ptr) => {
let mut result = vec![0 as u8];
result.append(&mut value_to_wire_data_unchecked(&ptr));
result
}
MutIndirect::Counted { thread_id, ptr } => {
let mut result = vec![1 as u8];
result.append(&mut value_to_wire_data_unchecked(&(thread_id, ptr)));
result
}
MutIndirect::AtomicCounted(arc) => {
let mut result = vec![2 as u8];
result.append(&mut value_to_wire_data_unchecked(&arc));
result
}
}
}
unsafe fn from_wire_data(data: &[u8]) -> Self {
match data[0] {
0 => MutIndirect::Pointer(value_from_wire_data_unchecked(&data[1..])),
1 => {
let (thread_id, ptr) = value_from_wire_data_unchecked::<(thread::ThreadId, *mut Rc<T>)>(&data[1..]);
MutIndirect::Counted { thread_id, ptr }
}
2 => MutIndirect::AtomicCounted(value_from_wire_data_unchecked(&data[1..])),
e => panic!("Wire data contained an illegal variant tag, expected: [0-2], actual {}", e),
}
}
}
/// An owned T
pub struct Owned<T: ?Sized + DartSafe>(*mut T);
impl<T: ?Sized + DartSafe> ops::Deref for Owned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
impl<T: ?Sized + DartSafe> ops::DerefMut for Owned<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.0 }
}
}
pub trait IntoOwned<T: ?Sized + DartSafe> {
fn into(self) -> Owned<T>;
}
impl<T: Sized + DartSafe> IntoOwned<T> for T {
fn into(self) -> Owned<T> {
Owned(Box::into_raw(Box::new(self)))
}
}
impl<T: ?Sized + DartSafe> IntoOwned<T> for Box<T> {
fn into(self) -> Owned<T> {
Owned(Box::into_raw(self))
}
}
impl<T: Sized + DartSafe> Owned<T> {
fn into_inner(self) -> T {
unsafe { std::ptr::read(self.0) }
}
}
impl<T: ?Sized + DartSafe> Owned<T> {
fn new<U: IntoOwned<T>>(value: U) -> Self {
value.into()
}
fn into_owned(self) -> Box<T> {
unsafe { Box::from_raw(self.0) }
}
unsafe fn to_wire_data(self) -> Vec<u8> {
value_to_wire_data_unchecked(&self.0)
}
unsafe fn from_wire_data(data: &[u8]) -> Self {
Owned(value_from_wire_data_unchecked(data))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment