From a044a51b016c82568a74919f50399cfadeadd80e Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Fri, 1 Nov 2024 02:49:08 +0100 Subject: [PATCH] rune: Store OwnedTuple in AnyObj instead of Mutable (relates #844) --- crates/rune-modules/src/http.rs | 2 +- crates/rune/src/compile/ir/interpreter.rs | 114 ++++---- crates/rune/src/doc/build.rs | 8 +- crates/rune/src/internal_macros.rs | 36 +++ crates/rune/src/modules/future.rs | 37 ++- crates/rune/src/modules/tuple.rs | 57 +++- crates/rune/src/runtime/any_obj.rs | 6 +- crates/rune/src/runtime/borrow_mut.rs | 17 +- crates/rune/src/runtime/borrow_ref.rs | 17 +- crates/rune/src/runtime/const_value.rs | 31 ++- crates/rune/src/runtime/mod.rs | 6 +- crates/rune/src/runtime/shared.rs | 4 +- crates/rune/src/runtime/static_type.rs | 46 +-- crates/rune/src/runtime/tests.rs | 10 +- crates/rune/src/runtime/tuple.rs | 202 ++++++++------ crates/rune/src/runtime/value.rs | 324 ++++++++++++---------- crates/rune/src/runtime/value/inline.rs | 7 +- crates/rune/src/runtime/value/macros.rs | 92 ++++-- crates/rune/src/runtime/value/serde.rs | 21 +- crates/rune/src/runtime/vm.rs | 69 +++-- crates/rune/src/tests/bug_700.rs | 4 +- crates/rune/src/tests/vm_const_exprs.rs | 4 +- 22 files changed, 665 insertions(+), 449 deletions(-) diff --git a/crates/rune-modules/src/http.rs b/crates/rune-modules/src/http.rs index 7ceaed3be..8f01c15bc 100644 --- a/crates/rune-modules/src/http.rs +++ b/crates/rune-modules/src/http.rs @@ -2338,7 +2338,7 @@ mod const_status_code { #[inline] pub(super) fn to_const_value(status: reqwest::StatusCode) -> Result { - ConstValue::try_from(status.as_u16()) + Ok(ConstValue::from(status.as_u16())) } #[inline] diff --git a/crates/rune/src/compile/ir/interpreter.rs b/crates/rune/src/compile/ir/interpreter.rs index 3659e859b..f72b126a1 100644 --- a/crates/rune/src/compile/ir/interpreter.rs +++ b/crates/rune/src/compile/ir/interpreter.rs @@ -222,25 +222,22 @@ impl ir::Scopes { } ir::IrTargetKind::Index(target, index) => { let value = self.get_target(target)?; - let target = value.borrow_ref_repr().with_span(ir_target)?; + let target = value.as_ref_repr().with_span(ir_target)?; match target { - BorrowRefRepr::Mutable(value) => { - match &*value { - Mutable::Tuple(tuple) => { - if let Some(value) = tuple.get(*index) { - return Ok(value.clone()); - } - } - actual => { - return Err(compile::Error::expected_type::( - ir_target, - actual.type_info(), - )) - } - }; + RefRepr::Inline(value) => { + return Err(compile::Error::expected_type::( + ir_target, + value.type_info(), + )); + } + RefRepr::Mutable(value) => { + return Err(compile::Error::expected_type::( + ir_target, + value.borrow_ref().with_span(ir_target)?.type_info(), + )); } - BorrowRefRepr::Any(value) => match value.type_hash() { + RefRepr::Any(value) => match value.type_hash() { runtime::Vec::HASH => { let vec = value.borrow_ref::().with_span(ir_target)?; @@ -248,6 +245,15 @@ impl ir::Scopes { return Ok(value.clone()); } } + runtime::OwnedTuple::HASH => { + let tuple = value + .borrow_ref::() + .with_span(ir_target)?; + + if let Some(value) = tuple.get(*index) { + return Ok(value.clone()); + } + } _ => { return Err(compile::Error::expected_type::( ir_target, @@ -255,12 +261,6 @@ impl ir::Scopes { )); } }, - value => { - return Err(compile::Error::expected_type::( - ir_target, - value.type_info(), - )); - } } Err(compile::Error::new( @@ -321,22 +321,12 @@ impl ir::Scopes { )); } RefRepr::Mutable(current) => { - let mut mutable = current.borrow_mut().with_span(ir_target)?; - - match &mut *mutable { - Mutable::Tuple(tuple) => { - if let Some(current) = tuple.get_mut(*index) { - *current = value; - return Ok(()); - } - } - value => { - return Err(compile::Error::expected_type::( - ir_target, - value.type_info(), - )); - } - }; + let mutable = current.borrow_mut().with_span(ir_target)?; + + return Err(compile::Error::expected_type::( + ir_target, + mutable.type_info(), + )); } RefRepr::Any(any) => match any.type_hash() { runtime::Vec::HASH => { @@ -347,6 +337,16 @@ impl ir::Scopes { return Ok(()); } } + runtime::OwnedTuple::HASH => { + let mut tuple = any + .borrow_mut::() + .with_span(ir_target)?; + + if let Some(current) = tuple.get_mut(*index) { + *current = value; + return Ok(()); + } + } _ => { return Err(compile::Error::expected_type::( ir_target, @@ -409,24 +409,12 @@ impl ir::Scopes { match current.as_ref_repr().with_span(ir_target)? { RefRepr::Mutable(value) => { - let mut value = value.borrow_mut().with_span(ir_target)?; - - match &mut *value { - Mutable::Tuple(tuple) => { - let value = tuple.get_mut(*index).ok_or_else(|| { - compile::Error::new( - ir_target, - IrErrorKind::MissingIndex { index: *index }, - ) - })?; - - op(value) - } - actual => Err(compile::Error::expected_type::( - ir_target, - actual.type_info(), - )), - } + let value = value.borrow_ref().with_span(ir_target)?; + + Err(compile::Error::expected_type::( + ir_target, + value.type_info(), + )) } RefRepr::Any(value) => match value.type_hash() { runtime::Vec::HASH => { @@ -442,6 +430,20 @@ impl ir::Scopes { op(value) } + runtime::OwnedTuple::HASH => { + let mut tuple = value + .borrow_mut::() + .with_span(ir_target)?; + + let value = tuple.get_mut(*index).ok_or_else(|| { + compile::Error::new( + ir_target, + IrErrorKind::MissingIndex { index: *index }, + ) + })?; + + op(value) + } _ => Err(compile::Error::expected_type::( ir_target, value.type_info(), diff --git a/crates/rune/src/doc/build.rs b/crates/rune/src/doc/build.rs index a5695998b..0786bd48e 100644 --- a/crates/rune/src/doc/build.rs +++ b/crates/rune/src/doc/build.rs @@ -24,9 +24,9 @@ use crate::doc::context::{Function, Kind, Meta, Signature}; use crate::doc::templating; use crate::doc::{Artifacts, Context, Visitor}; use crate::item::ComponentRef; -use crate::runtime::static_type; +use crate::runtime::OwnedTuple; use crate::std::borrow::ToOwned; -use crate::{Hash, Item}; +use crate::{Hash, Item, TypeHash}; use super::markdown; @@ -440,7 +440,7 @@ impl<'m> Ctxt<'_, 'm> { match *ty { meta::DocType { base, ref generics, .. - } if static_type::TUPLE == base && generics.is_empty() => Ok(None), + } if OwnedTuple::HASH == base && generics.is_empty() => Ok(None), meta::DocType { base, ref generics, .. } => Ok(Some(self.link(base, None, generics)?)), @@ -619,7 +619,7 @@ impl<'m> Ctxt<'_, 'm> { return Ok(()); }; - if static_type::TUPLE == hash && text.is_none() { + if OwnedTuple::HASH == hash && text.is_none() { write!(o, "(")?; self.write_generics(o, generics)?; write!(o, ")")?; diff --git a/crates/rune/src/internal_macros.rs b/crates/rune/src/internal_macros.rs index 255177ace..a060adc9c 100644 --- a/crates/rune/src/internal_macros.rs +++ b/crates/rune/src/internal_macros.rs @@ -8,6 +8,42 @@ macro_rules! resolve_context { }; } +macro_rules! impl_any_type { + (impl $(<$($p:ident),*>)? for $ty:ty, $path:path) => { + impl $(<$($p,)*>)* $crate::TypeHash for $ty { + const HASH: $crate::Hash = ::rune_macros::hash!($path); + } + + impl $(<$($p,)*>)* $crate::runtime::TypeOf for $ty + where + $($($p: $crate::runtime::MaybeTypeOf,)*)* + { + const STATIC_TYPE_INFO: $crate::runtime::StaticTypeInfo = $crate::runtime::StaticTypeInfo::any_type_info( + $crate::runtime::AnyTypeInfo::new( + { + fn full_name(f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "{}", ::rune_macros::item!($path)) + } + + full_name + }, + ::HASH, + ) + ); + } + + impl $(<$($p,)*>)* $crate::runtime::MaybeTypeOf for $ty + where + $($($p: $crate::runtime::MaybeTypeOf,)*)* + { + #[inline] + fn maybe_type_of() -> $crate::alloc::Result<$crate::compile::meta::DocType> { + Ok($crate::compile::meta::DocType::new(<$ty as $crate::TypeHash>::HASH)) + } + } + } +} + /// Build an implementation of `TypeOf` basic of a static type. macro_rules! impl_static_type { (impl $(<$($p:ident),*>)? for $ty:ty, $name:ident, $hash:ident) => { diff --git a/crates/rune/src/modules/future.rs b/crates/rune/src/modules/future.rs index fa238c85a..d99bb462e 100644 --- a/crates/rune/src/modules/future.rs +++ b/crates/rune/src/modules/future.rs @@ -3,8 +3,7 @@ use crate as rune; use crate::alloc::Vec; use crate::runtime::{ - self, BorrowRefRepr, Future, Inline, Mut, Mutable, RefRepr, SelectFuture, Value, VmErrorKind, - VmResult, + self, Future, Inline, Mut, Mutable, RefRepr, SelectFuture, Value, VmErrorKind, VmResult, }; use crate::{ContextError, Module, TypeHash}; @@ -101,29 +100,19 @@ where /// ``` #[rune::function] async fn join(value: Value) -> VmResult { - match vm_try!(value.borrow_ref_repr()) { - BorrowRefRepr::Inline(value) => match value { + match vm_try!(value.as_ref_repr()) { + RefRepr::Inline(value) => match value { Inline::Unit => VmResult::Ok(Value::unit()), value => VmResult::err([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), ]), }, - BorrowRefRepr::Mutable(value) => match *value { - Mutable::Tuple(ref tuple) => { - let result = try_join_impl(tuple.iter(), tuple.len(), |vec| { - VmResult::Ok(vm_try!(Value::tuple(vec))) - }) - .await; - - VmResult::Ok(vm_try!(result)) - } - ref value => VmResult::err([ - VmErrorKind::bad_argument(0), - VmErrorKind::expected::(value.type_info()), - ]), - }, - BorrowRefRepr::Any(value) => match value.type_hash() { + RefRepr::Mutable(value) => VmResult::err([ + VmErrorKind::bad_argument(0), + VmErrorKind::expected::(vm_try!(value.borrow_ref()).type_info()), + ]), + RefRepr::Any(value) => match value.type_hash() { runtime::Vec::HASH => { let vec = vm_try!(value.borrow_ref::()); let result = try_join_impl(vec.iter(), vec.len(), |vec| { @@ -132,6 +121,16 @@ async fn join(value: Value) -> VmResult { .await; VmResult::Ok(vm_try!(result)) } + runtime::OwnedTuple::HASH => { + let tuple = vm_try!(value.borrow_ref::()); + + let result = try_join_impl(tuple.iter(), tuple.len(), |vec| { + VmResult::Ok(vm_try!(Value::tuple(vec))) + }) + .await; + + VmResult::Ok(vm_try!(result)) + } _ => VmResult::err([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), diff --git a/crates/rune/src/modules/tuple.rs b/crates/rune/src/modules/tuple.rs index 4cc1590f7..52d0d7540 100644 --- a/crates/rune/src/modules/tuple.rs +++ b/crates/rune/src/modules/tuple.rs @@ -4,7 +4,9 @@ use core::cmp::Ordering; use crate as rune; use crate::runtime::slice::Iter; -use crate::runtime::{EnvProtocolCaller, Hasher, Ref, Tuple, Value, Vec, VmResult}; +use crate::runtime::{ + EnvProtocolCaller, Formatter, Hasher, OwnedTuple, Ref, Tuple, Value, Vec, VmResult, +}; use crate::{docstring, ContextError, Module}; /// The [`Tuple`] fixed collection. @@ -42,7 +44,7 @@ use crate::{docstring, ContextError, Module}; #[rune::module(::std::tuple)] pub fn module() -> Result { let mut m = Module::from_meta(self::module_meta)?; - m.ty::()?.docs(docstring! { + m.ty::()?.docs(docstring! { /// The tuple type. })?; m.function_meta(len)?; @@ -52,18 +54,22 @@ pub fn module() -> Result { m.function_meta(into_iter)?; m.function_meta(partial_eq__meta)?; - m.implement_trait::(rune::item!(::std::cmp::PartialEq))?; + m.implement_trait::(rune::item!(::std::cmp::PartialEq))?; m.function_meta(eq__meta)?; - m.implement_trait::(rune::item!(::std::cmp::Eq))?; + m.implement_trait::(rune::item!(::std::cmp::Eq))?; m.function_meta(partial_cmp__meta)?; - m.implement_trait::(rune::item!(::std::cmp::PartialOrd))?; + m.implement_trait::(rune::item!(::std::cmp::PartialOrd))?; m.function_meta(cmp__meta)?; - m.implement_trait::(rune::item!(::std::cmp::Ord))?; + m.implement_trait::(rune::item!(::std::cmp::Ord))?; - m.function_meta(hash)?; + m.function_meta(clone__meta)?; + m.implement_trait::(rune::item!(::std::clone::Clone))?; + + m.function_meta(hash__meta)?; + m.function_meta(string_debug__meta)?; Ok(m) } @@ -230,7 +236,42 @@ fn cmp(this: &Tuple, other: &Tuple) -> VmResult { /// // Note: this is not guaranteed to be true forever, but it's true right now. /// assert_eq!(hash((0, 2, 3)), hash([0, 2, 3])); /// ``` -#[rune::function(instance, protocol = HASH)] +#[rune::function(keep, instance, protocol = HASH)] fn hash(this: &Tuple, hasher: &mut Hasher) -> VmResult<()> { Tuple::hash_with(this, hasher, &mut EnvProtocolCaller) } + +/// Clone a tuple. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::hash; +/// +/// let a = (0, 2, 3); +/// let b = a; +/// let c = a.clone(); +/// +/// c.0 = 1; +/// +/// assert_eq!(a, (0, 2, 3)); +/// assert_eq!(c, (1, 2, 3)); +/// ``` +#[rune::function(keep, instance, protocol = CLONE)] +fn clone(this: &Tuple) -> VmResult { + VmResult::Ok(vm_try!(this.clone_with(&mut EnvProtocolCaller))) +} + +/// Write a debug representation of a tuple. +/// +/// # Examples +/// +/// ```rune +/// let a = (1, 2, 3); +/// println!("{a:?}"); +/// ``` +#[rune::function(keep, instance, protocol = STRING_DEBUG)] +#[inline] +fn string_debug(this: &Tuple, f: &mut Formatter) -> VmResult<()> { + this.string_debug_with(f, &mut EnvProtocolCaller) +} diff --git a/crates/rune/src/runtime/any_obj.rs b/crates/rune/src/runtime/any_obj.rs index c01d9cf76..2b56e6833 100644 --- a/crates/rune/src/runtime/any_obj.rs +++ b/crates/rune/src/runtime/any_obj.rs @@ -379,7 +379,7 @@ impl AnyObj { unsafe { let guard = self.shared.as_ref().access.shared()?; let data = vtable.as_ptr(self.shared); - Ok(BorrowRef::new(data, guard)) + Ok(BorrowRef::new(data, guard.into_raw())) } } @@ -404,7 +404,7 @@ impl AnyObj { unsafe { let guard = self.shared.as_ref().access.shared()?; let data = vtable.as_ptr(self.shared); - Ok(Some(BorrowRef::new(data, guard))) + Ok(Some(BorrowRef::new(data, guard.into_raw()))) } } @@ -433,7 +433,7 @@ impl AnyObj { unsafe { let guard = self.shared.as_ref().access.exclusive()?; let data = vtable.as_ptr(self.shared); - Ok(BorrowMut::new(data, guard)) + Ok(BorrowMut::new(data, guard.into_raw())) } } diff --git a/crates/rune/src/runtime/borrow_mut.rs b/crates/rune/src/runtime/borrow_mut.rs index f9a178a2b..05f5e6f76 100644 --- a/crates/rune/src/runtime/borrow_mut.rs +++ b/crates/rune/src/runtime/borrow_mut.rs @@ -6,7 +6,7 @@ use core::pin::Pin; use core::ptr::NonNull; use core::task::{Context, Poll}; -use super::AccessGuard; +use super::RawAccessGuard; /// Guard for data exclusively borrowed from a slot in the virtual machine. /// @@ -14,11 +14,20 @@ use super::AccessGuard; /// access depending on what we do. Releasing the guard releases the access. pub struct BorrowMut<'a, T: ?Sized> { data: NonNull, - guard: AccessGuard<'a>, + guard: Option, _marker: PhantomData<&'a mut T>, } impl<'a, T: ?Sized> BorrowMut<'a, T> { + /// Construct a borrow mut from static data. + pub(crate) fn from_static(data: &mut T) -> Self { + Self { + data: NonNull::from(data), + guard: None, + _marker: PhantomData, + } + } + /// Construct a new exclusive guard. /// /// # Safety @@ -27,10 +36,10 @@ impl<'a, T: ?Sized> BorrowMut<'a, T> { /// ensure that access has been acquired correctly using e.g. /// [Access::exclusive]. Otherwise access can be release incorrectly once /// this guard is dropped. - pub(crate) unsafe fn new(data: NonNull, guard: AccessGuard<'a>) -> Self { + pub(crate) unsafe fn new(data: NonNull, guard: RawAccessGuard) -> Self { Self { data, - guard, + guard: Some(guard), _marker: PhantomData, } } diff --git a/crates/rune/src/runtime/borrow_ref.rs b/crates/rune/src/runtime/borrow_ref.rs index ec8af8385..7c20daa8e 100644 --- a/crates/rune/src/runtime/borrow_ref.rs +++ b/crates/rune/src/runtime/borrow_ref.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::ops::Deref; use core::ptr::NonNull; -use super::AccessGuard; +use super::RawAccessGuard; /// Guard for a data borrowed from a slot in the virtual machine. /// @@ -11,11 +11,20 @@ use super::AccessGuard; /// access depending on what we do. Releasing the guard releases the access. pub struct BorrowRef<'a, T: ?Sized + 'a> { data: NonNull, - guard: AccessGuard<'a>, + guard: Option, _marker: PhantomData<&'a T>, } impl<'a, T: ?Sized> BorrowRef<'a, T> { + /// Construct a borrow ref from static data. + pub(crate) fn from_static(data: &'static T) -> Self { + Self { + data: NonNull::from(data), + guard: None, + _marker: PhantomData, + } + } + /// Construct a new shared guard. /// /// # Safety @@ -24,10 +33,10 @@ impl<'a, T: ?Sized> BorrowRef<'a, T> { /// ensure that access has been acquired correctly using e.g. /// [Access::shared]. Otherwise access can be release incorrectly once /// this guard is dropped. - pub(crate) unsafe fn new(data: NonNull, guard: AccessGuard<'a>) -> Self { + pub(crate) unsafe fn new(data: NonNull, guard: RawAccessGuard) -> Self { Self { data, - guard, + guard: Some(guard), _marker: PhantomData, } } diff --git a/crates/rune/src/runtime/const_value.rs b/crates/rune/src/runtime/const_value.rs index a17f905e2..5fbff5d74 100644 --- a/crates/rune/src/runtime/const_value.rs +++ b/crates/rune/src/runtime/const_value.rs @@ -16,8 +16,8 @@ use crate::runtime; use crate::{Hash, TypeHash}; use super::{ - BorrowRefRepr, Bytes, FromValue, Inline, Mutable, Object, OwnedTuple, ToValue, Tuple, Type, - TypeInfo, Value, VmErrorKind, + static_type, BorrowRefRepr, Bytes, FromValue, Inline, Mutable, Object, OwnedTuple, ToValue, + Tuple, Type, TypeInfo, Value, VmErrorKind, }; /// Derive for the [`ToConstValue`](trait@ToConstValue) trait. @@ -138,9 +138,9 @@ impl ConstValueKind { ConstValueKind::String(..) => TypeInfo::any::(), ConstValueKind::Bytes(..) => TypeInfo::any::(), ConstValueKind::Vec(..) => TypeInfo::any::(), - ConstValueKind::Tuple(..) => TypeInfo::static_type(runtime::static_type::TUPLE), - ConstValueKind::Object(..) => TypeInfo::static_type(runtime::static_type::OBJECT), - ConstValueKind::Option(..) => TypeInfo::static_type(runtime::static_type::OPTION), + ConstValueKind::Tuple(..) => TypeInfo::any::(), + ConstValueKind::Object(..) => TypeInfo::static_type(static_type::OBJECT), + ConstValueKind::Option(..) => TypeInfo::static_type(static_type::OPTION), ConstValueKind::Struct(hash, ..) => { TypeInfo::any_type_info(AnyTypeInfo::new(full_name, *hash)) } @@ -241,15 +241,6 @@ impl ConstValue { Some(some) => Some(Box::try_new(Self::from_value_ref(some)?)?), None => None, }), - Mutable::Tuple(ref tuple) => { - let mut const_tuple = Vec::try_with_capacity(tuple.len())?; - - for value in tuple.iter() { - const_tuple.try_push(Self::from_value_ref(value)?)?; - } - - ConstValueKind::Tuple(const_tuple.try_into_boxed_slice()?) - } Mutable::Object(ref object) => { let mut const_object = HashMap::try_with_capacity(object.len())?; @@ -286,6 +277,16 @@ impl ConstValue { ConstValueKind::Vec(const_vec) } + runtime::OwnedTuple::HASH => { + let tuple = value.borrow_ref::()?; + let mut const_tuple = Vec::try_with_capacity(tuple.len())?; + + for value in tuple.iter() { + const_tuple.try_push(Self::from_value_ref(value)?)?; + } + + ConstValueKind::Tuple(const_tuple.try_into_boxed_slice()?) + } _ => { return Err(RuntimeError::from(VmErrorKind::ConstNotSupported { actual: value.type_info(), @@ -318,7 +319,7 @@ impl ConstValue { None => None, })?), ConstValueKind::Vec(vec) => { - let mut v = super::Vec::with_capacity(vec.len())?; + let mut v = runtime::Vec::with_capacity(vec.len())?; for value in vec { v.push(Self::to_value_with(value, cx)?)?; diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index 70ef26faf..1582b3d93 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -11,7 +11,7 @@ use self::steps_between::StepsBetween; mod access; pub use self::access::AccessError; -pub(crate) use self::access::{Access, AccessErrorKind, AccessGuard, RawAccessGuard, Snapshot}; +pub(crate) use self::access::{Access, AccessErrorKind, RawAccessGuard, Snapshot}; mod borrow_mut; pub use self::borrow_mut::BorrowMut; @@ -165,7 +165,9 @@ pub(crate) use self::unit::UnitFn; pub use self::unit::{Unit, UnitStorage}; mod value; -pub(crate) use self::value::{BorrowRefRepr, MutRepr, Mutable, OwnedRepr, RefRepr, ValueShared}; +#[cfg(any(test, feature = "cli"))] +pub(crate) use self::value::OwnedRepr; +pub(crate) use self::value::{BorrowRefRepr, MutRepr, Mutable, RefRepr}; pub use self::value::{ EmptyStruct, Inline, RawValueGuard, Rtti, Struct, TupleStruct, TypeValue, Value, ValueMutGuard, ValueRefGuard, VariantRtti, diff --git a/crates/rune/src/runtime/shared.rs b/crates/rune/src/runtime/shared.rs index 8548241f2..6e6f1755c 100644 --- a/crates/rune/src/runtime/shared.rs +++ b/crates/rune/src/runtime/shared.rs @@ -128,7 +128,7 @@ impl Shared { Ok(BorrowRef::new( NonNull::new_unchecked(inner.data.get()), - guard, + guard.into_raw(), )) } } @@ -148,7 +148,7 @@ impl Shared { Ok(BorrowMut::new( NonNull::new_unchecked(inner.data.get()), - guard, + guard.into_raw(), )) } } diff --git a/crates/rune/src/runtime/static_type.rs b/crates/rune/src/runtime/static_type.rs index 8bcae6f20..3ea92086e 100644 --- a/crates/rune/src/runtime/static_type.rs +++ b/crates/rune/src/runtime/static_type.rs @@ -63,43 +63,7 @@ macro_rules! any_type { $( $( $(#[$($impl_meta)*])* - impl $(<$($p,)*>)* $crate::TypeHash for $ty { - const HASH: $crate::Hash = ::rune_macros::hash!($path); - } - - $(#[$($impl_meta)*])* - impl $(<$($p,)*>)* $crate::runtime::TypeOf for $ty - where - $( - $($p: $crate::runtime::MaybeTypeOf,)* - )* - { - const STATIC_TYPE_INFO: $crate::runtime::StaticTypeInfo = $crate::runtime::StaticTypeInfo::any_type_info( - $crate::runtime::AnyTypeInfo::new( - { - fn full_name(f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "{}", ::rune_macros::item!($path)) - } - - full_name - }, - ::HASH, - ) - ); - } - - $(#[$($impl_meta)*])* - impl $(<$($p,)*>)* $crate::runtime::MaybeTypeOf for $ty - where - $( - $($p: $crate::runtime::MaybeTypeOf,)* - )* - { - #[inline] - fn maybe_type_of() -> $crate::alloc::Result<$crate::compile::meta::DocType> { - Ok($crate::compile::meta::DocType::new(<$ty as $crate::TypeHash>::HASH)) - } - } + impl_any_type!(impl $(<$($p),*>)* for $ty, $path); )* )* } @@ -203,14 +167,14 @@ any_type! { impl for alloc::Vec; impl for rt::VecTuple; } -} -static_type! { /// The specialized type information for the [`Tuple`] type. - pub(crate) static [TUPLE, TUPLE_HASH] = ::std::tuple::Tuple { - impl for rt::OwnedTuple; + ::std::tuple::Tuple { + impl for rt::Tuple; } +} +static_type! { /// The specialized type information for the [`Object`] type. pub(crate) static [OBJECT, OBJECT_HASH] = ::std::object::Object { impl for rt::Struct; diff --git a/crates/rune/src/runtime/tests.rs b/crates/rune/src/runtime/tests.rs index 608747a32..e1723d7a1 100644 --- a/crates/rune/src/runtime/tests.rs +++ b/crates/rune/src/runtime/tests.rs @@ -13,7 +13,7 @@ use crate::alloc::prelude::*; use crate::support::Result; use crate::Any; -use super::{Access, AnyObj, Bytes, Mut, Ref, Shared, TypeHash, Value, VmResult}; +use super::{Access, AnyObj, Bytes, Mut, Ref, Shared, Tuple, TypeHash, Value, VmResult}; #[derive(Debug, PartialEq, Eq, Any)] struct Thing(u32); @@ -554,3 +554,11 @@ fn test_clone_issue() { out }; } + +#[test] +fn test_drop_boxed_tuple() { + let boxed = + crate::alloc::Box::<[Value]>::try_from([Value::from(1u32), Value::from(2u64)]).unwrap(); + let boxed = Tuple::from_boxed(boxed); + drop(boxed); +} diff --git a/crates/rune/src/runtime/tuple.rs b/crates/rune/src/runtime/tuple.rs index 9e8b6b200..e37fa160b 100644 --- a/crates/rune/src/runtime/tuple.rs +++ b/crates/rune/src/runtime/tuple.rs @@ -1,24 +1,24 @@ +use core::borrow::Borrow; use core::fmt; -use core::ops; +use core::ops::{self, Deref, DerefMut}; use core::slice; use crate as rune; +use crate::alloc::alloc::Global; +use crate::alloc::borrow::TryToOwned; use crate::alloc::clone::TryClone; +use crate::alloc::fmt::TryWrite; use crate::alloc::{self, Box}; use crate::Any; use super::{ - ConstValue, EmptyConstContext, FromConstValue, FromValue, Inline, Mut, Mutable, OwnedRepr, - RawAnyGuard, Ref, RuntimeError, ToConstValue, ToValue, UnsafeToMut, UnsafeToRef, Value, - ValueShared, VmErrorKind, VmResult, + ConstValue, EmptyConstContext, Formatter, FromConstValue, FromValue, Mut, RawAnyGuard, Ref, + RuntimeError, ToConstValue, ToValue, UnsafeToMut, UnsafeToRef, Value, VmErrorKind, VmResult, }; #[cfg(feature = "alloc")] use super::{Hasher, ProtocolCaller}; /// The type of a tuple slice. -#[derive(Any)] -#[rune(builtin, static_type = TUPLE)] -#[rune(item = ::std::tuple)] #[repr(transparent)] pub struct Tuple { values: [Value], @@ -31,6 +31,13 @@ impl Tuple { unsafe { &*(values as *const _ as *const Self) } } + /// Construct a boxed tuple over a boxed slice of values. + pub(crate) fn from_boxed(boxed: Box<[Value]>) -> Box { + let (values, Global) = Box::into_raw_with_allocator(boxed); + // SAFETY: Tuple is repr transparent over [Value]. + unsafe { Box::from_raw_in(values as *mut Tuple, Global) } + } + /// Construct a new tuple slice from a mutable reference. pub fn new_mut(values: &mut [Value]) -> &mut Self { // SAFETY: Tuple is repr transparent over [Value]. @@ -61,6 +68,37 @@ impl Tuple { VmResult::Ok(()) } + + pub(crate) fn string_debug_with( + &self, + f: &mut Formatter, + caller: &mut dyn ProtocolCaller, + ) -> VmResult<()> { + let mut it = self.iter().peekable(); + vm_try!(vm_write!(f, "(")); + + while let Some(value) = it.next() { + vm_try!(value.string_debug_with(f, caller)); + + if it.peek().is_some() { + vm_try!(vm_write!(f, ", ")); + } + } + + vm_try!(vm_write!(f, ")")); + VmResult::Ok(()) + } + + pub(crate) fn clone_with(&self, caller: &mut dyn ProtocolCaller) -> VmResult { + let mut vec = vm_try!(alloc::Vec::try_with_capacity(self.len())); + + for value in self.values.iter() { + let value = vm_try!(value.clone_with(caller)); + vm_try!(vec.try_push(value)); + } + + VmResult::Ok(vm_try!(OwnedTuple::try_from(vec))) + } } impl ops::Deref for Tuple { @@ -102,6 +140,8 @@ impl<'a> IntoIterator for &'a mut Tuple { /// Struct representing a dynamic anonymous object. /// /// To access borrowed values of a tuple in native functions, use [`Tuple`]. +#[derive(Any)] +#[rune(item = ::std::tuple, name = Tuple)] #[repr(transparent)] pub struct OwnedTuple { inner: Box<[Value]>, @@ -123,12 +163,54 @@ impl OwnedTuple { } } + /// Coerce this owned tuple into a boxed tuple. + pub fn into_boxed_tuple(self) -> Box { + Tuple::from_boxed(self.inner) + } + /// Convert into inner std boxed slice. pub fn into_inner(self) -> Box<[Value]> { self.inner } } +impl Deref for OwnedTuple { + type Target = Tuple; + + #[inline] + fn deref(&self) -> &Self::Target { + Tuple::new(&self.inner) + } +} + +impl DerefMut for OwnedTuple { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + Tuple::new_mut(&mut self.inner) + } +} + +impl AsRef for OwnedTuple { + #[inline] + fn as_ref(&self) -> &Tuple { + self + } +} + +impl AsMut for OwnedTuple { + #[inline] + fn as_mut(&mut self) -> &mut Tuple { + self + } +} + +impl Borrow for OwnedTuple { + #[inline] + fn borrow(&self) -> &Tuple { + self + } +} + impl Default for OwnedTuple { fn default() -> Self { Self::new() @@ -169,22 +251,6 @@ impl fmt::Debug for OwnedTuple { } } -impl ops::Deref for OwnedTuple { - type Target = Tuple; - - #[inline] - fn deref(&self) -> &Self::Target { - Tuple::new(&self.inner) - } -} - -impl ops::DerefMut for OwnedTuple { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - Tuple::new_mut(&mut self.inner) - } -} - #[cfg(feature = "alloc")] impl TryFrom<::rust_alloc::vec::Vec> for OwnedTuple { type Error = alloc::Error; @@ -279,20 +345,10 @@ impl TryFrom<::rust_alloc::boxed::Box<[ConstValue]>> for OwnedTuple { } } -impl FromValue for OwnedTuple { - fn from_value(value: Value) -> Result { - match value.take_repr()? { - OwnedRepr::Inline(Inline::Unit) => Ok(Self::new()), - OwnedRepr::Mutable(Mutable::Tuple(tuple)) => Ok(tuple), - value => Err(RuntimeError::expected::(value.type_info())), - } - } -} - macro_rules! impl_tuple { // Skip conflicting implementation with `()`. (0) => { - impl_static_type!(impl for (), TUPLE, TUPLE_HASH); + impl_any_type!(impl for (), ::std::tuple::Tuple); impl FromValue for () { #[inline] @@ -310,7 +366,7 @@ macro_rules! impl_tuple { }; ($count:expr $(, $ty:ident $var:ident $ignore_count:expr)*) => { - impl_static_type!(impl <$($ty),*> for ($($ty,)*), TUPLE, TUPLE_HASH); + impl_any_type!(impl <$($ty),*> for ($($ty,)*), ::std::tuple::Tuple); impl <$($ty,)*> FromValue for ($($ty,)*) where @@ -383,63 +439,24 @@ macro_rules! impl_tuple { repeat_macro!(impl_tuple); -impl FromValue for Ref { +impl FromValue for Box { + #[inline] fn from_value(value: Value) -> Result { - let result = match value.into_value_shared()? { - ValueShared::Inline(value) => match value { - Inline::Unit => Ok(Ref::from_static(Tuple::new(&[]))), - actual => Err(actual.type_info()), - }, - ValueShared::Mutable(value) => { - let value = value.into_ref()?; - - let result = Ref::try_map(value, |value| match value { - Mutable::Tuple(tuple) => Some(&**tuple), - _ => None, - }); - - match result { - Ok(tuple) => Ok(tuple), - Err(actual) => Err(actual.type_info()), - } - } - ValueShared::Any(value) => Err(value.type_info()), - }; + value.into_tuple() + } +} - match result { - Ok(tuple) => Ok(tuple), - Err(actual) => Err(RuntimeError::expected::(actual)), - } +impl FromValue for Ref { + #[inline] + fn from_value(value: Value) -> Result { + value.into_tuple_ref() } } impl FromValue for Mut { + #[inline] fn from_value(value: Value) -> Result { - let result = match value.into_value_shared()? { - ValueShared::Inline(value) => match value { - Inline::Unit => Ok(Mut::from_static(Tuple::new_mut(&mut []))), - actual => Err(actual.type_info()), - }, - ValueShared::Mutable(value) => { - let value = value.into_mut()?; - - let result = Mut::try_map(value, |kind| match kind { - Mutable::Tuple(tuple) => Some(&mut **tuple), - _ => None, - }); - - match result { - Ok(value) => Ok(value), - Err(actual) => Err(actual.type_info()), - } - } - ValueShared::Any(value) => Err(value.type_info()), - }; - - match result { - Ok(tuple) => Ok(tuple), - Err(actual) => Err(RuntimeError::expected::(actual)), - } + value.into_tuple_mut() } } @@ -460,3 +477,18 @@ impl UnsafeToMut for Tuple { VmResult::Ok((value.as_mut(), guard)) } } + +impl TryToOwned for Tuple { + type Owned = OwnedTuple; + + #[inline] + fn try_to_owned(&self) -> alloc::Result { + let mut vec = alloc::Vec::try_with_capacity(self.len())?; + + for value in self.iter() { + vec.try_push(value.clone())?; + } + + OwnedTuple::try_from(vec) + } +} diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 68f90faee..9ebbb6241 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -136,12 +136,6 @@ impl<'a> BorrowRefRepr<'a> { } } -pub(crate) enum ValueShared { - Inline(Inline), - Mutable(Shared), - Any(AnyObj), -} - /// An entry on the stack. pub struct Value { repr: Repr, @@ -428,7 +422,6 @@ impl Value { }); } RefRepr::Mutable(value) => match &*vm_try!(value.borrow_ref()) { - Mutable::Tuple(value) => Mutable::Tuple(vm_try!(value.try_clone())), Mutable::Object(value) => Mutable::Object(vm_try!(value.try_clone())), Mutable::Stream(value) => Mutable::Stream(vm_try!(value.try_clone())), Mutable::Generator(value) => Mutable::Generator(vm_try!(value.try_clone())), @@ -497,9 +490,6 @@ impl Value { }; match &*vm_try!(value.borrow_ref()) { - Mutable::Tuple(value) => { - vm_try!(vm_write!(f, "{value:?}")); - } Mutable::Object(value) => { vm_try!(vm_write!(f, "{value:?}")); } @@ -730,7 +720,6 @@ impl Value { value => Ok(TypeValue::NotTypedInline(NotTypedInlineValue(value))), }, OwnedRepr::Mutable(value) => match value { - Mutable::Tuple(tuple) => Ok(TypeValue::Tuple(tuple)), Mutable::Object(object) => Ok(TypeValue::Object(object)), Mutable::EmptyStruct(empty) => Ok(TypeValue::EmptyStruct(empty)), Mutable::TupleStruct(tuple) => Ok(TypeValue::TupleStruct(tuple)), @@ -738,7 +727,10 @@ impl Value { Mutable::Variant(object) => Ok(TypeValue::Variant(object)), value => Ok(TypeValue::NotTypedMutable(NotTypedMutableValue(value))), }, - OwnedRepr::Any(value) => Ok(TypeValue::NotTypedRef(NotTypedRefValue(value))), + OwnedRepr::Any(value) => match value.type_hash() { + OwnedTuple::HASH => Ok(TypeValue::Tuple(value.downcast()?)), + _ => Ok(TypeValue::NotTypedRef(NotTypedRefValue(value))), + }, } } @@ -840,16 +832,6 @@ impl Value { into_generator, } - into! { - /// Coerce into [`Tuple`]. - Tuple(OwnedTuple), - into_tuple_ref, - into_tuple_mut, - borrow_tuple_ref, - borrow_tuple_mut, - into_tuple, - } - into! { /// Coerce into [`Struct`] Struct(Struct), @@ -889,6 +871,102 @@ impl Value { borrow_future_mut, } + /// Borrow as a tuple. + /// + /// This ensures that the value has read access to the underlying value + /// and does not consume it. + #[inline] + pub fn borrow_tuple_ref(&self) -> Result, RuntimeError> { + match self.as_ref_repr()? { + RefRepr::Inline(Inline::Unit) => Ok(BorrowRef::from_static(Tuple::new(&[]))), + RefRepr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + RefRepr::Mutable(value) => Err(RuntimeError::expected::( + value.borrow_ref()?.type_info(), + )), + RefRepr::Any(value) => { + let value = value.borrow_ref::()?; + let value = BorrowRef::map(value, OwnedTuple::as_ref); + Ok(value) + } + } + } + + /// Borrow as a tuple as mutable. + /// + /// This ensures that the value has write access to the underlying value and + /// does not consume it. + #[inline] + pub fn borrow_tuple_mut(&self) -> Result, RuntimeError> { + match self.as_ref_repr()? { + RefRepr::Inline(Inline::Unit) => Ok(BorrowMut::from_static(Tuple::new_mut(&mut []))), + RefRepr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + RefRepr::Mutable(value) => Err(RuntimeError::expected::( + value.borrow_ref()?.type_info(), + )), + RefRepr::Any(value) => { + let value = value.borrow_mut::()?; + let value = BorrowMut::map(value, OwnedTuple::as_mut); + Ok(value) + } + } + } + + /// Borrow as an owned tuple reference. + /// + /// This ensures that the value has read access to the underlying value and + /// does not consume it. + #[inline] + pub fn into_tuple(&self) -> Result, RuntimeError> { + match self.as_ref_repr()? { + RefRepr::Inline(Inline::Unit) => Ok(Tuple::from_boxed(Box::default())), + RefRepr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + RefRepr::Mutable(value) => Err(RuntimeError::expected::( + value.borrow_ref()?.type_info(), + )), + RefRepr::Any(value) => Ok(value.clone().downcast::()?.into_boxed_tuple()), + } + } + + /// Borrow as an owned tuple reference. + /// + /// This ensures that the value has read access to the underlying value and + /// does not consume it. + #[inline] + pub fn into_tuple_ref(&self) -> Result, RuntimeError> { + match self.as_ref_repr()? { + RefRepr::Inline(Inline::Unit) => Ok(Ref::from_static(Tuple::new(&[]))), + RefRepr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + RefRepr::Mutable(value) => Err(RuntimeError::expected::( + value.borrow_ref()?.type_info(), + )), + RefRepr::Any(value) => { + let value = value.clone().into_ref::()?; + let value = Ref::map(value, OwnedTuple::as_ref); + Ok(value) + } + } + } + + /// Borrow as an owned tuple mutable. + /// + /// This ensures that the value has write access to the underlying value and + /// does not consume it. + #[inline] + pub fn into_tuple_mut(&self) -> Result, RuntimeError> { + match self.as_ref_repr()? { + RefRepr::Inline(Inline::Unit) => Ok(Mut::from_static(Tuple::new_mut(&mut []))), + RefRepr::Inline(value) => Err(RuntimeError::expected::(value.type_info())), + RefRepr::Mutable(value) => Err(RuntimeError::expected::( + value.borrow_ref()?.type_info(), + )), + RefRepr::Any(value) => { + let value = value.clone().into_mut::()?; + let value = Mut::map(value, OwnedTuple::as_mut); + Ok(value) + } + } + } + /// Coerce into an [`AnyObj`]. /// /// This consumes the underlying value. @@ -1111,100 +1189,76 @@ impl Value { b: &Value, caller: &mut dyn ProtocolCaller, ) -> VmResult { - 'fallback: { - let a = 'mutable: { - match (vm_try!(self.as_ref_repr()), vm_try!(b.borrow_ref_repr())) { - (RefRepr::Inline(a), BorrowRefRepr::Inline(b)) => { - return VmResult::Ok(vm_try!(a.partial_eq(b))); - } - (RefRepr::Inline(a), b) => { - return err(VmErrorKind::UnsupportedBinaryOperation { - op: Protocol::PARTIAL_EQ.name, - lhs: a.type_info(), - rhs: b.type_info(), - }); + match (vm_try!(self.as_ref_repr()), vm_try!(b.borrow_ref_repr())) { + (RefRepr::Inline(a), BorrowRefRepr::Inline(b)) => { + return VmResult::Ok(vm_try!(a.partial_eq(b))); + } + (RefRepr::Inline(a), b) => { + return err(VmErrorKind::UnsupportedBinaryOperation { + op: Protocol::PARTIAL_EQ.name, + lhs: a.type_info(), + rhs: b.type_info(), + }); + } + (RefRepr::Mutable(a), BorrowRefRepr::Mutable(b)) => { + let a = vm_try!(a.borrow_ref()); + + match (&*a, &*b) { + (Mutable::EmptyStruct(a), Mutable::EmptyStruct(b)) => { + if a.rtti.hash == b.rtti.hash { + // NB: don't get any future ideas, this must fall through to + // the VmError below since it's otherwise a comparison + // between two incompatible types. + // + // Other than that, all units are equal. + return VmResult::Ok(true); + } } - (RefRepr::Mutable(a), BorrowRefRepr::Mutable(b)) => { - let a = vm_try!(a.borrow_ref()); - - match (&*a, &*b) { - (Mutable::EmptyStruct(a), Mutable::EmptyStruct(b)) => { - if a.rtti.hash == b.rtti.hash { - // NB: don't get any future ideas, this must fall through to - // the VmError below since it's otherwise a comparison - // between two incompatible types. - // - // Other than that, all units are equal. - return VmResult::Ok(true); - } - - break 'fallback; - } - (Mutable::TupleStruct(a), Mutable::TupleStruct(b)) => { - if a.rtti.hash == b.rtti.hash { - return Vec::eq_with( - &a.data, - &b.data, - Value::partial_eq_with, - caller, - ); - } - - break 'fallback; - } - (Mutable::Struct(a), Mutable::Struct(b)) => { - if a.rtti.hash == b.rtti.hash { - return Object::eq_with( - &a.data, - &b.data, - Value::partial_eq_with, - caller, - ); - } - - break 'fallback; - } - (Mutable::Variant(a), Mutable::Variant(b)) => { - if a.rtti().enum_hash == b.rtti().enum_hash { - return Variant::partial_eq_with(a, b, caller); - } - - break 'fallback; - } - (Mutable::Option(a), Mutable::Option(b)) => match (a, b) { - (Some(a), Some(b)) => return Value::partial_eq_with(a, b, caller), - (None, None) => return VmResult::Ok(true), - _ => return VmResult::Ok(false), - }, - (Mutable::Result(a), Mutable::Result(b)) => match (a, b) { - (Ok(a), Ok(b)) => return Value::partial_eq_with(a, b, caller), - (Err(a), Err(b)) => return Value::partial_eq_with(a, b, caller), - _ => return VmResult::Ok(false), - }, - _ => {} + (Mutable::TupleStruct(a), Mutable::TupleStruct(b)) => { + if a.rtti.hash == b.rtti.hash { + return Vec::eq_with(&a.data, &b.data, Value::partial_eq_with, caller); } - - break 'mutable a; } - (RefRepr::Any(value), _) => match value.type_hash() { - runtime::Vec::HASH => { - let vec = vm_try!(value.borrow_ref::()); - return Vec::partial_eq_with(&vec, b.clone(), caller); + (Mutable::Struct(a), Mutable::Struct(b)) => { + if a.rtti.hash == b.rtti.hash { + return Object::eq_with( + &a.data, + &b.data, + Value::partial_eq_with, + caller, + ); } - _ => { - break 'fallback; + } + (Mutable::Variant(a), Mutable::Variant(b)) => { + if a.rtti().enum_hash == b.rtti().enum_hash { + return Variant::partial_eq_with(a, b, caller); } - }, - _ => { - break 'fallback; } + (Mutable::Option(a), Mutable::Option(b)) => match (a, b) { + (Some(a), Some(b)) => return Value::partial_eq_with(a, b, caller), + (None, None) => return VmResult::Ok(true), + _ => return VmResult::Ok(false), + }, + (Mutable::Result(a), Mutable::Result(b)) => match (a, b) { + (Ok(a), Ok(b)) => return Value::partial_eq_with(a, b, caller), + (Err(a), Err(b)) => return Value::partial_eq_with(a, b, caller), + _ => return VmResult::Ok(false), + }, + _ => {} } - }; - - // Special cases. - if let Mutable::Tuple(a) = &*a { - return Vec::partial_eq_with(a, b.clone(), caller); } + (RefRepr::Any(value), _) => match value.type_hash() { + runtime::Vec::HASH => { + let vec = vm_try!(value.borrow_ref::()); + return Vec::partial_eq_with(&vec, b.clone(), caller); + } + runtime::OwnedTuple::HASH => { + let tuple = vm_try!(value.borrow_ref::()); + return Vec::partial_eq_with(&tuple, b.clone(), caller); + } + _ => {} + }, + _ => {} } if let CallResultOnly::Ok(value) = vm_try!(caller.try_call_protocol_fn( @@ -1235,8 +1289,8 @@ impl Value { hasher: &mut Hasher, caller: &mut dyn ProtocolCaller, ) -> VmResult<()> { - match vm_try!(self.borrow_ref_repr()) { - BorrowRefRepr::Inline(value) => match value { + match vm_try!(self.as_ref_repr()) { + RefRepr::Inline(value) => match value { Inline::Unsigned(value) => { hasher.write_u64(*value); return VmResult::Ok(()); @@ -1264,15 +1318,17 @@ impl Value { }); } }, - BorrowRefRepr::Mutable(value) => { - if let Mutable::Tuple(tuple) = &*value { - return Tuple::hash_with(tuple, hasher, caller); + RefRepr::Any(value) => match value.type_hash() { + Vec::HASH => { + let vec = vm_try!(value.borrow_ref::()); + return Vec::hash_with(&vec, hasher, caller); } - } - BorrowRefRepr::Any(value) if value.type_hash() == runtime::Vec::HASH => { - let vec = vm_try!(value.borrow_ref::()); - return Vec::hash_with(&vec, hasher, caller); - } + OwnedTuple::HASH => { + let tuple = vm_try!(value.borrow_ref::()); + return Tuple::hash_with(&tuple, hasher, caller); + } + _ => {} + }, _ => {} } @@ -1324,9 +1380,6 @@ impl Value { }); } (BorrowRefRepr::Mutable(a), BorrowRefRepr::Mutable(b)) => match (&*a, &*b) { - (Mutable::Tuple(a), Mutable::Tuple(b)) => { - return Vec::eq_with(a, b, Value::eq_with, caller); - } (Mutable::Object(a), Mutable::Object(b)) => { return Object::eq_with(a, b, Value::eq_with, caller); } @@ -1423,9 +1476,6 @@ impl Value { }) } (BorrowRefRepr::Mutable(a), BorrowRefRepr::Mutable(b)) => match (&*a, &*b) { - (Mutable::Tuple(a), Mutable::Tuple(b)) => { - return Vec::partial_cmp_with(a, b, caller); - } (Mutable::Object(a), Mutable::Object(b)) => { return Object::partial_cmp_with(a, b, caller); } @@ -1515,9 +1565,6 @@ impl Value { ) { (BorrowRefRepr::Inline(a), BorrowRefRepr::Inline(b)) => return a.cmp(b), (BorrowRefRepr::Mutable(a), BorrowRefRepr::Mutable(b)) => match (&*a, &*b) { - (Mutable::Tuple(a), Mutable::Tuple(b)) => { - return Vec::cmp_with(a, b, caller); - } (Mutable::Object(a), Mutable::Object(b)) => { return Object::cmp_with(a, b, caller); } @@ -1706,15 +1753,6 @@ impl Value { } } - pub(crate) fn into_value_shared(self) -> Result { - match self.repr { - Repr::Empty => Err(AccessError::empty()), - Repr::Inline(value) => Ok(ValueShared::Inline(value)), - Repr::Mutable(value) => Ok(ValueShared::Mutable(value)), - Repr::Any(value) => Ok(ValueShared::Any(value)), - } - } - pub(crate) fn protocol_into_iter(&self) -> VmResult { EnvProtocolCaller.call_protocol_fn(Protocol::INTO_ITER, self.clone(), &mut ()) } @@ -1902,7 +1940,6 @@ from! { Struct => Struct, Variant => Variant, Object => Object, - Tuple => OwnedTuple, Generator => Generator, Future => Future, Stream => Stream, @@ -1915,6 +1952,7 @@ any_from! { super::ControlFlow, super::GeneratorState, super::Vec, + super::OwnedTuple, } from_container! { @@ -1922,6 +1960,10 @@ from_container! { Result => Result, } +signed_value_from!(i8, i16, i32); +signed_value_try_from!(i128, isize); +unsigned_value_from!(u8, u16, u32); +unsigned_value_try_from!(u128, usize); signed_value_trait!(i8, i16, i32, i128, isize); unsigned_value_trait!(u8, u16, u32, u128, usize); float_value_trait!(f32); @@ -2019,8 +2061,8 @@ impl TypeValue { #[doc(hidden)] pub fn type_info(&self) -> TypeInfo { match self { - TypeValue::Unit => TypeInfo::static_type(static_type::TUPLE), - TypeValue::Tuple(..) => TypeInfo::static_type(static_type::TUPLE), + TypeValue::Unit => TypeInfo::any::(), + TypeValue::Tuple(..) => TypeInfo::any::(), TypeValue::Object(..) => TypeInfo::static_type(static_type::OBJECT), TypeValue::EmptyStruct(empty) => empty.type_info(), TypeValue::TupleStruct(tuple) => tuple.type_info(), @@ -2034,8 +2076,6 @@ impl TypeValue { } pub(crate) enum Mutable { - /// A tuple. - Tuple(OwnedTuple), /// An object. Object(Object), /// A stored future. @@ -2063,7 +2103,6 @@ pub(crate) enum Mutable { impl Mutable { pub(crate) fn type_info(&self) -> TypeInfo { match self { - Mutable::Tuple(..) => TypeInfo::static_type(static_type::TUPLE), Mutable::Object(..) => TypeInfo::static_type(static_type::OBJECT), Mutable::Future(..) => TypeInfo::static_type(static_type::FUTURE), Mutable::Stream(..) => TypeInfo::static_type(static_type::STREAM), @@ -2084,7 +2123,6 @@ impl Mutable { /// *enum*, and not the type hash of the variant itself. pub(crate) fn type_hash(&self) -> Hash { match self { - Mutable::Tuple(..) => static_type::TUPLE.hash, Mutable::Object(..) => static_type::OBJECT.hash, Mutable::Future(..) => static_type::FUTURE.hash, Mutable::Stream(..) => static_type::STREAM.hash, diff --git a/crates/rune/src/runtime/value/inline.rs b/crates/rune/src/runtime/value/inline.rs index e79d463aa..796a3051f 100644 --- a/crates/rune/src/runtime/value/inline.rs +++ b/crates/rune/src/runtime/value/inline.rs @@ -7,7 +7,8 @@ use serde::{Deserialize, Serialize}; use crate::hash::Hash; use crate::runtime::{ - static_type, Protocol, RuntimeError, Type, TypeInfo, VmErrorKind, VmIntegerRepr, VmResult, + static_type, OwnedTuple, Protocol, RuntimeError, Type, TypeInfo, VmErrorKind, VmIntegerRepr, + VmResult, }; use crate::TypeHash; @@ -190,7 +191,7 @@ impl fmt::Debug for Inline { impl Inline { pub(crate) fn type_info(&self) -> TypeInfo { match self { - Inline::Unit => TypeInfo::static_type(static_type::TUPLE), + Inline::Unit => TypeInfo::any::(), Inline::Bool(..) => TypeInfo::named::(), Inline::Char(..) => TypeInfo::named::(), Inline::Unsigned(..) => TypeInfo::named::(), @@ -207,7 +208,7 @@ impl Inline { /// *enum*, and not the type hash of the variant itself. pub(crate) fn type_hash(&self) -> Hash { match self { - Inline::Unit => static_type::TUPLE.hash, + Inline::Unit => OwnedTuple::HASH, Inline::Bool(..) => bool::HASH, Inline::Char(..) => char::HASH, Inline::Signed(..) => i64::HASH, diff --git a/crates/rune/src/runtime/value/macros.rs b/crates/rune/src/runtime/value/macros.rs index 272c641bb..51f74870b 100644 --- a/crates/rune/src/runtime/value/macros.rs +++ b/crates/rune/src/runtime/value/macros.rs @@ -385,13 +385,48 @@ macro_rules! from_container { macro_rules! signed_value_trait { ($($ty:ty),* $(,)?) => { $( + #[allow(clippy::needless_question_mark)] impl $crate::runtime::ToValue for $ty { #[inline] fn to_value(self) -> Result { - Value::try_from(self) + Ok($crate::runtime::Value::try_from(self)?) + } + } + + #[allow(clippy::needless_question_mark)] + impl $crate::runtime::ToConstValue for $ty { + #[inline] + fn to_const_value(self) -> Result<$crate::runtime::ConstValue, $crate::runtime::RuntimeError> { + Ok($crate::runtime::ConstValue::try_from(self)?) + } + } + )* + }; +} + +macro_rules! signed_value_from { + ($($ty:ty),* $(,)?) => { + $( + impl From<$ty> for $crate::runtime::Value { + #[inline] + fn from(number: $ty) -> Self { + $crate::runtime::Value::from(number as i64) } } + impl From<$ty> for $crate::runtime::ConstValue { + #[inline] + fn from(number: $ty) -> Self { + $crate::runtime::ConstValue::from(number as i64) + } + } + )* + } +} + +macro_rules! signed_value_try_from { + ($($ty:ty),* $(,)?) => { + $( impl TryFrom<$ty> for Value { type Error = $crate::runtime::RuntimeError; @@ -408,13 +443,6 @@ macro_rules! signed_value_trait { } } - impl $crate::runtime::ToConstValue for $ty { - #[inline] - fn to_const_value(self) -> Result<$crate::runtime::ConstValue, $crate::runtime::RuntimeError> { - $crate::runtime::ConstValue::try_from(self) - } - } - impl TryFrom<$ty> for ConstValue { type Error = $crate::runtime::RuntimeError; @@ -431,19 +459,54 @@ macro_rules! signed_value_trait { } } )* - }; + } } macro_rules! unsigned_value_trait { ($($ty:ty),* $(,)?) => { $( + #[allow(clippy::needless_question_mark)] impl $crate::runtime::ToValue for $ty { #[inline] fn to_value(self) -> Result { - Value::try_from(self) + Ok($crate::runtime::Value::try_from(self)?) + } + } + + #[allow(clippy::needless_question_mark)] + impl $crate::runtime::ToConstValue for $ty { + #[inline] + fn to_const_value(self) -> Result<$crate::runtime::ConstValue, $crate::runtime::RuntimeError> { + Ok($crate::runtime::ConstValue::try_from(self)?) + } + } + )* + }; +} + +macro_rules! unsigned_value_from { + ($($ty:ty),* $(,)?) => { + $( + impl From<$ty> for Value { + #[inline] + fn from(number: $ty) -> Self { + Value::from(number as u64) } } + impl From<$ty> for ConstValue { + #[inline] + fn from(number: $ty) -> Self { + ConstValue::from(number as u64) + } + } + )* + } +} + +macro_rules! unsigned_value_try_from { + ($($ty:ty),* $(,)?) => { + $( impl TryFrom<$ty> for Value { type Error = $crate::runtime::RuntimeError; @@ -460,13 +523,6 @@ macro_rules! unsigned_value_trait { } } - impl $crate::runtime::ToConstValue for $ty { - #[inline] - fn to_const_value(self) -> Result<$crate::runtime::ConstValue, $crate::runtime::RuntimeError> { - $crate::runtime::ConstValue::try_from(self) - } - } - impl TryFrom<$ty> for ConstValue { type Error = $crate::runtime::RuntimeError; @@ -483,7 +539,7 @@ macro_rules! unsigned_value_trait { } } )* - }; + } } macro_rules! float_value_trait { diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index 37bb220a8..0605a2c71 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -38,15 +38,6 @@ impl ser::Serialize for Value { Inline::Ordering(..) => Err(ser::Error::custom("cannot serialize orderings")), }, BorrowRefRepr::Mutable(value) => match &*value { - Mutable::Tuple(tuple) => { - let mut serializer = serializer.serialize_seq(Some(tuple.len()))?; - - for value in tuple.iter() { - serializer.serialize_element(value)?; - } - - serializer.end() - } Mutable::Object(object) => { let mut serializer = serializer.serialize_map(Some(object.len()))?; @@ -92,6 +83,18 @@ impl ser::Serialize for Value { serializer.end() } + runtime::OwnedTuple::HASH => { + let tuple = value + .borrow_ref::() + .map_err(S::Error::custom)?; + let mut serializer = serializer.serialize_seq(Some(tuple.len()))?; + + for value in tuple.iter() { + serializer.serialize_element(value)?; + } + + serializer.end() + } _ => Err(ser::Error::custom("cannot serialize external references")), }, } diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index d4a200689..a9b105e98 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -864,10 +864,6 @@ impl Vm { _ => return VmResult::Ok(None), }, BorrowRefRepr::Mutable(target) => match &*target { - Mutable::Tuple(tuple) => match tuple.get(index) { - Some(value) => Ok(value.clone()), - None => Err(target.type_info()), - }, Mutable::Result(result) => match (index, result) { (0, Ok(value)) => Ok(value.clone()), (0, Err(value)) => Ok(value.clone()), @@ -904,6 +900,14 @@ impl Vm { None => Err(target.type_info()), } } + runtime::OwnedTuple::HASH => { + let tuple = vm_try!(target.borrow_ref::()); + + match tuple.get(index) { + Some(value) => Ok(value.clone()), + None => Err(target.type_info()), + } + } _ => { return VmResult::Ok(None); } @@ -930,7 +934,6 @@ impl Vm { let result = BorrowMut::try_map(vm_try!(value.borrow_mut()), |kind| { match kind { - Mutable::Tuple(tuple) => return tuple.get_mut(index), Mutable::Result(result) => match (index, result) { (0, Ok(value)) => return Some(value), (0, Err(value)) => return Some(value), @@ -995,7 +998,20 @@ impl Vm { } err(VmErrorKind::MissingIndexInteger { - target: TypeInfo::any::(), + target: TypeInfo::any::(), + index: VmIntegerRepr::from(index), + }) + } + runtime::OwnedTuple::HASH => { + let tuple = vm_try!(value.borrow_mut::()); + let result = BorrowMut::try_map(tuple, |tuple| tuple.get_mut(index)); + + if let Ok(value) = result { + return VmResult::Ok(Some(value)); + } + + err(VmErrorKind::MissingIndexInteger { + target: TypeInfo::any::(), index: VmIntegerRepr::from(index), }) } @@ -1065,14 +1081,6 @@ impl Vm { _ => VmResult::Ok(false), }, RefRepr::Mutable(target) => match &mut *vm_try!(target.borrow_mut()) { - Mutable::Tuple(tuple) => { - if let Some(target) = tuple.get_mut(index) { - target.clone_from(from); - return VmResult::Ok(true); - } - - VmResult::Ok(false) - } Mutable::Result(result) => { let target = match result { Ok(ok) if index == 0 => ok, @@ -1123,6 +1131,16 @@ impl Vm { VmResult::Ok(false) } + runtime::OwnedTuple::HASH => { + let mut tuple = vm_try!(value.borrow_mut::()); + + if let Some(target) = tuple.get_mut(index) { + target.clone_from(from); + return VmResult::Ok(true); + } + + VmResult::Ok(false) + } _ => VmResult::Ok(false), }, } @@ -1232,7 +1250,6 @@ impl Vm { _ => None, }, BorrowRefRepr::Mutable(value) => match (ty, &*value) { - (TypeCheck::Tuple, Mutable::Tuple(tuple)) => Some(f(tuple)), (TypeCheck::Result(v), Mutable::Result(result)) => match (v, result) { (0, Ok(ok)) => Some(f(slice::from_ref(ok))), (1, Err(err)) => Some(f(slice::from_ref(err))), @@ -1250,6 +1267,10 @@ impl Vm { let vec = vm_try!(value.borrow_ref::()); Some(f(&vec)) } + (TypeCheck::Tuple, runtime::OwnedTuple::HASH) => { + let tuple = vm_try!(value.borrow_ref::()); + Some(f(&tuple)) + } _ => None, }, }; @@ -2120,11 +2141,9 @@ impl Vm { .map(take) .try_collect::>()); - vm_try!( - out.store(&mut self.stack, || VmResult::Ok(Mutable::Tuple(vm_try!( - OwnedTuple::try_from(tuple) - )))) - ); + vm_try!(out.store(&mut self.stack, || VmResult::Ok(vm_try!( + OwnedTuple::try_from(tuple) + )))); VmResult::Ok(()) } @@ -2139,11 +2158,9 @@ impl Vm { vm_try!(tuple.try_push(value)); } - vm_try!( - out.store(&mut self.stack, || VmResult::Ok(Mutable::Tuple(vm_try!( - OwnedTuple::try_from(tuple) - )))) - ); + vm_try!(out.store(&mut self.stack, || VmResult::Ok(vm_try!( + OwnedTuple::try_from(tuple) + )))); VmResult::Ok(()) } @@ -3297,7 +3314,6 @@ impl Vm { _ => false, }, BorrowRefRepr::Mutable(value) => match (type_check, &*value) { - (TypeCheck::Tuple, Mutable::Tuple(..)) => true, (TypeCheck::Result(v), Mutable::Result(result)) => match (v, result) { (0, Ok(..)) => true, (1, Err(..)) => true, @@ -3312,6 +3328,7 @@ impl Vm { }, BorrowRefRepr::Any(value) => match (type_check, value.type_hash()) { (TypeCheck::Vec, runtime::Vec::HASH) => true, + (TypeCheck::Tuple, runtime::OwnedTuple::HASH) => true, _ => false, }, }; diff --git a/crates/rune/src/tests/bug_700.rs b/crates/rune/src/tests/bug_700.rs index be37008c2..8ebe4ba81 100644 --- a/crates/rune/src/tests/bug_700.rs +++ b/crates/rune/src/tests/bug_700.rs @@ -1,5 +1,3 @@ -use crate::runtime::static_type; - prelude!(); /// See https://github.com/rune-rs/rune/issues/700 @@ -41,7 +39,7 @@ pub fn test_bug_700() -> Result<()> { assert_eq!( error.into_kind(), VmErrorKind::Expected { - expected: TypeInfo::static_type(static_type::TUPLE), + expected: TypeInfo::any::(), actual: TypeInfo::named::() } ); diff --git a/crates/rune/src/tests/vm_const_exprs.rs b/crates/rune/src/tests/vm_const_exprs.rs index 444430a3e..77f5dc315 100644 --- a/crates/rune/src/tests/vm_const_exprs.rs +++ b/crates/rune/src/tests/vm_const_exprs.rs @@ -96,10 +96,10 @@ fn test_const_collections() { let object: Object = rune!(pub fn main() { VALUE } const VALUE = #{};); assert!(object.is_empty()); - let tuple: OwnedTuple = rune!(pub fn main() { VALUE } const VALUE = ();); + let tuple: Box = rune!(pub fn main() { VALUE } const VALUE = ();); assert!(tuple.is_empty()); - let tuple: OwnedTuple = rune!(pub fn main() { VALUE } const VALUE = ("Hello World",);); + let tuple: Box = rune!(pub fn main() { VALUE } const VALUE = ("Hello World",);); assert_eq!( Some("Hello World"), tuple.get_value::(0).unwrap().as_deref()