Last active
March 13, 2023 20:35
-
-
Save coder0xff/016d2e3744610ad56182c4b9b93c290e to your computer and use it in GitHub Desktop.
Rust counterparts for the Dart abstraction of the Rust memory model
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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