Skip to content

Commit

Permalink
[3/n][vm-rewrite][Move] Update native context extensions to support C…
Browse files Browse the repository at this point in the history
…loning, and let extension determine how to handle interior mutability.

This updates the `NativeContextExtensions` struct to be `Clone`able.
This updates the `Box<dyn Tid<'a>>` to a `Rc<dyn Tid<'a>>` and the
extension is responsible for handling interior mutability.

As a helper struct the `NativeContextMut` was added to allow for easy
writing/handling of native extensions that need interior mutability.

NB: The code in the PR may not be working as future PRs will build on
top of this. In particular, for this PR, the changes to the object
runtime/sui-adapter/sui-execution natives will be needed.
  • Loading branch information
tzakian committed Feb 3, 2025
1 parent c07295c commit a1a87a0
Showing 1 changed file with 63 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,56 @@
// SPDX-License-Identifier: Apache-2.0

use better_any::{Tid, TidAble, TidExt};
use std::{any::TypeId, collections::HashMap};
use std::{
any::TypeId,
cell::{Ref, RefCell, RefMut},
collections::HashMap,
ops::{Deref, DerefMut},
rc::Rc,
};

/// A helper wrapper around a `Tid`able type that encapsulates interior mutability in a single-threaded
/// manner.
///
/// Note that this is _not_ threadsafe. If you need threadsafe access to the `T` you will need to
/// handle that within `T'`s type (just like in the previous implementation of the
/// `NativeContextExtensions`).
#[derive(Tid)]
pub struct NativeContextMut<'a, T: Tid<'a>>(pub RefCell<T>, std::marker::PhantomData<&'a ()>);

impl<'a, T: Tid<'a>> NativeContextMut<'a, T> {
/// Create a new `NativeContextMut` value with the given value.
pub fn new(t: T) -> Self {
NativeContextMut(RefCell::new(t), std::marker::PhantomData)
}

/// Get the inner value by `&mut`.
pub fn get_mut(&self) -> RefMut<T> {
self.0.borrow_mut()
}

/// Get the inner value by `&`.
pub fn get(&self) -> Ref<T> {
self.0.borrow()
}

pub fn into_inner(self) -> T {
self.0.into_inner()
}
}

impl<'a, T: Tid<'a>> Deref for NativeContextMut<'a, T> {
type Target = RefCell<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'a, T: Tid<'a>> DerefMut for NativeContextMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

/// A data type to represent a heterogeneous collection of extensions which are available to
/// native functions. A value to this is passed into the session function execution.
Expand All @@ -13,15 +62,15 @@ use std::{any::TypeId, collections::HashMap};
/// avoids that extensions need to have `'static` lifetime, which `Any` requires. In order to make a
/// struct suitable to be a 'Tid', use `#[derive(Tid)]` in the struct declaration. (See also
/// tests at the end of this module.)
#[derive(Default)]
#[derive(Default, Clone)]
pub struct NativeContextExtensions<'a> {
map: HashMap<TypeId, Box<dyn Tid<'a>>>,
map: HashMap<TypeId, Rc<dyn Tid<'a>>>,
}

impl<'a> NativeContextExtensions<'a> {
pub fn add<T: TidAble<'a>>(&mut self, ext: T) {
assert!(
self.map.insert(T::id(), Box::new(ext)).is_none(),
self.map.insert(T::id(), Rc::new(ext)).is_none(),
"multiple extensions of the same type not allowed"
)
}
Expand All @@ -35,32 +84,23 @@ impl<'a> NativeContextExtensions<'a> {
.unwrap()
}

pub fn get_mut<T: TidAble<'a>>(&mut self) -> &mut T {
self.map
.get_mut(&T::id())
.expect("extension unknown")
.as_mut()
.downcast_mut::<T>()
.unwrap()
}

pub fn remove<T: TidAble<'a>>(&mut self) -> T {
pub fn remove<T: TidAble<'a>>(&mut self) -> Rc<T> {
// can't use expect below because it requires `T: Debug`.
match self
.map
.remove(&T::id())
.expect("extension unknown")
.downcast_box::<T>()
.downcast_rc::<T>()
{
Ok(val) => *val,
Ok(val) => val,
Err(_) => panic!("downcast error"),
}
}
}

#[cfg(test)]
mod tests {
use crate::natives::extensions::NativeContextExtensions;
use super::*;
use better_any::{Tid, TidAble};

#[derive(Tid)]
Expand All @@ -73,11 +113,11 @@ mod tests {
let mut v: u64 = 23;
let e = Ext { a: &mut v };
let mut exts = NativeContextExtensions::default();
exts.add(e);
*exts.get_mut::<Ext>().a += 1;
assert_eq!(*exts.get_mut::<Ext>().a, 24);
*exts.get_mut::<Ext>().a += 1;
let e1 = exts.remove::<Ext>();
assert_eq!(*e1.a, 25)
exts.add(NativeContextMut::new(e));
*exts.get::<NativeContextMut<Ext>>().get_mut().a += 1;
assert_eq!(*exts.get::<NativeContextMut<Ext>>().get_mut().a, 24);
*exts.get::<NativeContextMut<Ext>>().get_mut().a += 1;
let e1 = exts.get::<NativeContextMut<Ext>>();
assert_eq!(*e1.get().a, 25);
}
}

0 comments on commit a1a87a0

Please sign in to comment.