Skip to content

Commit

Permalink
feat: Allow OpaqueValue to be converted into its inner value
Browse files Browse the repository at this point in the history
The deref coercion enables cheap access to Userdata values as well as
strings
  • Loading branch information
Marwes committed Jul 30, 2018
1 parent 1ea2428 commit 1147ab5
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 5 deletions.
7 changes: 7 additions & 0 deletions examples/marshalling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,17 @@ fn marshal_userdata() -> Result<()> {
hwnd
"#;

// `UserdataValue` lets us extract a `Clone` of its inner userdata value
let (UserdataValue(handle), _) =
compiler.run_expr::<UserdataValue<WindowHandle>>(&vm, "test", script)?;
assert_eq!(*handle.id, 0);
assert_eq!(&*handle.metadata, "Window1");

// If cloning would be expansive we can instate use `OpaqueValue` to get a smart pointer to the
// userdata which implements `Deref` for easy access
let (handle, _) = compiler.run_expr::<OpaqueValue<&Thread, WindowHandle>>(&vm, "test", script)?;
assert_eq!(*handle.id, 0);
assert_eq!(&*handle.metadata, "Window1");
Ok(())
}

Expand Down
54 changes: 49 additions & 5 deletions vm/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,12 +552,18 @@ where
T: ?Sized + VmType,
{
type Type = T::Type;

fn make_type(vm: &Thread) -> ArcType {
T::make_type(vm)
}

fn make_forall_type(vm: &Thread) -> ArcType {
T::make_forall_type(vm)
}

fn extra_args() -> VmIndex {
T::extra_args()
}
}

impl<'vm, 'value, T> Getable<'vm, 'value> for UserdataValue<T>
Expand Down Expand Up @@ -1332,13 +1338,42 @@ where
}
}

/// Type which represents an array in gluon
/// Type implementing both `Pushable` and `Getable` of values of `V`.
/// The actual value, `V` is not accessible directly but is only intended to be transferred between
/// two different threads.
/// Type implementing both `Pushable` and `Getable` of values of `V` regardless of wheter `V`
/// implements the traits.
/// The actual value, `V` is only accessible directly either by `Deref` if it is `Userdata` or a
/// string or by the `to_value` method if it implements `Getable`.
///
/// When the value is not accessible the value can only be transferred back into gluon again
/// without inspecting the value itself two different threads.
pub struct OpaqueValue<T, V>(RootedValue<T>, PhantomData<V>)
where
T: Deref<Target = Thread>;
T: Deref<Target = Thread>,
V: ?Sized;

impl<T, V> Deref for OpaqueValue<T, V>
where
T: Deref<Target = Thread>,
V: vm::Userdata,
{
type Target = V;

fn deref(&self) -> &V {
// The value is rooted by self
unsafe { <&V>::from_value_unsafe(self.vm(), self.get_variant()) }
}
}

impl<T> Deref for OpaqueValue<T, str>
where
T: Deref<Target = Thread>,
{
type Target = str;

fn deref(&self) -> &str {
// The value is rooted by self
unsafe { <&str>::from_value_unsafe(self.vm(), self.get_variant()) }
}
}

#[cfg(feature = "serde")]
impl<'de, V> Deserialize<'de> for OpaqueValue<RootedThread, V> {
Expand Down Expand Up @@ -1372,6 +1407,7 @@ where
impl<T, V> OpaqueValue<T, V>
where
T: Deref<Target = Thread>,
V: ?Sized,
{
pub fn from_value(value: RootedValue<T>) -> Self {
OpaqueValue(value, PhantomData)
Expand All @@ -1381,6 +1417,14 @@ where
self.0.vm()
}

/// Converts the value into its Rust representation
pub fn to_value<'vm>(&'vm self) -> V
where
V: Getable<'vm, 'vm>,
{
V::from_value(self.vm(), self.get_variant())
}

pub fn into_inner(self) -> RootedValue<T> {
self.0
}
Expand Down

0 comments on commit 1147ab5

Please sign in to comment.