From 1c23f2ef627ad6ff024e758c60ac614366b3d94e Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sat, 17 Feb 2024 01:34:43 +0100 Subject: [PATCH] Hide internals of values (#663) --- .github/workflows/ci.yml | 2 +- .github/workflows/weekly.yml | 2 +- benches/benches/benchmarks/aoc_2020_19b.rs | 5 +- crates/rune-alloc-macros/Cargo.toml | 2 +- crates/rune-alloc-macros/src/lib.rs | 3 +- crates/rune-alloc-macros/src/try_clone.rs | 14 +- crates/rune-alloc/Cargo.toml | 4 +- crates/rune-alloc/src/clone.rs | 3 + crates/rune-alloc/src/error.rs | 8 + crates/rune-alloc/src/hashbrown/map.rs | 5 +- crates/rune-alloc/src/lib.rs | 2 +- crates/rune-cli/Cargo.toml | 2 +- crates/rune-cli/src/main.rs | 2 +- crates/rune-core/Cargo.toml | 2 +- crates/rune-core/src/item/internal.rs | 4 +- crates/rune-core/src/lib.rs | 2 +- crates/rune-core/src/protocol.rs | 24 + crates/rune-languageserver/Cargo.toml | 2 +- crates/rune-languageserver/src/main.rs | 2 +- crates/rune-macros/Cargo.toml | 2 +- crates/rune-macros/src/any.rs | 71 +- crates/rune-macros/src/context.rs | 44 +- crates/rune-macros/src/from_value.rs | 66 +- crates/rune-macros/src/internals.rs | 3 + crates/rune-macros/src/lib.rs | 2 +- crates/rune-macros/src/macro_.rs | 15 +- crates/rune-modules/Cargo.toml | 4 +- crates/rune-modules/src/lib.rs | 2 +- crates/rune-modules/src/process.rs | 22 +- crates/rune-modules/src/rand.rs | 35 +- crates/rune-wasm/Cargo.toml | 2 +- crates/rune-wasm/src/lib.rs | 2 +- crates/rune/Cargo.toml | 2 +- crates/rune/src/cli/benches.rs | 4 +- crates/rune/src/cli/run.rs | 42 +- crates/rune/src/cli/tests.rs | 8 +- crates/rune/src/compile/context.rs | 1 + crates/rune/src/compile/error.rs | 23 +- crates/rune/src/compile/ir.rs | 7 +- crates/rune/src/compile/ir/compiler.rs | 47 +- crates/rune/src/compile/ir/eval.rs | 244 +- crates/rune/src/compile/ir/interpreter.rs | 86 +- crates/rune/src/compile/ir/scopes.rs | 16 +- crates/rune/src/compile/ir/value.rs | 177 - crates/rune/src/compile/prelude.rs | 1 + crates/rune/src/compile/v1/assemble.rs | 2 +- crates/rune/src/doc/build.rs | 4 +- crates/rune/src/internal_macros.rs | 44 +- crates/rune/src/lib.rs | 2 +- crates/rune/src/macros/format_args.rs | 18 +- crates/rune/src/macros/macro_context.rs | 6 +- crates/rune/src/module/module.rs | 2 +- crates/rune/src/modules.rs | 1 + crates/rune/src/modules/capture_io.rs | 2 +- crates/rune/src/modules/char.rs | 10 +- crates/rune/src/modules/clone.rs | 37 + crates/rune/src/modules/core.rs | 95 +- crates/rune/src/modules/disable_io.rs | 4 +- crates/rune/src/modules/future.rs | 57 +- crates/rune/src/modules/io.rs | 2 +- crates/rune/src/modules/iter.rs | 19 +- crates/rune/src/modules/mem.rs | 2 +- crates/rune/src/modules/option.rs | 28 +- crates/rune/src/modules/result.rs | 14 +- crates/rune/src/modules/string.rs | 40 +- crates/rune/src/modules/vec.rs | 2 +- crates/rune/src/runtime.rs | 22 +- crates/rune/src/runtime/access.rs | 540 ++- crates/rune/src/runtime/any_obj.rs | 163 +- crates/rune/src/runtime/awaited.rs | 6 +- crates/rune/src/runtime/bytes.rs | 30 +- crates/rune/src/runtime/const_value.rs | 79 +- crates/rune/src/runtime/control_flow.rs | 17 +- crates/rune/src/runtime/format.rs | 75 +- crates/rune/src/runtime/from_value.rs | 257 +- crates/rune/src/runtime/function.rs | 64 +- crates/rune/src/runtime/future.rs | 5 +- crates/rune/src/runtime/generator.rs | 20 +- crates/rune/src/runtime/generator_state.rs | 14 +- crates/rune/src/runtime/inst.rs | 17 +- crates/rune/src/runtime/iterator.rs | 21 +- crates/rune/src/runtime/object.rs | 2 +- crates/rune/src/runtime/panic.rs | 7 + crates/rune/src/runtime/protocol_caller.rs | 4 +- crates/rune/src/runtime/range.rs | 27 +- crates/rune/src/runtime/range_from.rs | 24 +- crates/rune/src/runtime/range_full.rs | 9 +- crates/rune/src/runtime/range_inclusive.rs | 27 +- crates/rune/src/runtime/range_to.rs | 10 +- crates/rune/src/runtime/range_to_inclusive.rs | 8 +- crates/rune/src/runtime/shared.rs | 794 ++--- crates/rune/src/runtime/stack.rs | 46 +- crates/rune/src/runtime/stream.rs | 29 +- crates/rune/src/runtime/tests.rs | 192 +- crates/rune/src/runtime/to_value.rs | 51 +- crates/rune/src/runtime/tuple.rs | 86 +- crates/rune/src/runtime/type_.rs | 2 +- crates/rune/src/runtime/unit.rs | 5 +- crates/rune/src/runtime/unit/storage.rs | 10 +- crates/rune/src/runtime/value.rs | 2906 +++++++++-------- crates/rune/src/runtime/value/serde.rs | 164 +- crates/rune/src/runtime/variant.rs | 7 +- crates/rune/src/runtime/vec.rs | 89 +- crates/rune/src/runtime/vec_tuple.rs | 2 +- crates/rune/src/runtime/vm.rs | 1117 +++---- crates/rune/src/runtime/vm_error.rs | 136 +- crates/rune/src/runtime/vm_execution.rs | 25 +- crates/rune/src/runtime/vm_halt.rs | 4 +- crates/rune/src/tests.rs | 8 +- crates/rune/src/tests/bug_344.rs | 33 +- crates/rune/src/tests/external_constructor.rs | 2 +- crates/rune/src/tests/external_generic.rs | 4 +- crates/rune/src/tests/external_ops.rs | 4 +- crates/rune/src/tests/getter_setter.rs | 2 +- crates/rune/src/tests/reference_error.rs | 5 +- crates/rune/src/tests/unit_constants.rs | 23 +- crates/rune/src/tests/vm_closures.rs | 12 +- crates/rune/src/tests/vm_function.rs | 23 +- examples/examples/object.rs | 4 +- examples/examples/rune_function.rs | 4 +- 120 files changed, 4262 insertions(+), 4384 deletions(-) delete mode 100644 crates/rune/src/compile/ir/value.rs create mode 100644 crates/rune/src/modules/clone.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9fd9c02ea..41c11a480 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,7 +62,7 @@ jobs: needs: basics steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@1.70 + - uses: dtolnay/rust-toolchain@1.74 - uses: Swatinem/rust-cache@v2 - run: cargo build --workspace diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml index bfd7bf2e9..eb891b651 100644 --- a/.github/workflows/weekly.yml +++ b/.github/workflows/weekly.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - rust: ["1.70", stable] + rust: ['1.74', stable] steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master diff --git a/benches/benches/benchmarks/aoc_2020_19b.rs b/benches/benches/benchmarks/aoc_2020_19b.rs index 6ef4b6b5f..910c62168 100644 --- a/benches/benches/benchmarks/aoc_2020_19b.rs +++ b/benches/benches/benchmarks/aoc_2020_19b.rs @@ -166,7 +166,7 @@ fn aoc_2020_19b(b: &mut Criterion) { fn clone(self) { Self { string: self.string, - position: self.position + position: clone(self.position) } } @@ -178,7 +178,6 @@ fn aoc_2020_19b(b: &mut Criterion) { fn completed(self) { self.position == self.string.len() } - } enum Rule { @@ -187,7 +186,6 @@ fn aoc_2020_19b(b: &mut Criterion) { Seq(vs), } - impl Rule { fn validate(self, rules, str) { let it = StrIter::new(str); @@ -217,7 +215,6 @@ fn aoc_2020_19b(b: &mut Criterion) { messages.iter().filter(|v| root.validate(rules, v)).count() } - pub fn main(n) { let r = get_rules(); let t1 = validate_all(r, n); diff --git a/crates/rune-alloc-macros/Cargo.toml b/crates/rune-alloc-macros/Cargo.toml index 362e6c0b2..6ef7fe07a 100644 --- a/crates/rune-alloc-macros/Cargo.toml +++ b/crates/rune-alloc-macros/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-alloc-macros" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "Macros for alloc crate of the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-alloc-macros/src/lib.rs b/crates/rune-alloc-macros/src/lib.rs index c7acf39d3..94db523a8 100644 --- a/crates/rune-alloc-macros/src/lib.rs +++ b/crates/rune-alloc-macros/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 @@ -23,6 +23,7 @@ //! This is part of the [Rune Language](https://rune-rs.github.io). #![allow(clippy::manual_map)] +#![allow(clippy::enum_variant_names)] extern crate proc_macro; diff --git a/crates/rune-alloc-macros/src/try_clone.rs b/crates/rune-alloc-macros/src/try_clone.rs index 13b5430fb..5f75464f7 100644 --- a/crates/rune-alloc-macros/src/try_clone.rs +++ b/crates/rune-alloc-macros/src/try_clone.rs @@ -6,10 +6,11 @@ use crate::context::{Context, Tokens}; pub(super) fn expand(mut input: syn::DeriveInput) -> Result> { let cx = Context::new(); - let tokens = cx.tokens_with_module(None); let attr = parse_type_attr(&cx, &input.attrs); + let tokens = cx.tokens_with_module(attr.module.as_ref()); + if !attr.predicates.is_empty() { input .generics @@ -161,6 +162,7 @@ pub(super) fn expand(mut input: syn::DeriveInput) -> Result, copy: bool, + module: Option, } fn parse_type_attr(cx: &Context, input: &[syn::Attribute]) -> TypeAttr { @@ -186,6 +188,16 @@ fn parse_type_attr(cx: &Context, input: &[syn::Attribute]) -> TypeAttr { return Ok(()); } + if parser.path.is_ident("crate") { + if parser.input.parse::>()?.is_some() { + attr.module = Some(parser.input.parse::()?); + } else { + attr.module = Some(syn::parse_quote!(crate)); + } + + return Ok(()); + } + Err(syn::Error::new( parser.input.span(), "unsupported attribute", diff --git a/crates/rune-alloc/Cargo.toml b/crates/rune-alloc/Cargo.toml index 5bc70c31b..8c5cc16fc 100644 --- a/crates/rune-alloc/Cargo.toml +++ b/crates/rune-alloc/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-alloc" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "The Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -22,7 +22,7 @@ alloc = [] rune-alloc-macros = { version = "=0.13.1", path = "../rune-alloc-macros" } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } -ahash = { version = "0.8.3", default-features = false } +ahash = { version = "0.8.8", default-features = false } pin-project = "1.1.0" [dev-dependencies] diff --git a/crates/rune-alloc/src/clone.rs b/crates/rune-alloc/src/clone.rs index 3602c9f2e..e22c1be7a 100644 --- a/crates/rune-alloc/src/clone.rs +++ b/crates/rune-alloc/src/clone.rs @@ -131,6 +131,9 @@ impl_copy!(::core::num::NonZeroI32); impl_copy!(::core::num::NonZeroI64); impl_copy!(::core::num::NonZeroI128); +#[cfg(feature = "std")] +impl_copy!(::std::process::ExitStatus); + impl TryClone for ::core::result::Result where T: TryClone, diff --git a/crates/rune-alloc/src/error.rs b/crates/rune-alloc/src/error.rs index 78ba7ba3b..f6c566e8b 100644 --- a/crates/rune-alloc/src/error.rs +++ b/crates/rune-alloc/src/error.rs @@ -1,5 +1,6 @@ //! Error types used by rune alloc. +use core::convert::Infallible; use core::fmt; use crate::alloc::AllocError; @@ -57,6 +58,13 @@ impl From for Error { } } +impl From for Error { + #[inline(always)] + fn from(value: Infallible) -> Self { + match value {} + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/crates/rune-alloc/src/hashbrown/map.rs b/crates/rune-alloc/src/hashbrown/map.rs index dc596a1ed..7a01a7ab7 100644 --- a/crates/rune-alloc/src/hashbrown/map.rs +++ b/crates/rune-alloc/src/hashbrown/map.rs @@ -280,10 +280,7 @@ where Q: Hash, S: BuildHasher, { - use core::hash::Hasher; - let mut state = hash_builder.build_hasher(); - val.hash(&mut state); - state.finish() + hash_builder.hash_one(val) } #[cfg(rune_nightly)] diff --git a/crates/rune-alloc/src/lib.rs b/crates/rune-alloc/src/lib.rs index 96bd01852..ff1a025aa 100644 --- a/crates/rune-alloc/src/lib.rs +++ b/crates/rune-alloc/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-cli/Cargo.toml b/crates/rune-cli/Cargo.toml index f218040fd..4d9268adf 100644 --- a/crates/rune-cli/Cargo.toml +++ b/crates/rune-cli/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-cli" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "An interpreter for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-cli/src/main.rs b/crates/rune-cli/src/main.rs index 80e136f84..a35bedcc6 100644 --- a/crates/rune-cli/src/main.rs +++ b/crates/rune-cli/src/main.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-core/Cargo.toml b/crates/rune-core/Cargo.toml index 6084fb88d..d9e58f113 100644 --- a/crates/rune-core/Cargo.toml +++ b/crates/rune-core/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-core" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "Core components for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-core/src/item/internal.rs b/crates/rune-core/src/item/internal.rs index 1fe2a133e..6743a4d2a 100644 --- a/crates/rune-core/src/item/internal.rs +++ b/crates/rune-core/src/item/internal.rs @@ -31,7 +31,7 @@ pub(super) struct Tag(pub(super) u8); /// Panics if the byte is not available. pub(super) fn read_tag(content: &[u8]) -> (Tag, usize) { let n = NativeEndian::read_u16(content); - let n = usize::try_from(n).unwrap(); + let n = usize::from(n); (Tag((n & TYPE_MASK) as u8), n >> TYPE_BITS) } @@ -45,7 +45,7 @@ pub(super) fn write_tag( Tag(tag): Tag, n: usize, ) -> alloc::Result<()> { - let tag = usize::try_from(tag).expect("tag out of bounds"); + let tag = usize::from(tag); debug_assert!(tag <= TYPE_MASK); assert!( n < MAX_DATA, diff --git a/crates/rune-core/src/lib.rs b/crates/rune-core/src/lib.rs index c8954efe1..1da05e05d 100644 --- a/crates/rune-core/src/lib.rs +++ b/crates/rune-core/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-core/src/protocol.rs b/crates/rune-core/src/protocol.rs index 054917ba9..73d3f409a 100644 --- a/crates/rune-core/src/protocol.rs +++ b/crates/rune-core/src/protocol.rs @@ -494,4 +494,28 @@ define! { repr: Some("let output = hash($value)"), doc: ["Hash the given value."], }; + + /// Protocol used when cloning a value. + pub const [CLONE, CLONE_HASH]: Protocol = Protocol { + name: "clone", + hash: 0x2af2c875e36971eu64, + repr: Some("let output = clone($value)"), + doc: ["Clone the given value."], + }; + + /// Protocol used when cloning a value. + pub const [SIZE_HINT, SIZE_HINT_HASH]: Protocol = Protocol { + name: "size_hint", + hash: 0x3de0975a7000dau64, + repr: Some("let output = $value.size_hint()"), + doc: ["Get the size hint of the given iterator."], + }; + + /// Protocol used when cloning a value. + pub const [NEXT_BACK, NEXT_BACK_HASH]: Protocol = Protocol { + name: "next_back", + hash: 0x91149fef42c0a8aeu64, + repr: Some("let output = $value.next_back()"), + doc: ["Get the next value from the back of the iterator."], + }; } diff --git a/crates/rune-languageserver/Cargo.toml b/crates/rune-languageserver/Cargo.toml index d5c22817e..fa32e3d14 100644 --- a/crates/rune-languageserver/Cargo.toml +++ b/crates/rune-languageserver/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-languageserver" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "A language server for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-languageserver/src/main.rs b/crates/rune-languageserver/src/main.rs index b71bd5847..e040f7307 100644 --- a/crates/rune-languageserver/src/main.rs +++ b/crates/rune-languageserver/src/main.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-macros/Cargo.toml b/crates/rune-macros/Cargo.toml index e7bd2b248..6d9de9826 100644 --- a/crates/rune-macros/Cargo.toml +++ b/crates/rune-macros/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-macros" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "Macros for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-macros/src/any.rs b/crates/rune-macros/src/any.rs index 5d89d08bf..8611f8fbd 100644 --- a/crates/rune-macros/src/any.rs +++ b/crates/rune-macros/src/any.rs @@ -510,7 +510,6 @@ where raw_into_mut, raw_into_ref, raw_str, - shared, type_info, any_type_info, type_of, @@ -658,7 +657,8 @@ where type Guard = #raw_into_ref; unsafe fn unsafe_to_ref<'a>(value: #value) -> #vm_result<(&'a Self, Self::Guard)> { - let (value, guard) = #vm_try!(value.into_any_ptr()); + let value = #vm_try!(#value::into_any_ref(value)); + let (value, guard) = #ref_::into_raw(value); #vm_result::Ok((#non_null::as_ref(&value), guard)) } } @@ -668,7 +668,8 @@ where type Guard = #raw_into_mut; unsafe fn unsafe_to_mut<'a>(value: #value) -> #vm_result<(&'a mut Self, Self::Guard)> { - let (mut value, guard) = #vm_try!(value.into_any_mut()); + let value = #vm_try!(#value::into_any_mut(value)); + let (mut value, guard) = #mut_::into_raw(value); #vm_result::Ok((#non_null::as_mut(&mut value), guard)) } } @@ -678,8 +679,8 @@ where type Guard = #pointer_guard; unsafe fn unsafe_to_value(self) -> #vm_result<(#value, Self::Guard)> { - let (shared, guard) = #vm_try!(#shared::from_ref(self)); - #vm_result::Ok((#value::from(shared), guard)) + let (shared, guard) = #vm_try!(#value::from_ref(self)); + #vm_result::Ok((shared, guard)) } } @@ -688,8 +689,8 @@ where type Guard = #pointer_guard; unsafe fn unsafe_to_value(self) -> #vm_result<(#value, Self::Guard)> { - let (shared, guard) = #vm_try!(#shared::from_mut(self)); - #vm_result::Ok((#value::from(shared), guard)) + let (shared, guard) = #vm_try!(#value::from_mut(self)); + #vm_result::Ok((shared, guard)) } } }) @@ -709,52 +710,68 @@ where impl #from_value for #ty { fn from_value(value: Value) -> #vm_result { let value = #vm_try!(#path(value)); - let value = #vm_try!(#shared::take(value)); #vm_result::Ok(value) } } + }) + } else { + None + } + }; + + let impl_from_value_ref = 'out: { + if let Some(path) = attr.from_value_ref { + let ty = match &attr.from_value_params { + Some(params) => quote!(#ident<#params>), + None if generics.params.is_empty() => quote!(#ident), + _ => break 'out None, + }; + Some(quote! { impl #unsafe_to_ref for #ty { type Guard = #raw_ref; unsafe fn unsafe_to_ref<'a>(value: #value) -> #vm_result<(&'a Self, Self::Guard)> { let value = #vm_try!(#path(value)); - let value = #vm_try!(#shared::into_ref(value)); let (value, guard) = #ref_::into_raw(value); #vm_result::Ok((value.as_ref(), guard)) } } + impl #from_value for #ref_<#ty> { + fn from_value(value: Value) -> #vm_result { + let value = #vm_try!(#path(value)); + #vm_result::Ok(value) + } + } + }) + } else { + None + } + }; + + let impl_from_value_mut = 'out: { + if let Some(path) = attr.from_value_mut { + let ty = match &attr.from_value_params { + Some(params) => quote!(#ident<#params>), + None if generics.params.is_empty() => quote!(#ident), + _ => break 'out None, + }; + + Some(quote! { impl #unsafe_to_mut for #ty { type Guard = #raw_mut; unsafe fn unsafe_to_mut<'a>(value: #value) -> #vm_result<(&'a mut Self, Self::Guard)> { let value = #vm_try!(#path(value)); - let value = #vm_try!(#shared::into_mut(value)); let (mut value, guard) = #mut_::into_raw(value); #vm_result::Ok((value.as_mut(), guard)) } } - impl #from_value for #shared<#ty> { - #[inline] - fn from_value(value: #value) -> #vm_result { - #path(value) - } - } - - impl #from_value for #ref_<#ty> { - fn from_value(value: Value) -> #vm_result { - let value = #vm_try!(#path(value)); - let value = #vm_try!(#shared::into_ref(value)); - #vm_result::Ok(value) - } - } - impl #from_value for #mut_<#ty> { fn from_value(value: Value) -> #vm_result { let value = #vm_try!(#path(value)); - let value = #vm_try!(#shared::into_mut(value)); #vm_result::Ok(value) } } @@ -769,6 +786,8 @@ where #impl_named #impl_type_of #impl_from_value + #impl_from_value_ref + #impl_from_value_mut #any } } diff --git a/crates/rune-macros/src/context.rs b/crates/rune-macros/src/context.rs index 33e26ab0d..8f233a09d 100644 --- a/crates/rune-macros/src/context.rs +++ b/crates/rune-macros/src/context.rs @@ -83,6 +83,10 @@ pub(crate) struct TypeAttr { pub(crate) static_type: Option, /// Method to use to convert from value. pub(crate) from_value: Option, + /// Method to use to convert from value ref. + pub(crate) from_value_ref: Option, + /// Method to use to convert from value mut. + pub(crate) from_value_mut: Option, /// Method to use to convert from value. pub(crate) from_value_params: Option>, } @@ -276,31 +280,38 @@ impl Context { .. } = g; + let Tokens { + try_clone, + vm_try, + vm_result, + .. + } = g.tokens; + match target { GenerateTarget::Named { field_ident, field_name } => { let access = if g.attrs.copy { quote!(s.#field_ident) } else { - quote!(Clone::clone(&s.#field_ident)) + quote!(#vm_try!(#try_clone::try_clone(&s.#field_ident))) }; let protocol = g.tokens.protocol(PROTOCOL_GET); quote_spanned! { g.field.span() => - module.field_function(#protocol, #field_name, |s: &Self| #access)?; + module.field_function(#protocol, #field_name, |s: &Self| #vm_result::Ok(#access))?; } } GenerateTarget::Numbered { field_index } => { let access = if g.attrs.copy { quote!(s.#field_index) } else { - quote!(Clone::clone(&s.#field_index)) + quote!(#vm_try!(#try_clone::try_clone(&s.#field_index))) }; let protocol = g.tokens.protocol(PROTOCOL_GET); quote_spanned! { g.field.span() => - module.index_function(#protocol, #field_index, |s: &Self| #access)?; + module.index_function(#protocol, #field_index, |s: &Self| #vm_result::Ok(#access))?; } } } @@ -449,10 +460,13 @@ impl Context { // Parse `#[rune(name = "..")]` meta.input.parse::()?; attr.name = Some(meta.input.parse()?); - } else if meta.path == MODULE { - // Parse `#[rune(module = )]` - meta.input.parse::()?; - attr.module = Some(parse_path_compat(meta.input)?); + } else if meta.path == MODULE || meta.path == CRATE { + // Parse `#[rune(crate [= ])]` + if meta.input.parse::>()?.is_some() { + attr.module = Some(parse_path_compat(meta.input)?); + } else { + attr.module = Some(syn::parse_quote!(crate)); + } } else if meta.path == INSTALL_WITH { // Parse `#[rune(install_with = )]` meta.input.parse::()?; @@ -467,6 +481,12 @@ impl Context { } else if meta.path == FROM_VALUE { meta.input.parse::()?; attr.from_value = Some(meta.input.parse()?); + } else if meta.path == FROM_VALUE_REF { + meta.input.parse::()?; + attr.from_value_ref = Some(meta.input.parse()?); + } else if meta.path == FROM_VALUE_MUT { + meta.input.parse::()?; + attr.from_value_mut = Some(meta.input.parse()?); } else if meta.path == FROM_VALUE_PARAMS { meta.input.parse::()?; let content; @@ -596,7 +616,7 @@ impl Context { any: path(m, ["Any"]), box_: path(m, ["__private", "Box"]), vec: path(m, ["alloc", "Vec"]), - clone: path(&core, ["clone", "Clone"]), + try_clone: path(m, ["alloc", "clone", "TryClone"]), compile_error: path(m, ["compile", "Error"]), context_error: path(m, ["compile", "ContextError"]), double_ended_iterator: path(&core, ["iter", "DoubleEndedIterator"]), @@ -629,7 +649,6 @@ impl Context { raw_str: path(m, ["runtime", "RawStr"]), ref_: path(m, ["runtime", "Ref"]), result: path(&core, ["result", "Result"]), - shared: path(m, ["runtime", "Shared"]), span: path(m, ["ast", "Span"]), spanned: path(m, ["ast", "Spanned"]), static_type_mod: path(m, ["runtime", "static_type"]), @@ -646,6 +665,7 @@ impl Context { unsafe_to_ref: path(m, ["runtime", "UnsafeToRef"]), unsafe_to_value: path(m, ["runtime", "UnsafeToValue"]), value: path(m, ["runtime", "Value"]), + type_value: path(m, ["runtime", "TypeValue"]), variant_data: path(m, ["runtime", "VariantData"]), vm_result: path(m, ["runtime", "VmResult"]), vm_try: path(m, ["vm_try"]), @@ -688,7 +708,7 @@ pub(crate) struct Tokens { pub(crate) any: syn::Path, pub(crate) box_: syn::Path, pub(crate) vec: syn::Path, - pub(crate) clone: syn::Path, + pub(crate) try_clone: syn::Path, pub(crate) compile_error: syn::Path, pub(crate) context_error: syn::Path, pub(crate) double_ended_iterator: syn::Path, @@ -721,7 +741,6 @@ pub(crate) struct Tokens { pub(crate) raw_str: syn::Path, pub(crate) ref_: syn::Path, pub(crate) result: syn::Path, - pub(crate) shared: syn::Path, pub(crate) span: syn::Path, pub(crate) spanned: syn::Path, pub(crate) static_type_mod: syn::Path, @@ -738,6 +757,7 @@ pub(crate) struct Tokens { pub(crate) unsafe_to_ref: syn::Path, pub(crate) unsafe_to_value: syn::Path, pub(crate) value: syn::Path, + pub(crate) type_value: syn::Path, pub(crate) variant_data: syn::Path, pub(crate) vm_result: syn::Path, pub(crate) vm_try: syn::Path, diff --git a/crates/rune-macros/src/from_value.rs b/crates/rune-macros/src/from_value.rs index 1e35eb87f..c9528ef12 100644 --- a/crates/rune-macros/src/from_value.rs +++ b/crates/rune-macros/src/from_value.rs @@ -1,6 +1,6 @@ use crate::context::{Context, Tokens}; use proc_macro2::TokenStream; -use quote::quote_spanned; +use quote::{quote, quote_spanned}; use syn::spanned::Spanned as _; struct Expander { @@ -19,6 +19,7 @@ impl Expander { let Tokens { value, + type_value, from_value, vm_result, tuple, @@ -28,12 +29,11 @@ impl Expander { let (expanded, expected) = match &st.fields { syn::Fields::Unit => { - let expanded = quote_spanned! { - input.span() => - #value::EmptyTuple => { + let expanded = quote! { + #type_value::EmptyTuple => { #vm_result::Ok(Self) } - #value::EmptyStruct(..) => { + #type_value::EmptyStruct(..) => { #vm_result::Ok(Self) } }; @@ -43,18 +43,15 @@ impl Expander { syn::Fields::Unnamed(f) => { let expanded = self.expand_unnamed(f)?; - let expanded = quote_spanned! { - f.span() => - #value::EmptyTuple => { + let expanded = quote! { + #type_value::EmptyTuple => { let tuple = #tuple::new(&[]); #vm_result::Ok(Self(#expanded)) } - #value::Tuple(tuple) => { - let tuple = #vm_try!(tuple.borrow_ref()); + #type_value::Tuple(tuple) => { #vm_result::Ok(Self(#expanded)) } - #value::TupleStruct(tuple) => { - let tuple = #vm_try!(tuple.borrow_ref()); + #type_value::TupleStruct(tuple) => { #vm_result::Ok(Self(#expanded)) } }; @@ -64,14 +61,11 @@ impl Expander { syn::Fields::Named(f) => { let expanded = self.expand_named(f)?; - let expanded = quote_spanned! { - f.span() => - #value::Object(object) => { - let object = #vm_try!(object.borrow_ref()); + let expanded = quote! { + #type_value::Object(object) => { #vm_result::Ok(Self { #expanded }) } - #value::Struct(object) => { - let object = #vm_try!(object.borrow_ref()); + #type_value::Struct(object) => { #vm_result::Ok(Self { #expanded }) } }; @@ -80,14 +74,14 @@ impl Expander { } }; - Ok(quote_spanned! { input.span() => + Ok(quote! { #[automatically_derived] impl #from_value for #ident { fn from_value(value: #value) -> #vm_result { - match value { + match #vm_try!(#value::into_type_value(value)) { #expanded actual => { - #vm_result::expected::<#expected>(#vm_try!(actual.type_info())) + #vm_result::expected::<#expected>(#type_value::type_info(&actual)) } } } @@ -108,6 +102,7 @@ impl Expander { let ident = &input.ident; let Tokens { + type_value, from_value, variant_data, value, @@ -122,34 +117,33 @@ impl Expander { match &variant.fields { syn::Fields::Unit => { - unit_matches.push(quote_spanned! { variant.span() => + unit_matches.push(quote! { #lit_str => #vm_result::Ok(Self::#ident) }); } syn::Fields::Unnamed(named) => { let expanded = self.expand_unnamed(named)?; - unnamed_matches.push(quote_spanned! { variant.span() => + unnamed_matches.push(quote! { #lit_str => #vm_result::Ok(Self::#ident ( #expanded )) }); } syn::Fields::Named(named) => { let expanded = self.expand_named(named)?; - named_matches.push(quote_spanned! { variant.span() => + named_matches.push(quote! { #lit_str => #vm_result::Ok(Self::#ident { #expanded }) }); } } } - let missing = quote_spanned! { input.span() => + let missing = quote! { name => #vm_try!(#vm_result::__rune_macros__missing_variant(name)) }; - let variant = quote_spanned! { input.span() => - #value::Variant(variant) => { - let variant = #vm_try!(variant.borrow_ref()); + let variant = quote! { + #type_value::Variant(variant) => { let mut it = variant.rtti().item.iter(); let name = match it.next_back_str() { @@ -171,14 +165,14 @@ impl Expander { } }; - Ok(quote_spanned! { input.span() => + Ok(quote! { #[automatically_derived] impl #from_value for #ident { fn from_value(value: #value) -> #vm_result { - match value { + match #vm_try!(#value::into_type_value(value)) { #variant, actual => { - #vm_result::__rune_macros__expected_variant(#vm_try!(actual.type_info())) + #vm_result::__rune_macros__expected_variant(#type_value::type_info(&actual)) } } } @@ -209,17 +203,19 @@ impl Expander { vm_result, type_name, vm_try, - clone, + try_clone, .. } = &self.tokens; for (index, field) in unnamed.unnamed.iter().enumerate() { let _ = self.cx.field_attrs(&field.attrs)?; - from_values.push(quote_spanned! { - field.span() => + from_values.push(quote! { match tuple.get(#index) { - Some(value) => #vm_try!(#from_value::from_value(#clone::clone(value))), + Some(value) => { + let value = #vm_try!(#try_clone::try_clone(value)); + #vm_try!(#from_value::from_value(value)) + } None => { return #vm_result::__rune_macros__missing_tuple_index(#type_name::(), #index); } diff --git a/crates/rune-macros/src/internals.rs b/crates/rune-macros/src/internals.rs index 8d1771e90..2697ea0b4 100644 --- a/crates/rune-macros/src/internals.rs +++ b/crates/rune-macros/src/internals.rs @@ -18,12 +18,15 @@ pub const PARSE: Symbol = Symbol("parse"); pub const NAME: Symbol = Symbol("name"); pub const ITEM: Symbol = Symbol("item"); pub const MODULE: Symbol = Symbol("module"); +pub const CRATE: Symbol = Symbol("crate"); pub const INSTALL_WITH: Symbol = Symbol("install_with"); pub const CONSTRUCTOR: Symbol = Symbol("constructor"); pub const BUILTIN: Symbol = Symbol("builtin"); pub const STATIC_TYPE: Symbol = Symbol("static_type"); pub const FROM_VALUE: Symbol = Symbol("from_value"); +pub const FROM_VALUE_REF: Symbol = Symbol("from_value_ref"); +pub const FROM_VALUE_MUT: Symbol = Symbol("from_value_mut"); pub const FROM_VALUE_PARAMS: Symbol = Symbol("from_value_params"); pub const GET: Symbol = Symbol("get"); pub const SET: Symbol = Symbol("set"); diff --git a/crates/rune-macros/src/lib.rs b/crates/rune-macros/src/lib.rs index f7f918a69..378987023 100644 --- a/crates/rune-macros/src/lib.rs +++ b/crates/rune-macros/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-macros/src/macro_.rs b/crates/rune-macros/src/macro_.rs index de84d59e4..e44d3d346 100644 --- a/crates/rune-macros/src/macro_.rs +++ b/crates/rune-macros/src/macro_.rs @@ -1,4 +1,4 @@ -use proc_macro2::{Ident, Span, TokenStream}; +use proc_macro2::{Ident, TokenStream}; use quote::{quote, ToTokens}; use syn::parse::ParseStream; use syn::punctuated::Punctuated; @@ -8,7 +8,7 @@ use syn::spanned::Spanned; enum Path { #[default] None, - Path(Span, syn::Path), + Path(syn::Path), } #[derive(Default)] @@ -19,19 +19,18 @@ pub(crate) struct Config { impl Config { /// Parse the given parse stream. pub(crate) fn parse(input: ParseStream) -> syn::Result { - let span = input.span(); let mut out = Self::default(); while !input.is_empty() { let ident = input.parse::()?; - if ident == "path" { - input.parse::()?; - out.path = Path::Path(span, input.parse()?); - } else { + if ident != "path" { return Err(syn::Error::new_spanned(ident, "Unsupported option")); } + input.parse::()?; + out.path = Path::Path(input.parse()?); + if input.parse::>()?.is_none() { break; } @@ -140,7 +139,7 @@ impl Macro { lit: syn::Lit::Str(self.name_string.clone()), })); } - Path::Path(_, path) => { + Path::Path(path) => { for s in &path.segments { let syn::PathArguments::None = s.arguments else { return Err(syn::Error::new_spanned( diff --git a/crates/rune-modules/Cargo.toml b/crates/rune-modules/Cargo.toml index eee142d63..40a116ff9 100644 --- a/crates/rune-modules/Cargo.toml +++ b/crates/rune-modules/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-modules" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "Native modules for Rune, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -20,7 +20,7 @@ time = ["tokio", "tokio?/time"] fs = ["tokio", "tokio?/fs"] http = ["reqwest"] json = ["serde_json"] -process = ["tokio?/process"] +process = ["tokio?/process", "rune/std"] signal = ["tokio?/signal"] rand = ["nanorand"] experiments = [] diff --git a/crates/rune-modules/src/lib.rs b/crates/rune-modules/src/lib.rs index 55b9e5a3e..63c1f82d2 100644 --- a/crates/rune-modules/src/lib.rs +++ b/crates/rune-modules/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-modules/src/process.rs b/crates/rune-modules/src/process.rs index f28ce4c75..48e5d0c52 100644 --- a/crates/rune-modules/src/process.rs +++ b/crates/rune-modules/src/process.rs @@ -30,7 +30,8 @@ //! ``` use rune::{Any, Module, ContextError, vm_try}; -use rune::runtime::{Bytes, Shared, Value, VmResult, Formatter}; +use rune::runtime::{Bytes, Value, VmResult, Formatter}; +use rune::alloc::clone::TryClone; use rune::alloc::fmt::TryWrite; use rune::alloc::Vec; @@ -74,14 +75,7 @@ impl Command { #[rune::function(instance)] fn args(&mut self, args: &[Value]) -> VmResult<()> { for arg in args { - match arg { - Value::String(s) => { - self.inner.arg(&*vm_try!(s.borrow_ref())); - } - actual => { - return VmResult::expected::(vm_try!(actual.type_info())); - } - } + self.inner.arg(&*vm_try!(arg.as_string())); } VmResult::Ok(()) @@ -128,8 +122,8 @@ impl Child { Ok(Output { status: ExitStatus { status: output.status }, - stdout: Shared::new(Bytes::from_vec(Vec::try_from(output.stdout).vm?)).vm?, - stderr: Shared::new(Bytes::from_vec(Vec::try_from(output.stderr).vm?)).vm?, + stdout: Bytes::from_vec(Vec::try_from(output.stdout).vm?), + stderr: Bytes::from_vec(Vec::try_from(output.stderr).vm?), }) } } @@ -140,12 +134,12 @@ struct Output { #[rune(get)] status: ExitStatus, #[rune(get)] - stdout: Shared, + stdout: Bytes, #[rune(get)] - stderr: Shared, + stderr: Bytes, } -#[derive(Clone, Copy, Any)] +#[derive(TryClone, Clone, Copy, Any)] #[rune(item = ::process)] struct ExitStatus { status: std::process::ExitStatus, diff --git a/crates/rune-modules/src/rand.rs b/crates/rune-modules/src/rand.rs index 07bf8f319..bb1e4eb01 100644 --- a/crates/rune-modules/src/rand.rs +++ b/crates/rune-modules/src/rand.rs @@ -33,7 +33,6 @@ use nanorand::Rng; use rune::{Any, ContextError, Module}; -use rune::runtime::Value; /// Construct the `rand` module. pub fn module(_stdio: bool) -> Result { @@ -78,13 +77,13 @@ impl WyRand { } /// Generate a random integer - fn int(&mut self) -> Value { - Value::Integer(self.inner.generate::() as i64) + fn int(&mut self) -> i64 { + self.inner.generate::() as i64 } /// Generate a random integer within the specified range - fn int_range(&mut self, lower: i64, upper: i64) -> Value { - Value::Integer(self.inner.generate_range(0..(upper - lower) as u64) as i64 + lower) + fn int_range(&mut self, lower: i64, upper: i64) -> i64 { + self.inner.generate_range(0..(upper - lower) as u64) as i64 + lower } } @@ -110,26 +109,26 @@ impl Pcg64 { } /// Generate a random integer - fn int(&mut self) -> Value { - Value::Integer(self.inner.generate::() as i64) + fn int(&mut self) -> i64 { + self.inner.generate::() as i64 } /// Generate a random integer within the specified range - fn int_range(&mut self, lower: i64, upper: i64) -> Value { - Value::Integer(self.inner.generate_range(0..(upper - lower) as u64) as i64 + lower) + fn int_range(&mut self, lower: i64, upper: i64) -> i64 { + self.inner.generate_range(0..(upper - lower) as u64) as i64 + lower } } -fn int() -> rune::support::Result { - Ok(Value::Integer( +fn int() -> rune::support::Result { + Ok( nanorand::WyRand::new().generate::() as i64 - )) + ) } -fn int_range(lower: i64, upper: i64) -> rune::support::Result { - Ok(Value::Integer( +fn int_range(lower: i64, upper: i64) -> rune::support::Result { + Ok( nanorand::WyRand::new().generate_range(0..(upper - lower) as u64) as i64 + lower, - )) + ) } #[cfg(test)] @@ -139,14 +138,14 @@ mod tests { #[test] fn test_range_is_exclusive() { for _ in 0..100 { - assert_eq!(rune::from_value::(int_range(0, 1).unwrap()).unwrap(), 0); + assert_eq!(int_range(0, 1).unwrap(), 0); } } #[test] fn test_range_can_be_negative() { for _ in 0..100 { - assert_eq!(rune::from_value::(int_range(-2, -1).unwrap()).unwrap(), -2); + assert_eq!(int_range(-2, -1).unwrap(), -2); } } @@ -156,7 +155,7 @@ mod tests { let mut any_positive = false; for _ in 0..100 { - let v: i64 = rune::from_value(int().unwrap()).unwrap(); + let v: i64 = int().unwrap(); any_negative = any_negative || v < 0; any_positive = any_positive || v > 0; } diff --git a/crates/rune-wasm/Cargo.toml b/crates/rune-wasm/Cargo.toml index 39d71d90f..d1a526de9 100644 --- a/crates/rune-wasm/Cargo.toml +++ b/crates/rune-wasm/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-wasm" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "A WASM module for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-wasm/src/lib.rs b/crates/rune-wasm/src/lib.rs index 6d4cb2669..4e7ae7f9b 100644 --- a/crates/rune-wasm/src/lib.rs +++ b/crates/rune-wasm/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune/Cargo.toml b/crates/rune/Cargo.toml index 6b125d014..2d156536b 100644 --- a/crates/rune/Cargo.toml +++ b/crates/rune/Cargo.toml @@ -3,7 +3,7 @@ name = "rune" version = "0.13.1" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" description = "The Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune/src/cli/benches.rs b/crates/rune/src/cli/benches.rs index 5b770aba3..de38f868c 100644 --- a/crates/rune/src/cli/benches.rs +++ b/crates/rune/src/cli/benches.rs @@ -115,7 +115,7 @@ fn bench_fn( multiple: bool, ) -> Result<()> { for _ in 0..args.warmup { - let value = f.call::<_, Value>(()).into_result()?; + let value = f.call::(()).into_result()?; drop(value); } @@ -124,7 +124,7 @@ fn bench_fn( for _ in 0..args.iterations { let start = Instant::now(); - let value = f.call::<_, Value>(()).into_result()?; + let value = f.call::(()).into_result()?; let duration = Instant::now().duration_since(start); collected.try_push(duration.as_nanos() as i128)?; drop(value); diff --git a/crates/rune/src/cli/run.rs b/crates/rune/src/cli/run.rs index 454ac3e13..6c487a2ce 100644 --- a/crates/rune/src/cli/run.rs +++ b/crates/rune/src/cli/run.rs @@ -273,9 +273,13 @@ pub(super) async fn run( writeln!(io.stdout, " *empty*")?; } - for (n, value) in stack.iter().enumerate() { - writeln!(io.stdout, "{}+{} = {:?}", frame.stack_bottom, n, value)?; - } + vm.with(|| { + for (n, value) in stack.iter().enumerate() { + writeln!(io.stdout, "{}+{} = {:?}", frame.stack_bottom, n, value)?; + } + + Ok::<_, crate::support::Error>(()) + })?; } // NB: print final frame @@ -292,15 +296,19 @@ pub(super) async fn run( writeln!(io.stdout, " *empty*")?; } - for (n, value) in values.iter().enumerate() { - writeln!( - io.stdout, - " {}+{} = {:?}", - stack.stack_bottom(), - n, - value - )?; - } + vm.with(|| { + for (n, value) in values.iter().enumerate() { + writeln!( + io.stdout, + " {}+{} = {:?}", + stack.stack_bottom(), + n, + value + )?; + } + + Ok::<_, crate::support::Error>(()) + })?; } if let Some(error) = errored { @@ -402,9 +410,13 @@ where writeln!(o, " *empty*")?; } - for (n, value) in values.iter().enumerate() { - writeln!(o, " {}+{} = {:?}", stack.stack_bottom(), n, value)?; - } + vm.with(|| { + for (n, value) in values.iter().enumerate() { + writeln!(o, " {}+{} = {:?}", stack.stack_bottom(), n, value)?; + } + + Ok::<_, TraceError>(()) + })?; } if let Some(result) = result { diff --git a/crates/rune/src/cli/tests.rs b/crates/rune/src/cli/tests.rs index 484a264fa..efde525ef 100644 --- a/crates/rune/src/cli/tests.rs +++ b/crates/rune/src/cli/tests.rs @@ -14,7 +14,7 @@ use crate::cli::{ use crate::compile::{FileSourceLoader, ItemBuf}; use crate::doc::TestParams; use crate::modules::capture_io::CaptureIo; -use crate::runtime::{UnitFn, Value, Vm, VmError, VmResult}; +use crate::runtime::{UnitFn, Value, Vm, VmError, VmResult, ValueKind}; use crate::termcolor::{Color, ColorSpec, WriteColor}; use crate::{Diagnostics, Hash, Source, Sources, Unit}; @@ -338,12 +338,12 @@ impl TestCase { capture_io.drain_into(&mut self.output)?; self.outcome = match result { - VmResult::Ok(v) => match v { - Value::Result(result) => match result.take()? { + VmResult::Ok(v) => match v.take_kind()? { + ValueKind::Result(result) => match result { Ok(..) => Outcome::Ok, Err(error) => Outcome::Err(error), }, - Value::Option(option) => match *option.borrow_ref()? { + ValueKind::Option(option) => match option { Some(..) => Outcome::Ok, None => Outcome::None, }, diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index 1c98182c8..226d8c3f0 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -139,6 +139,7 @@ impl Context { // This must go first, because it includes types which are used in other modules. this.install(crate::modules::core::module()?)?; + this.install(crate::modules::clone::module()?)?; this.install(crate::modules::num::module()?)?; this.install(crate::modules::any::module()?)?; this.install(crate::modules::bytes::module()?)?; diff --git a/crates/rune/src/compile/error.rs b/crates/rune/src/compile/error.rs index bdf9a5a7c..1a1a7d8ba 100644 --- a/crates/rune/src/compile/error.rs +++ b/crates/rune/src/compile/error.rs @@ -17,7 +17,7 @@ use crate::parse::{Expectation, IntoExpectation, LexerMode}; use crate::query::MissingId; use crate::runtime::debug::DebugSignature; use crate::runtime::unit::EncodeError; -use crate::runtime::{AccessError, TypeInfo, TypeOf}; +use crate::runtime::{AccessError, RuntimeError, TypeInfo, TypeOf, ValueKind, VmError}; #[cfg(feature = "std")] use crate::source; use crate::{Hash, SourceId}; @@ -190,7 +190,7 @@ impl Error { } /// An error raised when we expect a certain constant value but get another. - pub(crate) fn expected_type(spanned: S, actual: &ir::Value) -> Self + pub(crate) fn expected_type(spanned: S, actual: &ValueKind) -> Self where S: Spanned, E: TypeOf, @@ -225,6 +225,7 @@ pub(crate) enum ErrorKind { IrError(IrErrorKind), MetaError(MetaError), AccessError(AccessError), + VmError(VmError), EncodeError(EncodeError), MissingLastId(MissingLastId), GuardMismatch(GuardMismatch), @@ -528,6 +529,7 @@ cfg_std! { ErrorKind::IrError(source) => Some(source), ErrorKind::MetaError(source) => Some(source), ErrorKind::AccessError(source) => Some(source), + ErrorKind::VmError(source) => Some(source), ErrorKind::EncodeError(source) => Some(source), ErrorKind::MissingLastId(source) => Some(source), ErrorKind::GuardMismatch(source) => Some(source), @@ -566,6 +568,9 @@ impl fmt::Display for ErrorKind { ErrorKind::AccessError(error) => { error.fmt(f)?; } + ErrorKind::VmError(error) => { + error.fmt(f)?; + } ErrorKind::EncodeError(error) => { error.fmt(f)?; } @@ -1082,6 +1087,20 @@ impl From for ErrorKind { } } +impl From for ErrorKind { + #[inline] + fn from(error: VmError) -> Self { + ErrorKind::VmError(error) + } +} + +impl From for ErrorKind { + #[inline] + fn from(error: RuntimeError) -> Self { + ErrorKind::VmError(VmError::new(error.into_vm_error_kind())) + } +} + impl From for ErrorKind { #[inline] fn from(source: EncodeError) -> Self { diff --git a/crates/rune/src/compile/ir.rs b/crates/rune/src/compile/ir.rs index 37a5fcee0..1afa25f01 100644 --- a/crates/rune/src/compile/ir.rs +++ b/crates/rune/src/compile/ir.rs @@ -7,7 +7,6 @@ pub(crate) mod compiler; mod eval; mod interpreter; pub(crate) mod scopes; -mod value; use core::ops::{AddAssign, MulAssign, ShlAssign, ShrAssign, SubAssign}; @@ -22,12 +21,12 @@ use crate::indexing::index; use crate::macros::MacroContext; use crate::parse::NonZeroId; use crate::query::Used; +use crate::runtime::{Value, ValueKind}; pub(crate) use self::compiler::Ctxt; pub(crate) use self::eval::{eval_ir, EvalOutcome}; pub(crate) use self::interpreter::{Budget, Interpreter}; pub(crate) use self::scopes::Scopes; -pub(crate) use self::value::Value; impl ast::Expr { pub(crate) fn eval(&self, cx: &mut MacroContext<'_, '_, '_>) -> compile::Result { @@ -534,8 +533,8 @@ impl IrAssignOp { where S: Copy + Spanned, { - if let Value::Integer(target) = target { - if let Value::Integer(operand) = operand { + if let ValueKind::Integer(target) = &mut *target.borrow_kind_mut().with_span(spanned)? { + if let ValueKind::Integer(operand) = *operand.borrow_kind_ref().with_span(spanned)? { return self.assign_int(spanned, target, operand); } } diff --git a/crates/rune/src/compile/ir/compiler.rs b/crates/rune/src/compile/ir/compiler.rs index eced1a697..bb6e82e0d 100644 --- a/crates/rune/src/compile/ir/compiler.rs +++ b/crates/rune/src/compile/ir/compiler.rs @@ -7,7 +7,7 @@ use crate::compile::ir; use crate::compile::{self, ErrorKind, WithSpan}; use crate::hir; use crate::query::Query; -use crate::runtime::{Bytes, Shared}; +use crate::runtime::{Bytes, Value}; use crate::SourceId; use rune_macros::instrument; @@ -50,7 +50,8 @@ pub(crate) fn expr(hir: &hir::Expr<'_>, c: &mut Ctxt<'_, '_>) -> compile::Result )); }; - ir::Ir::new(span, ir::Value::from_const(value).with_span(span)?) + let value = value.as_value().with_span(span)?; + ir::Ir::new(span, value) } hir::ExprKind::Variable(name) => { return Ok(ir::Ir::new(span, name.into_owned()?)); @@ -202,28 +203,44 @@ fn expr_binary( #[instrument(span = span)] fn lit(c: &mut Ctxt<'_, '_>, span: Span, hir: hir::Lit<'_>) -> compile::Result { Ok(match hir { - hir::Lit::Bool(boolean) => ir::Ir::new(span, ir::Value::Bool(boolean)), - hir::Lit::Str(string) => ir::Ir::new( - span, - ir::Value::String(Shared::new(string.try_to_owned()?).with_span(span)?), - ), - hir::Lit::Integer(n) => ir::Ir::new(span, ir::Value::Integer(n)), - hir::Lit::Float(n) => ir::Ir::new(span, ir::Value::Float(n)), - hir::Lit::Byte(b) => ir::Ir::new(span, ir::Value::Byte(b)), + hir::Lit::Bool(boolean) => { + let value = Value::try_from(boolean).with_span(span)?; + ir::Ir::new(span, value) + } + hir::Lit::Str(string) => { + let string = string.try_to_owned().with_span(span)?; + let value = Value::try_from(string).with_span(span)?; + ir::Ir::new(span, value) + } + hir::Lit::Integer(n) => { + let value = Value::try_from(n).with_span(span)?; + ir::Ir::new(span, value) + } + hir::Lit::Float(n) => { + let value = Value::try_from(n).with_span(span)?; + ir::Ir::new(span, value) + } + hir::Lit::Byte(b) => { + let value = Value::try_from(b).with_span(span)?; + ir::Ir::new(span, value) + } hir::Lit::ByteStr(byte_str) => { - let value = ir::Value::Bytes( - Shared::new(Bytes::from_vec(Vec::try_from(byte_str)?)).with_span(span)?, - ); + let value = Bytes::from_vec(Vec::try_from(byte_str).with_span(span)?); + let value = Value::try_from(value).with_span(span)?; + ir::Ir::new(span, value) + } + hir::Lit::Char(c) => { + let value = Value::try_from(c).with_span(span)?; ir::Ir::new(span, value) } - hir::Lit::Char(c) => ir::Ir::new(span, ir::Value::Char(c)), }) } #[instrument(span = span)] fn expr_tuple(c: &mut Ctxt<'_, '_>, span: Span, hir: &hir::ExprSeq<'_>) -> compile::Result { if hir.items.is_empty() { - return Ok(ir::Ir::new(span, ir::Value::EmptyTuple)); + let value = Value::empty().with_span(span)?; + return Ok(ir::Ir::new(span, value)); } let mut items = Vec::new(); diff --git a/crates/rune/src/compile/ir/eval.rs b/crates/rune/src/compile/ir/eval.rs index 756cbbdb6..8caeba232 100644 --- a/crates/rune/src/compile/ir/eval.rs +++ b/crates/rune/src/compile/ir/eval.rs @@ -2,19 +2,12 @@ use core::ops::{Add, Mul, Shl, Shr, Sub}; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; -use crate::alloc::{Box, HashMap, String, Vec}; +use crate::alloc::{Box, String, Vec}; use crate::ast::{Span, Spanned}; -use crate::compile::ir; +use crate::compile::ir::{self}; use crate::compile::{self, WithSpan}; use crate::query::Used; -use crate::runtime::Shared; - -/// Process an ir value as a boolean. -fn as_bool(span: Span, value: ir::Value) -> compile::Result { - value - .into_bool() - .map_err(|actual| compile::Error::expected_type::<_, bool>(span, &actual)) -} +use crate::runtime::{Object, OwnedTuple, Value, ValueKind}; /// The outcome of a constant evaluation. pub enum EvalOutcome { @@ -23,7 +16,7 @@ pub enum EvalOutcome { /// A compile error. Error(compile::Error), /// Break until the next loop, or the optional label. - Break(Span, Option>, Option), + Break(Span, Option>, Option), } impl EvalOutcome { @@ -49,7 +42,7 @@ fn eval_ir_assign( ir: &ir::IrAssign, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { interp.budget.take(ir)?; let value = eval_ir(&ir.value, interp, used)?; @@ -57,108 +50,110 @@ fn eval_ir_assign( .scopes .mut_target(&ir.target, move |t| ir.op.assign(ir, t, value))?; - Ok(ir::Value::EmptyTuple) + Ok(Value::empty().with_span(ir)?) } fn eval_ir_binary( ir: &ir::IrBinary, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { + fn add_strings(a: &str, b: &str) -> crate::alloc::Result { + let mut out = String::try_with_capacity(a.len() + b.len())?; + out.try_push_str(a)?; + out.try_push_str(b)?; + Ok(out) + } + let span = ir.span(); interp.budget.take(span)?; let a = eval_ir(&ir.lhs, interp, used)?; let b = eval_ir(&ir.rhs, interp, used)?; - match (a, b) { - (ir::Value::Integer(a), ir::Value::Integer(b)) => match ir.op { - ir::IrBinaryOp::Add => { - return Ok(ir::Value::Integer(a.add(&b))); - } - ir::IrBinaryOp::Sub => { - return Ok(ir::Value::Integer(a.sub(&b))); - } - ir::IrBinaryOp::Mul => { - return Ok(ir::Value::Integer(a.mul(&b))); - } - ir::IrBinaryOp::Div => { - let number = a - .checked_div(b) - .ok_or_else(|| compile::Error::msg(span, "division by zero"))?; - return Ok(ir::Value::Integer(number)); - } - ir::IrBinaryOp::Shl => { - let b = u32::try_from(b).map_err(|_| { - compile::Error::msg(&ir.rhs, "cannot be converted to shift operand") - })?; + let a = a.borrow_kind_ref().with_span(ir)?; + let b = b.borrow_kind_ref().with_span(ir)?; - let n = a.shl(b); - return Ok(ir::Value::Integer(n)); - } - ir::IrBinaryOp::Shr => { - let b = u32::try_from(b).map_err(|_| { - compile::Error::msg(&ir.rhs, "cannot be converted to shift operand") - })?; + let kind = 'out: { + match (&*a, &*b) { + (ValueKind::Integer(a), ValueKind::Integer(b)) => match ir.op { + ir::IrBinaryOp::Add => { + break 'out ValueKind::Integer(a.add(b)); + } + ir::IrBinaryOp::Sub => { + break 'out ValueKind::Integer(a.sub(b)); + } + ir::IrBinaryOp::Mul => { + break 'out ValueKind::Integer(a.mul(b)); + } + ir::IrBinaryOp::Div => { + let number = a + .checked_div(*b) + .ok_or_else(|| compile::Error::msg(span, "division by zero"))?; + break 'out ValueKind::Integer(number); + } + ir::IrBinaryOp::Shl => { + let b = u32::try_from(*b).map_err(|_| { + compile::Error::msg(&ir.rhs, "cannot be converted to shift operand") + })?; - let n = a.shr(b); - return Ok(ir::Value::Integer(n)); + let n = a.shl(b); + break 'out ValueKind::Integer(n); + } + ir::IrBinaryOp::Shr => { + let b = u32::try_from(*b).map_err(|_| { + compile::Error::msg(&ir.rhs, "cannot be converted to shift operand") + })?; + + let n = a.shr(b); + break 'out ValueKind::Integer(n); + } + ir::IrBinaryOp::Lt => break 'out ValueKind::Bool(a < b), + ir::IrBinaryOp::Lte => break 'out ValueKind::Bool(a <= b), + ir::IrBinaryOp::Eq => break 'out ValueKind::Bool(a == b), + ir::IrBinaryOp::Gt => break 'out ValueKind::Bool(a > b), + ir::IrBinaryOp::Gte => break 'out ValueKind::Bool(a >= b), + }, + (ValueKind::Float(a), ValueKind::Float(b)) => { + #[allow(clippy::float_cmp)] + match ir.op { + ir::IrBinaryOp::Add => break 'out ValueKind::Float(a + b), + ir::IrBinaryOp::Sub => break 'out ValueKind::Float(a - b), + ir::IrBinaryOp::Mul => break 'out ValueKind::Float(a * b), + ir::IrBinaryOp::Div => break 'out ValueKind::Float(a / b), + ir::IrBinaryOp::Lt => break 'out ValueKind::Bool(a < b), + ir::IrBinaryOp::Lte => break 'out ValueKind::Bool(a <= b), + ir::IrBinaryOp::Eq => break 'out ValueKind::Bool(a == b), + ir::IrBinaryOp::Gt => break 'out ValueKind::Bool(a > b), + ir::IrBinaryOp::Gte => break 'out ValueKind::Bool(a >= b), + _ => (), + }; } - ir::IrBinaryOp::Lt => return Ok(ir::Value::Bool(a < b)), - ir::IrBinaryOp::Lte => return Ok(ir::Value::Bool(a <= b)), - ir::IrBinaryOp::Eq => return Ok(ir::Value::Bool(a == b)), - ir::IrBinaryOp::Gt => return Ok(ir::Value::Bool(a > b)), - ir::IrBinaryOp::Gte => return Ok(ir::Value::Bool(a >= b)), - }, - (ir::Value::Float(a), ir::Value::Float(b)) => { - #[allow(clippy::float_cmp)] - match ir.op { - ir::IrBinaryOp::Add => return Ok(ir::Value::Float(a + b)), - ir::IrBinaryOp::Sub => return Ok(ir::Value::Float(a - b)), - ir::IrBinaryOp::Mul => return Ok(ir::Value::Float(a * b)), - ir::IrBinaryOp::Div => return Ok(ir::Value::Float(a / b)), - ir::IrBinaryOp::Lt => return Ok(ir::Value::Bool(a < b)), - ir::IrBinaryOp::Lte => return Ok(ir::Value::Bool(a <= b)), - ir::IrBinaryOp::Eq => return Ok(ir::Value::Bool(a == b)), - ir::IrBinaryOp::Gt => return Ok(ir::Value::Bool(a > b)), - ir::IrBinaryOp::Gte => return Ok(ir::Value::Bool(a >= b)), - _ => (), - }; - } - (ir::Value::String(a), ir::Value::String(b)) => { - if let ir::IrBinaryOp::Add = ir.op { - return Ok(ir::Value::String(add_strings(span, &a, &b)?)); + (ValueKind::String(a), ValueKind::String(b)) => { + if let ir::IrBinaryOp::Add = ir.op { + break 'out ValueKind::String(add_strings(a, b).with_span(span)?); + } } + _ => (), } - _ => (), - } - return Err(EvalOutcome::not_const(span)); - - fn add_strings( - span: Span, - a: &Shared, - b: &Shared, - ) -> compile::Result> { - let a = a.borrow_ref().with_span(span)?; - let b = b.borrow_ref().with_span(span)?; - let mut a = (*a).try_clone()?; - a.try_push_str(&b)?; - Ok(Shared::new(a).with_span(span)?) - } + return Err(EvalOutcome::not_const(span)); + }; + + Ok(Value::try_from(kind).with_span(span)?) } fn eval_ir_branches( ir: &ir::IrBranches, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { for (ir_condition, branch) in &ir.branches { let guard = interp.scopes.push()?; let value = eval_ir_condition(ir_condition, interp, used)?; - let output = if as_bool(ir_condition.span(), value)? { + let output = if value.as_bool().with_span(ir_condition)? { Some(eval_ir_scope(branch, interp, used)?) } else { None @@ -175,14 +170,14 @@ fn eval_ir_branches( return eval_ir_scope(branch, interp, used); } - Ok(ir::Value::EmptyTuple) + Ok(Value::empty().with_span(ir)?) } fn eval_ir_call( ir: &ir::IrCall, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { let mut args = Vec::new(); for arg in &ir.args { @@ -196,35 +191,37 @@ fn eval_ir_condition( ir: &ir::IrCondition, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { - Ok(ir::Value::Bool(match ir { +) -> Result { + let value = match ir { ir::IrCondition::Ir(ir) => { let value = eval_ir(ir, interp, used)?; - as_bool(ir.span(), value)? + value.as_bool().with_span(ir)? } ir::IrCondition::Let(ir_let) => { let value = eval_ir(&ir_let.ir, interp, used)?; ir_let.pat.matches(interp, value, ir)? } - })) + }; + + Ok(Value::try_from(value).with_span(ir)?) } fn eval_ir_decl( ir: &ir::IrDecl, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { interp.budget.take(ir)?; let value = eval_ir(&ir.value, interp, used)?; interp.scopes.decl(&ir.name, value).with_span(ir)?; - Ok(ir::Value::EmptyTuple) + Ok(Value::empty().with_span(ir)?) } fn eval_ir_loop( ir: &ir::IrLoop, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { let span = ir.span(); interp.budget.take(span)?; @@ -236,7 +233,7 @@ fn eval_ir_loop( let value = eval_ir_condition(condition, interp, used)?; - if !as_bool(condition.span(), value)? { + if !value.as_bool().with_span(condition)? { break None; } } @@ -268,7 +265,7 @@ fn eval_ir_loop( Ok(value) } else { - Ok(ir::Value::EmptyTuple) + Ok(Value::empty().with_span(ir)?) } } @@ -276,21 +273,22 @@ fn eval_ir_object( ir: &ir::IrObject, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { - let mut object = HashMap::try_with_capacity(ir.assignments.len())?; +) -> Result { + let mut object = Object::with_capacity(ir.assignments.len())?; for (key, value) in ir.assignments.iter() { - object.try_insert(key.as_ref().try_to_owned()?, eval_ir(value, interp, used)?)?; + let key = key.as_ref().try_to_owned()?; + object.insert(key, eval_ir(value, interp, used)?)?; } - Ok(ir::Value::Object(Shared::new(object).with_span(ir)?)) + Ok(Value::try_from(object).with_span(ir)?) } fn eval_ir_scope( ir: &ir::IrScope, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { interp.budget.take(ir)?; let guard = interp.scopes.push()?; @@ -301,7 +299,7 @@ fn eval_ir_scope( let value = if let Some(last) = &ir.last { eval_ir(last, interp, used)? } else { - ir::Value::EmptyTuple + Value::empty().with_span(ir)? }; interp.scopes.pop(guard).with_span(ir)?; @@ -312,18 +310,18 @@ fn eval_ir_set( ir: &ir::IrSet, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { interp.budget.take(ir)?; let value = eval_ir(&ir.value, interp, used)?; interp.scopes.set_target(&ir.target, value)?; - Ok(ir::Value::EmptyTuple) + Ok(Value::empty().with_span(ir)?) } fn eval_ir_template( ir: &ir::IrTemplate, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { interp.budget.take(ir)?; let mut buf = String::new(); @@ -335,21 +333,21 @@ fn eval_ir_template( } ir::IrTemplateComponent::Ir(ir) => { let const_value = eval_ir(ir, interp, used)?; + let kind = const_value.borrow_kind_ref().with_span(ir)?; - match const_value { - ir::Value::Integer(integer) => { - write!(buf, "{}", integer)?; + match &*kind { + ValueKind::Integer(integer) => { + write!(buf, "{integer}")?; } - ir::Value::Float(float) => { + ValueKind::Float(float) => { let mut buffer = ryu::Buffer::new(); - buf.try_push_str(buffer.format(float))?; + buf.try_push_str(buffer.format(*float))?; } - ir::Value::Bool(b) => { - write!(buf, "{}", b)?; + ValueKind::Bool(b) => { + write!(buf, "{b}")?; } - ir::Value::String(s) => { - let s = s.borrow_ref().with_span(ir)?; - buf.try_push_str(&s)?; + ValueKind::String(s) => { + buf.try_push_str(s)?; } _ => { return Err(EvalOutcome::not_const(ir)); @@ -359,37 +357,37 @@ fn eval_ir_template( } } - Ok(ir::Value::String(Shared::new(buf).with_span(ir)?)) + Ok(Value::try_from(buf).with_span(ir)?) } fn eval_ir_tuple( ir: &ir::Tuple, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { let mut items = Vec::try_with_capacity(ir.items.len())?; for item in ir.items.iter() { items.try_push(eval_ir(item, interp, used)?)?; } - Ok(ir::Value::Tuple( - Shared::new(items.try_into_boxed_slice()?).with_span(ir)?, - )) + let tuple = OwnedTuple::try_from(items).with_span(ir)?; + Ok(Value::try_from(tuple).with_span(ir)?) } fn eval_ir_vec( ir: &ir::IrVec, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { let mut vec = Vec::try_with_capacity(ir.items.len())?; for item in ir.items.iter() { vec.try_push(eval_ir(item, interp, used)?)?; } - Ok(ir::Value::Vec(Shared::new(vec).with_span(ir)?)) + let vec = crate::runtime::Vec::from(vec); + Ok(Value::try_from(vec).with_span(ir)?) } /// IrEval the interior expression. @@ -397,7 +395,7 @@ pub(crate) fn eval_ir( ir: &ir::Ir, interp: &mut ir::Interpreter<'_, '_>, used: Used, -) -> Result { +) -> Result { interp.budget.take(ir)?; match &ir.kind { diff --git a/crates/rune/src/compile/ir/interpreter.rs b/crates/rune/src/compile/ir/interpreter.rs index 0e8c9da0f..14c2b9241 100644 --- a/crates/rune/src/compile/ir/interpreter.rs +++ b/crates/rune/src/compile/ir/interpreter.rs @@ -8,7 +8,7 @@ use crate::compile::{self, IrErrorKind, ItemId, ModId, WithSpan}; use crate::hir; use crate::parse::NonZeroId; use crate::query::{Query, Used}; -use crate::runtime::{ConstValue, Object, OwnedTuple}; +use crate::runtime::{ConstValue, Object, OwnedTuple, Value, ValueKind}; /// The interpreter that executed [Ir][crate::ir::Ir]. pub struct Interpreter<'a, 'arena> { @@ -53,7 +53,7 @@ impl Interpreter<'_, '_> { }, }; - let const_value = ir_value.into_const(ir)?; + let const_value: ConstValue = crate::from_value(ir_value).with_span(ir)?; if self .q @@ -68,7 +68,7 @@ impl Interpreter<'_, '_> { } /// Evaluate to an ir value. - pub(crate) fn eval_value(&mut self, ir: &ir::Ir, used: Used) -> compile::Result { + pub(crate) fn eval_value(&mut self, ir: &ir::Ir, used: Used) -> compile::Result { match ir::eval_ir(ir, self, used) { Ok(ir_value) => Ok(ir_value), Err(outcome) => match outcome { @@ -92,7 +92,7 @@ impl Interpreter<'_, '_> { span: &dyn Spanned, name: &hir::OwnedName, used: Used, - ) -> compile::Result { + ) -> compile::Result { if let Some(ir_value) = self.scopes.try_get(name) { return Ok(ir_value.try_clone()?); } @@ -106,7 +106,7 @@ impl Interpreter<'_, '_> { .alloc_item(base.extended(name.try_to_string()?)?)?; if let Some(const_value) = self.q.consts.get(item) { - return Ok(ir::Value::from_const(const_value).with_span(span)?); + return Ok(const_value.as_value().with_span(span)?); } if let Some(meta) = self.q.query_meta(span, item, used)? { @@ -119,7 +119,7 @@ impl Interpreter<'_, '_> { )); }; - return Ok(ir::Value::from_const(const_value).with_span(span)?); + return Ok(const_value.as_value().with_span(span)?); } _ => { return Err(compile::Error::new( @@ -158,9 +158,9 @@ impl Interpreter<'_, '_> { &mut self, spanned: S, id: NonZeroId, - args: Vec, + args: Vec, used: Used, - ) -> compile::Result + ) -> compile::Result where S: Copy + Spanned, { @@ -191,23 +191,21 @@ impl Interpreter<'_, '_> { impl ir::Scopes { /// Get the given target as mut. - pub(crate) fn get_target(&mut self, ir_target: &ir::IrTarget) -> compile::Result { + pub(crate) fn get_target(&mut self, ir_target: &ir::IrTarget) -> compile::Result { match &ir_target.kind { ir::IrTargetKind::Name(name) => Ok(self.get_name(name, ir_target)?.try_clone()?), ir::IrTargetKind::Field(ir_target, field) => { let value = self.get_target(ir_target)?; - match value { - ir::Value::Object(object) => { - let object = object.borrow_ref().with_span(ir_target)?; - + match &*value.borrow_kind_ref().with_span(ir_target)? { + ValueKind::Object(object) => { if let Some(value) = object.get(field.as_ref()).try_cloned()? { return Ok(value); } } actual => { return Err(compile::Error::expected_type::<_, OwnedTuple>( - ir_target, &actual, + ir_target, actual, )) } }; @@ -222,24 +220,20 @@ impl ir::Scopes { ir::IrTargetKind::Index(target, index) => { let value = self.get_target(target)?; - match value { - ir::Value::Vec(vec) => { - let vec = vec.borrow_ref().with_span(ir_target)?; - + match &*value.borrow_kind_ref().with_span(ir_target)? { + ValueKind::Vec(vec) => { if let Some(value) = vec.get(*index).try_cloned()? { return Ok(value); } } - ir::Value::Tuple(tuple) => { - let tuple = tuple.borrow_ref().with_span(ir_target)?; - + ValueKind::Tuple(tuple) => { if let Some(value) = tuple.get(*index).try_cloned()? { return Ok(value); } } actual => { return Err(compile::Error::expected_type::<_, OwnedTuple>( - ir_target, &actual, + ir_target, actual, )) } }; @@ -256,7 +250,7 @@ impl ir::Scopes { pub(crate) fn set_target( &mut self, ir_target: &ir::IrTarget, - value: ir::Value, + value: Value, ) -> compile::Result<()> { match &ir_target.kind { ir::IrTargetKind::Name(name) => { @@ -266,14 +260,14 @@ impl ir::Scopes { ir::IrTargetKind::Field(target, field) => { let current = self.get_target(target)?; - match current { - ir::Value::Object(object) => { - let mut object = object.borrow_mut().with_span(ir_target)?; - object.try_insert(field.as_ref().try_to_owned()?, value)?; + match &mut *current.borrow_kind_mut().with_span(ir_target)? { + ValueKind::Object(object) => { + let field = field.as_ref().try_to_owned()?; + object.insert(field, value).with_span(ir_target)?; } actual => { return Err(compile::Error::expected_type::<_, Object>( - ir_target, &actual, + ir_target, actual, )); } } @@ -283,18 +277,14 @@ impl ir::Scopes { ir::IrTargetKind::Index(target, index) => { let current = self.get_target(target)?; - match current { - ir::Value::Vec(vec) => { - let mut vec = vec.borrow_mut().with_span(ir_target)?; - + match &mut *current.borrow_kind_mut().with_span(ir_target)? { + ValueKind::Vec(vec) => { if let Some(current) = vec.get_mut(*index) { *current = value; return Ok(()); } } - ir::Value::Tuple(tuple) => { - let mut tuple = tuple.borrow_mut().with_span(ir_target)?; - + ValueKind::Tuple(tuple) => { if let Some(current) = tuple.get_mut(*index) { *current = value; return Ok(()); @@ -302,7 +292,7 @@ impl ir::Scopes { } actual => { return Err(compile::Error::expected_type::<_, OwnedTuple>( - ir_target, &actual, + ir_target, actual, )); } }; @@ -316,7 +306,7 @@ impl ir::Scopes { pub(crate) fn mut_target( &mut self, ir_target: &ir::IrTarget, - op: impl FnOnce(&mut ir::Value) -> compile::Result<()>, + op: impl FnOnce(&mut Value) -> compile::Result<()>, ) -> compile::Result<()> { match &ir_target.kind { ir::IrTargetKind::Name(name) => { @@ -325,11 +315,10 @@ impl ir::Scopes { } ir::IrTargetKind::Field(target, field) => { let current = self.get_target(target)?; + let mut kind = current.borrow_kind_mut().with_span(ir_target)?; - match current { - ir::Value::Object(object) => { - let mut object = object.borrow_mut().with_span(ir_target)?; - + match &mut *kind { + ValueKind::Object(object) => { let Some(value) = object.get_mut(field.as_ref()) else { return Err(compile::Error::new( ir_target, @@ -342,17 +331,16 @@ impl ir::Scopes { op(value) } actual => Err(compile::Error::expected_type::<_, Object>( - ir_target, &actual, + ir_target, actual, )), } } ir::IrTargetKind::Index(target, index) => { let current = self.get_target(target)?; + let mut kind = current.borrow_kind_mut().with_span(ir_target)?; - match current { - ir::Value::Vec(vec) => { - let mut vec = vec.borrow_mut().with_span(ir_target)?; - + match &mut *kind { + ValueKind::Vec(vec) => { let value = vec.get_mut(*index).ok_or_else(|| { compile::Error::new( ir_target, @@ -362,9 +350,7 @@ impl ir::Scopes { op(value) } - ir::Value::Tuple(tuple) => { - let mut tuple = tuple.borrow_mut().with_span(ir_target)?; - + ValueKind::Tuple(tuple) => { let value = tuple.get_mut(*index).ok_or_else(|| { compile::Error::new( ir_target, @@ -375,7 +361,7 @@ impl ir::Scopes { op(value) } actual => Err(compile::Error::expected_type::<_, OwnedTuple>( - ir_target, &actual, + ir_target, actual, )), } } diff --git a/crates/rune/src/compile/ir/scopes.rs b/crates/rune/src/compile/ir/scopes.rs index 66b35db2c..ce8ce5de3 100644 --- a/crates/rune/src/compile/ir/scopes.rs +++ b/crates/rune/src/compile/ir/scopes.rs @@ -1,9 +1,9 @@ use crate::alloc::prelude::*; use crate::alloc::{self, try_vec, Box, HashMap, Vec}; use crate::ast::Spanned; -use crate::compile::ir; use crate::compile::{self, ErrorKind}; use crate::hir; +use crate::runtime::Value; /// Error indicating that a local variable is missing. pub(crate) struct MissingLocal(pub(crate) Box); @@ -33,11 +33,7 @@ impl Scopes { } /// Declare a value in the scope. - pub(crate) fn decl( - &mut self, - name: &hir::OwnedName, - value: ir::Value, - ) -> Result<(), ErrorKind> { + pub(crate) fn decl(&mut self, name: &hir::OwnedName, value: Value) -> Result<(), ErrorKind> { let last = self .last_mut() .ok_or_else(|| ErrorKind::msg("Expected at least one scope"))?; @@ -46,7 +42,7 @@ impl Scopes { } /// Try to get the value out from the scopes. - pub(crate) fn try_get(&self, name: &hir::OwnedName) -> Option<&ir::Value> { + pub(crate) fn try_get(&self, name: &hir::OwnedName) -> Option<&Value> { for scope in self.scopes.iter().rev() { if let Some(current) = scope.locals.get(name) { return Some(current); @@ -66,7 +62,7 @@ impl Scopes { &self, name: &hir::OwnedName, span: &dyn Spanned, - ) -> compile::Result<&ir::Value> { + ) -> compile::Result<&Value> { for scope in self.scopes.iter().rev() { if let Some(current) = scope.locals.get(name) { return Ok(current); @@ -89,7 +85,7 @@ impl Scopes { &mut self, name: &hir::OwnedName, span: &dyn Spanned, - ) -> compile::Result<&mut ir::Value> { + ) -> compile::Result<&mut Value> { for scope in self.scopes.iter_mut().rev() { if let Some(current) = scope.locals.get_mut(name) { return Ok(current); @@ -157,7 +153,7 @@ enum ScopeKind { pub(crate) struct Scope { kind: ScopeKind, /// Locals in the current scope. - locals: HashMap, + locals: HashMap, } impl Default for Scope { diff --git a/crates/rune/src/compile/ir/value.rs b/crates/rune/src/compile/ir/value.rs deleted file mode 100644 index 8de31a002..000000000 --- a/crates/rune/src/compile/ir/value.rs +++ /dev/null @@ -1,177 +0,0 @@ -use crate as rune; -use crate::alloc::prelude::*; -use crate::alloc::{self, Box, HashMap, String, Vec}; -use crate::ast::Spanned; -use crate::compile::{self, WithSpan}; -use crate::runtime as rt; -use crate::runtime::{Bytes, ConstValue, Shared, TypeInfo}; - -/// A constant value. -#[derive(Debug, TryClone)] -pub enum Value { - /// A constant unit. - EmptyTuple, - /// A byte. - Byte(u8), - /// A character. - Char(char), - /// A boolean constant value. - Bool(bool), - /// An integer constant. - Integer(i64), - /// An float constant. - Float(f64), - /// A string constant designated by its slot. - String(Shared), - /// An optional value. - Option(Shared>), - /// A byte string. - Bytes(Shared), - /// A vector of values. - Vec(Shared>), - /// An anonymous tuple. - Tuple(Shared>), - /// An anonymous object. - Object(Shared>), -} - -impl Value { - /// Try to coerce into boolean. - pub fn into_bool(self) -> Result { - match self { - Self::Bool(value) => Ok(value), - value => Err(value), - } - } - - /// Try to coerce into an integer of the specified type. - pub fn into_integer(self) -> Option - where - T: TryFrom, - { - match self { - Self::Integer(n) => T::try_from(n).ok(), - _ => None, - } - } - - /// Convert a constant value into an interpreter value. - pub(crate) fn from_const(value: &ConstValue) -> alloc::Result { - Ok(match value { - ConstValue::EmptyTuple => Self::EmptyTuple, - ConstValue::Byte(b) => Self::Byte(*b), - ConstValue::Char(c) => Self::Char(*c), - ConstValue::Bool(b) => Self::Bool(*b), - ConstValue::Integer(n) => Self::Integer(*n), - ConstValue::Float(n) => Self::Float(*n), - ConstValue::String(s) => Self::String(Shared::new(s.try_clone()?)?), - ConstValue::Bytes(b) => Self::Bytes(Shared::new(b.try_clone()?)?), - ConstValue::Option(option) => Self::Option(Shared::new(match option { - Some(some) => Some(Self::from_const(some)?), - None => None, - })?), - ConstValue::Vec(vec) => { - let mut ir_vec = Vec::try_with_capacity(vec.len())?; - - for value in vec { - ir_vec.try_push(Self::from_const(value)?)?; - } - - Self::Vec(Shared::new(ir_vec)?) - } - ConstValue::Tuple(tuple) => { - let mut ir_tuple = Vec::try_with_capacity(tuple.len())?; - - for value in tuple.iter() { - ir_tuple.try_push(Self::from_const(value)?)?; - } - - Self::Tuple(Shared::new(ir_tuple.try_into_boxed_slice()?)?) - } - ConstValue::Object(object) => { - let mut ir_object = HashMap::try_with_capacity(object.len())?; - - for (key, value) in object { - ir_object.try_insert(key.try_clone()?, Self::from_const(value)?)?; - } - - Self::Object(Shared::new(ir_object)?) - } - }) - } - - /// Convert into constant value. - pub(crate) fn into_const(self, spanned: S) -> compile::Result - where - S: Copy + Spanned, - { - Ok(match self { - Value::EmptyTuple => ConstValue::EmptyTuple, - Value::Byte(b) => ConstValue::Byte(b), - Value::Char(c) => ConstValue::Char(c), - Value::Bool(b) => ConstValue::Bool(b), - Value::Integer(n) => ConstValue::Integer(n), - Value::Float(f) => ConstValue::Float(f), - Value::String(s) => { - let s = s.take().with_span(spanned)?; - ConstValue::String(s) - } - Value::Bytes(b) => { - let b = b.take().with_span(spanned)?; - ConstValue::Bytes(b) - } - Self::Option(option) => ConstValue::Option(match option.take().with_span(spanned)? { - Some(value) => Some(Box::try_new(value.into_const(spanned)?)?), - None => None, - }), - Value::Vec(vec) => { - let vec = vec.take().with_span(spanned)?; - let mut const_vec = Vec::try_with_capacity(vec.len())?; - - for value in vec { - const_vec.try_push(value.into_const(spanned)?)?; - } - - ConstValue::Vec(const_vec) - } - Value::Tuple(tuple) => { - let tuple = tuple.take().with_span(spanned)?; - let mut const_tuple = Vec::try_with_capacity(tuple.len())?; - - for value in Vec::from(tuple) { - const_tuple.try_push(value.into_const(spanned)?)?; - } - - ConstValue::Tuple(const_tuple.try_into_boxed_slice()?) - } - Value::Object(object) => { - let object = object.take().with_span(spanned)?; - let mut const_object = HashMap::try_with_capacity(object.len())?; - - for (key, value) in object { - const_object.try_insert(key, value.into_const(spanned)?)?; - } - - ConstValue::Object(const_object) - } - }) - } - - /// Get the type information of the value. - pub(crate) fn type_info(&self) -> TypeInfo { - match self { - Self::EmptyTuple => TypeInfo::StaticType(rt::static_type::TUPLE_TYPE), - Self::Byte(..) => TypeInfo::StaticType(rt::static_type::BYTE_TYPE), - Self::Char(..) => TypeInfo::StaticType(rt::static_type::CHAR_TYPE), - Self::Bool(..) => TypeInfo::StaticType(rt::static_type::BOOL_TYPE), - Self::String(..) => TypeInfo::StaticType(rt::static_type::STRING_TYPE), - Self::Bytes(..) => TypeInfo::StaticType(rt::static_type::BYTES_TYPE), - Self::Integer(..) => TypeInfo::StaticType(rt::static_type::INTEGER_TYPE), - Self::Float(..) => TypeInfo::StaticType(rt::static_type::FLOAT_TYPE), - Self::Option(..) => TypeInfo::StaticType(rt::static_type::OPTION_TYPE), - Self::Vec(..) => TypeInfo::StaticType(rt::static_type::VEC_TYPE), - Self::Tuple(..) => TypeInfo::StaticType(rt::static_type::TUPLE_TYPE), - Self::Object(..) => TypeInfo::StaticType(rt::static_type::OBJECT_TYPE), - } - } -} diff --git a/crates/rune/src/compile/prelude.rs b/crates/rune/src/compile/prelude.rs index a2caa6893..fb5766234 100644 --- a/crates/rune/src/compile/prelude.rs +++ b/crates/rune/src/compile/prelude.rs @@ -24,6 +24,7 @@ impl Prelude { this.add_prelude("char", ["char"])?; this.add_prelude("dbg", ["io", "dbg"])?; this.add_prelude("drop", ["mem", "drop"])?; + this.add_prelude("clone", ["clone", "clone"])?; this.add_prelude("Err", ["result", "Result", "Err"])?; this.add_prelude("file", ["macros", "builtin", "file"])?; this.add_prelude("format", ["fmt", "format"])?; diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index 8731bb657..812c65b34 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -163,7 +163,7 @@ impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> { interpreter.module = query_const_fn.item_meta.module; interpreter.item = query_const_fn.item_meta.item; let value = interpreter.eval_value(&query_const_fn.ir_fn.ir, Used::Used)?; - value.into_const(span) + Ok(crate::from_value(value).with_span(span)?) } } diff --git a/crates/rune/src/doc/build.rs b/crates/rune/src/doc/build.rs index f3e00d69b..d06ff423c 100644 --- a/crates/rune/src/doc/build.rs +++ b/crates/rune/src/doc/build.rs @@ -58,7 +58,9 @@ impl<'m> Builder<'m> { } mod embed { + #[cfg(debug_assertions)] use rust_alloc::boxed::Box; + #[cfg(debug_assertions)] use rust_alloc::string::String; use rust_embed::RustEmbed; @@ -218,7 +220,7 @@ pub(crate) fn build( for builder in builders { cx.state = builder.state; artifacts.asset(false, &cx.state.path, || { - Ok((builder.builder)(&cx)?.into_bytes().try_into()?) + Ok((builder.builder)(&cx)?.into_bytes().into()) })?; } diff --git a/crates/rune/src/internal_macros.rs b/crates/rune/src/internal_macros.rs index 254e37c7c..e77a503c9 100644 --- a/crates/rune/src/internal_macros.rs +++ b/crates/rune/src/internal_macros.rs @@ -121,25 +121,15 @@ macro_rules! cfg_std { } } -/// Implements a set of common value conversions. -macro_rules! from_value { - ($ty:ty, $into:ident) => { - impl $crate::runtime::FromValue for $ty { - fn from_value(value: Value) -> $crate::runtime::VmResult { - let value = vm_try!(value.$into()); - let value = vm_try!(value.take()); - $crate::runtime::VmResult::Ok(value) - } - } - +macro_rules! from_value_ref { + ($ty:ty, $into_ref:ident, $into_mut:ident, $into:ident) => { impl $crate::runtime::UnsafeToRef for $ty { type Guard = $crate::runtime::RawRef; unsafe fn unsafe_to_ref<'a>( value: $crate::runtime::Value, ) -> $crate::runtime::VmResult<(&'a Self, Self::Guard)> { - let value = vm_try!(value.$into()); - let value = vm_try!(value.into_ref()); + let value = vm_try!(value.$into_ref()); let (value, guard) = $crate::runtime::Ref::into_raw(value); $crate::runtime::VmResult::Ok((value.as_ref(), guard)) } @@ -151,34 +141,38 @@ macro_rules! from_value { unsafe fn unsafe_to_mut<'a>( value: $crate::runtime::Value, ) -> $crate::runtime::VmResult<(&'a mut Self, Self::Guard)> { - let value = vm_try!(value.$into()); - let value = vm_try!(value.into_mut()); + let value = vm_try!(value.$into_mut()); let (mut value, guard) = $crate::runtime::Mut::into_raw(value); $crate::runtime::VmResult::Ok((value.as_mut(), guard)) } } - impl $crate::runtime::FromValue for $crate::runtime::Shared<$ty> { - #[inline] - fn from_value(value: $crate::runtime::Value) -> $crate::runtime::VmResult { - value.$into() - } - } - impl $crate::runtime::FromValue for $crate::runtime::Ref<$ty> { fn from_value(value: Value) -> $crate::runtime::VmResult { - let value = vm_try!(value.$into()); - let value = vm_try!(value.into_ref()); + let value = vm_try!(value.$into_ref()); $crate::runtime::VmResult::Ok(value) } } impl $crate::runtime::FromValue for $crate::runtime::Mut<$ty> { fn from_value(value: Value) -> VmResult { + let value = vm_try!(value.$into_mut()); + $crate::runtime::VmResult::Ok(value) + } + } + }; +} + +/// Implements a set of common value conversions. +macro_rules! from_value2 { + ($ty:ty, $into_ref:ident, $into_mut:ident, $into:ident) => { + impl $crate::runtime::FromValue for $ty { + fn from_value(value: Value) -> $crate::runtime::VmResult { let value = vm_try!(value.$into()); - let value = vm_try!(value.into_mut()); $crate::runtime::VmResult::Ok(value) } } + + from_value_ref!($ty, $into_ref, $into_mut, $into); }; } diff --git a/crates/rune/src/lib.rs b/crates/rune/src/lib.rs index 77648e2db..942255f68 100644 --- a/crates/rune/src/lib.rs +++ b/crates/rune/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.70+. +//! Minimum support: Rust 1.74+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune/src/macros/format_args.rs b/crates/rune/src/macros/format_args.rs index caa748c61..d5fad43a1 100644 --- a/crates/rune/src/macros/format_args.rs +++ b/crates/rune/src/macros/format_args.rs @@ -4,11 +4,11 @@ use crate as rune; use crate::alloc::prelude::*; use crate::alloc::{self, BTreeMap, BTreeSet, Box, HashMap, String, Vec}; use crate::ast::{self, Span, Spanned}; -use crate::compile::ir; use crate::compile::{self, WithSpan}; use crate::macros::{quote, MacroContext, Quote}; use crate::parse::{Parse, Parser, Peek, Peeker}; use crate::runtime::format; +use crate::runtime::ValueKind; /// A format specification: A format string followed by arguments to be /// formatted in accordance with that string. @@ -49,8 +49,8 @@ impl FormatArgs { } } - let format = match format { - ir::Value::String(string) => string.take().with_span(&self.format)?, + let format = match format.take_kind().with_span(&self.format)? { + ValueKind::String(string) => string, _ => { return Err(compile::Error::msg( &self.format, @@ -529,7 +529,7 @@ fn expand_format_spec<'a>( } let precision = if input_precision { - let expr = match pos.get(*count) { + let &expr = match pos.get(*count) { Some(expr) => expr, None => { return Err(compile::Error::msg( @@ -547,22 +547,24 @@ fn expand_format_spec<'a>( let value = cx.eval(expr)?; - let number = match &value { - ir::Value::Integer(n) => n.to_usize(), + let number = match *value.borrow_kind_ref().with_span(expr)? { + ValueKind::Integer(n) => n.to_usize(), _ => None, }; let precision = if let Some(number) = number { number } else { + let span = expr.span(); + return Err(compile::Error::msg( - expr.span(), + span, format!( "expected position argument #{} \ to be a positive number in use as precision, \ but got `{}`", count, - value.type_info() + value.type_info().with_span(span)? ), )); }; diff --git a/crates/rune/src/macros/macro_context.rs b/crates/rune/src/macros/macro_context.rs index f009e46c2..d5c4daf27 100644 --- a/crates/rune/src/macros/macro_context.rs +++ b/crates/rune/src/macros/macro_context.rs @@ -5,11 +5,11 @@ use core::fmt; use crate::alloc; use crate::ast; use crate::ast::Span; -use crate::compile::ir; use crate::compile::{self, ErrorKind, ItemMeta}; use crate::indexing::Indexer; use crate::macros::{IntoLit, ToTokens, TokenStream}; use crate::parse::{Parse, Resolve}; +use crate::runtime::Value; use crate::{Source, SourceId}; cfg_std! { @@ -142,13 +142,13 @@ impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { /// let expr = p.parse_all::()?; /// let value = cx.eval(&expr)?; /// - /// let integer = value.into_integer::().context("Expected integer")?; + /// let integer = value.try_as_integer::().context("Expected integer")?; /// assert_eq!(3, integer); /// Ok(()) /// })?; /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn eval(&mut self, target: &ast::Expr) -> compile::Result { + pub fn eval(&mut self, target: &ast::Expr) -> compile::Result { target.eval(self) } diff --git a/crates/rune/src/module/module.rs b/crates/rune/src/module/module.rs index ea1ddd8d2..d38b5f21e 100644 --- a/crates/rune/src/module/module.rs +++ b/crates/rune/src/module/module.rs @@ -1686,7 +1686,7 @@ impl Module { /// let mut number = 0; /// /// for _ in 0..args { - /// number += vm_try!(vm_try!(stack.pop()).into_integer()); + /// number += vm_try!(vm_try!(stack.pop()).as_integer()); /// } /// /// stack.push(vm_try!(number.to_value())); diff --git a/crates/rune/src/modules.rs b/crates/rune/src/modules.rs index 372667d8d..86737af4a 100644 --- a/crates/rune/src/modules.rs +++ b/crates/rune/src/modules.rs @@ -9,6 +9,7 @@ pub mod bytes; #[cfg(feature = "capture-io")] pub mod capture_io; pub mod char; +pub mod clone; pub mod cmp; pub mod collections; pub mod core; diff --git a/crates/rune/src/modules/capture_io.rs b/crates/rune/src/modules/capture_io.rs index 672cf0428..82128d93a 100644 --- a/crates/rune/src/modules/capture_io.rs +++ b/crates/rune/src/modules/capture_io.rs @@ -107,6 +107,6 @@ fn dbg_impl(o: &mut Vec, stack: &mut Stack, args: usize) -> VmResult<()> { vm_try!(writeln!(o, "{:?}", value).map_err(VmError::panic)); } - vm_try!(stack.push(Value::EmptyTuple)); + vm_try!(stack.push(vm_try!(Value::empty()))); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/char.rs b/crates/rune/src/modules/char.rs index 3b84aa0ff..e7a56e624 100644 --- a/crates/rune/src/modules/char.rs +++ b/crates/rune/src/modules/char.rs @@ -40,7 +40,11 @@ fn from_i64(value: i64) -> VmResult> { } else if value > u32::MAX as i64 { VmResult::err(VmErrorKind::Overflow) } else { - VmResult::Ok(core::char::from_u32(value as u32).map(|v| v.into())) + let Some(c) = core::char::from_u32(value as u32) else { + return VmResult::Ok(None); + }; + + VmResult::Ok(Some(vm_try!(Value::try_from(c)))) } } @@ -53,8 +57,8 @@ fn from_i64(value: i64) -> VmResult> { /// assert_eq!(c.to_i64(), 80); /// ``` #[rune::function(instance)] -fn to_i64(value: char) -> Value { - (value as i64).into() +fn to_i64(value: char) -> VmResult { + VmResult::Ok(vm_try!(Value::try_from(value as i64))) } /// Returns `true` if this `char` has the `Alphabetic` property. diff --git a/crates/rune/src/modules/clone.rs b/crates/rune/src/modules/clone.rs new file mode 100644 index 000000000..b9cbd3730 --- /dev/null +++ b/crates/rune/src/modules/clone.rs @@ -0,0 +1,37 @@ +//! The `std::clone` module. + +use crate as rune; +use crate::runtime::{Value, VmResult}; +use crate::{ContextError, Module}; + +#[rune::module(::std::clone)] +/// The `std::clone` module. +/// +/// This module defines methods and types used when cloning values. +/// +/// By default all values in rune are structurally shared, so in order to get a +/// unique instance of it you must call [`clone`] over it. +pub fn module() -> Result { + let mut module = Module::from_meta(self::module_meta)?; + module.function_meta(clone)?; + Ok(module) +} + +/// Clone the specified `value`. +/// +/// # Examples +/// +/// ```rune +/// let a = 42; +/// let b = a; +/// let c = clone(a); +/// +/// a += 1; +/// assert_eq!(a, 43); +/// assert_eq!(b, 43); +/// assert_eq!(c, 42); +/// ``` +#[rune::function] +fn clone(value: Value) -> VmResult { + value.clone_() +} diff --git a/crates/rune/src/modules/core.rs b/crates/rune/src/modules/core.rs index 5df30cf2c..cf8dad06b 100644 --- a/crates/rune/src/modules/core.rs +++ b/crates/rune/src/modules/core.rs @@ -55,47 +55,13 @@ fn panic(message: &str) -> VmResult<()> { /// let value = Some(42); /// assert!(is_readable(value)); /// let value2 = value.map(|v| v + 1); +/// drop(value); /// assert!(!is_readable(value)); /// assert_eq!(value2, Some(43)); /// ``` #[rune::function] fn is_readable(value: Value) -> bool { - match value { - Value::EmptyTuple => true, - Value::Bool(_) => true, - Value::Byte(_) => true, - Value::Char(_) => true, - Value::Integer(_) => true, - Value::Float(_) => true, - Value::Type(_) => true, - Value::Ordering(_) => true, - Value::String(value) => value.is_readable(), - Value::Bytes(value) => value.is_readable(), - Value::Vec(value) => value.is_readable(), - Value::Tuple(value) => value.is_readable(), - Value::Object(value) => value.is_readable(), - Value::RangeFrom(value) => value.is_readable(), - Value::RangeFull(value) => value.is_readable(), - Value::RangeInclusive(value) => value.is_readable(), - Value::RangeToInclusive(value) => value.is_readable(), - Value::RangeTo(value) => value.is_readable(), - Value::Range(value) => value.is_readable(), - Value::ControlFlow(value) => value.is_readable(), - Value::Future(value) => value.is_readable(), - Value::Stream(value) => value.is_readable(), - Value::Generator(value) => value.is_readable(), - Value::GeneratorState(value) => value.is_readable(), - Value::Option(value) => value.is_readable(), - Value::Result(value) => value.is_readable(), - Value::EmptyStruct(value) => value.is_readable(), - Value::TupleStruct(value) => value.is_readable(), - Value::Struct(value) => value.is_readable(), - Value::Variant(value) => value.is_readable(), - Value::Function(value) => value.is_readable(), - Value::Format(_) => true, - Value::Iterator(value) => value.is_readable(), - Value::Any(value) => value.is_readable(), - } + value.is_readable() } /// Test if the given `value` is writable. @@ -109,47 +75,32 @@ fn is_readable(value: Value) -> bool { /// let value = Some(42); /// assert!(is_writable(value)); /// let value2 = value.map(|v| v + 1); +/// drop(value); /// assert!(!is_writable(value)); /// assert_eq!(value2, Some(43)); /// ``` #[rune::function] fn is_writable(value: Value) -> bool { - match value { - Value::EmptyTuple => true, - Value::Bool(_) => true, - Value::Byte(_) => true, - Value::Char(_) => true, - Value::Integer(_) => true, - Value::Float(_) => true, - Value::Type(_) => true, - Value::Ordering(_) => true, - Value::String(value) => value.is_writable(), - Value::Bytes(value) => value.is_writable(), - Value::Vec(value) => value.is_writable(), - Value::Tuple(value) => value.is_writable(), - Value::Object(value) => value.is_writable(), - Value::RangeFrom(value) => value.is_writable(), - Value::RangeFull(value) => value.is_writable(), - Value::RangeInclusive(value) => value.is_writable(), - Value::RangeToInclusive(value) => value.is_writable(), - Value::RangeTo(value) => value.is_writable(), - Value::Range(value) => value.is_writable(), - Value::ControlFlow(value) => value.is_writable(), - Value::Future(value) => value.is_writable(), - Value::Stream(value) => value.is_writable(), - Value::Generator(value) => value.is_writable(), - Value::GeneratorState(value) => value.is_writable(), - Value::Option(value) => value.is_writable(), - Value::Result(value) => value.is_writable(), - Value::EmptyStruct(value) => value.is_writable(), - Value::TupleStruct(value) => value.is_writable(), - Value::Struct(value) => value.is_writable(), - Value::Variant(value) => value.is_writable(), - Value::Function(value) => value.is_writable(), - Value::Format(_) => false, - Value::Iterator(value) => value.is_writable(), - Value::Any(value) => value.is_writable(), - } + value.is_writable() +} + +/// Clone the specified `value`. +/// +/// # Examples +/// +/// ```rune +/// let a = 42; +/// let b = a; +/// let c = clone(a); +/// +/// a += 1; +/// assert_eq!(a, 43); +/// assert_eq!(b, 43); +/// assert_eq!(c, 42); +/// ``` +#[rune::function] +fn clone(value: Value) -> Value { + value.clone() } /// Stringify the given argument, causing it to expand to its underlying token diff --git a/crates/rune/src/modules/disable_io.rs b/crates/rune/src/modules/disable_io.rs index d750c271e..289d13de4 100644 --- a/crates/rune/src/modules/disable_io.rs +++ b/crates/rune/src/modules/disable_io.rs @@ -9,7 +9,7 @@ //! # Ok::<_, ContextError>(()) //! ``` -use crate::runtime::{Stack, Value, VmResult}; +use crate::runtime::{Stack, VmResult}; use crate::{ContextError, Module}; /// Provide a bunch of `std::io` functions which will cause any output to be ignored. @@ -24,7 +24,7 @@ pub fn module() -> Result { .raw_function("dbg", move |stack: &mut Stack, args: usize| { // NB: still need to maintain the stack. drop(vm_try!(stack.drain(args))); - vm_try!(stack.push(Value::from(()))); + vm_try!(stack.push(())); VmResult::Ok(()) }) .build()?; diff --git a/crates/rune/src/modules/future.rs b/crates/rune/src/modules/future.rs index 82ee5f9a7..019d3145e 100644 --- a/crates/rune/src/modules/future.rs +++ b/crates/rune/src/modules/future.rs @@ -1,7 +1,7 @@ //! The `std::future` module. use crate::alloc::Vec; -use crate::runtime::{Future, SelectFuture, Shared, Stack, Value, VmErrorKind, VmResult}; +use crate::runtime::{Future, Mut, SelectFuture, Stack, Value, ValueKind, VmErrorKind, VmResult}; use crate::{ContextError, Module}; /// Construct the `std::future` module. @@ -60,18 +60,25 @@ where let mut results = vm_try!(Vec::try_with_capacity(len)); for (index, value) in values.into_iter().enumerate() { - let future = match value { - Value::Future(future) => vm_try!(future.clone().into_mut()), - value => { + let value = vm_try!(value.clone().into_kind_mut()); + + let future = Mut::try_map(value, |kind| match kind { + ValueKind::Future(future) => Some(future), + _ => None, + }); + + let future = match future { + Ok(future) => future, + Err(actual) => { return VmResult::err([ - VmErrorKind::expected::(vm_try!(value.type_info())), + VmErrorKind::expected::(actual.type_info()), VmErrorKind::bad_argument(index), - ]) + ]); } }; futures.push(SelectFuture::new(index, future)); - vm_try!(results.try_push(Value::EmptyTuple)); + vm_try!(results.try_push(vm_try!(Value::empty()))); } while !futures.is_empty() { @@ -83,26 +90,20 @@ where } async fn join(value: Value) -> VmResult { - match value { - Value::EmptyTuple => VmResult::Ok(Value::EmptyTuple), - Value::Tuple(tuple) => { - let tuple = vm_try!(tuple.borrow_ref()); - VmResult::Ok(vm_try!( - try_join_impl(tuple.iter(), tuple.len(), |vec| VmResult::Ok(vm_try!( - Value::tuple(vec) - ))) - .await - )) - } - Value::Vec(vec) => { - let vec = vm_try!(vec.borrow_ref()); - VmResult::Ok(vm_try!( - try_join_impl(vec.iter(), vec.len(), Value::vec).await - )) - } - actual => VmResult::err([ + match &*vm_try!(value.borrow_kind_ref()) { + ValueKind::EmptyTuple => VmResult::Ok(vm_try!(Value::empty())), + ValueKind::Tuple(tuple) => VmResult::Ok(vm_try!( + try_join_impl(tuple.iter(), tuple.len(), |vec| VmResult::Ok(vm_try!( + Value::tuple(vec) + ))) + .await + )), + ValueKind::Vec(vec) => VmResult::Ok(vm_try!( + try_join_impl(vec.iter(), vec.len(), Value::vec).await + )), + _ => VmResult::err([ VmErrorKind::bad_argument(0), - VmErrorKind::expected::(vm_try!(actual.type_info())), + VmErrorKind::expected::(vm_try!(value.type_info())), ]), } } @@ -117,7 +118,7 @@ fn raw_join(stack: &mut Stack, args: usize) -> VmResult<()> { } let value = vm_try!(stack.pop()); - let value = Value::Future(vm_try!(Shared::new(vm_try!(Future::new(join(value)))))); - vm_try!(stack.push(value)); + let future = vm_try!(Future::new(join(value))); + vm_try!(stack.push(future)); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/io.rs b/crates/rune/src/modules/io.rs index b4057295f..ecb7942a4 100644 --- a/crates/rune/src/modules/io.rs +++ b/crates/rune/src/modules/io.rs @@ -80,7 +80,7 @@ fn dbg_impl(stack: &mut Stack, args: usize) -> VmResult<()> { vm_try!(writeln!(stdout, "{:?}", value).map_err(Panic::custom)); } - vm_try!(stack.push(Value::EmptyTuple)); + vm_try!(stack.push(vm_try!(Value::empty()))); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index d9d48654d..50de9cc9a 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -1,5 +1,7 @@ //! The `std::iter` module. +use core::convert::identity; + use crate as rune; use crate::alloc::String; use crate::modules::collections::VecDeque; @@ -8,7 +10,7 @@ use crate::modules::collections::{HashMap, HashSet}; #[cfg(feature = "alloc")] use crate::runtime::EnvProtocolCaller; use crate::runtime::{ - FromValue, Function, Iterator, Object, OwnedTuple, Protocol, Value, Vec, VmResult, + FromValue, Function, Iterator, Object, OwnedTuple, Protocol, Value, ValueKind, Vec, VmResult, }; use crate::{ContextError, Module}; @@ -43,7 +45,7 @@ pub fn module() -> Result { module.function_meta(take)?; module.function_meta(count)?; module.associated_function(Protocol::NEXT, Iterator::next)?; - module.associated_function(Protocol::INTO_ITER, >::from)?; + module.associated_function(Protocol::INTO_ITER, identity::)?; module.function_meta(range)?; module.function_meta(empty)?; @@ -1140,16 +1142,15 @@ fn collect_string(mut it: Iterator) -> VmResult { let mut string = String::new(); while let Some(value) = vm_try!(it.next()) { - match value { - Value::Char(c) => { - vm_try!(string.try_push(c)); + match &*vm_try!(value.borrow_kind_ref()) { + ValueKind::Char(c) => { + vm_try!(string.try_push(*c)); } - Value::String(s) => { - let s = vm_try!(s.into_ref()); - vm_try!(string.try_push_str(s.as_str())); + ValueKind::String(s) => { + vm_try!(string.try_push_str(s)); } value => { - return VmResult::expected::(vm_try!(value.type_info())); + return VmResult::expected::(value.type_info()); } } } diff --git a/crates/rune/src/modules/mem.rs b/crates/rune/src/modules/mem.rs index 5f72f9ac4..b10ff62d7 100644 --- a/crates/rune/src/modules/mem.rs +++ b/crates/rune/src/modules/mem.rs @@ -26,6 +26,6 @@ pub fn module() -> Result { /// ``` #[rune::function] fn drop(value: Value) -> VmResult<()> { - vm_try!(value.take()); + vm_try!(value.drop()); VmResult::Ok(()) } diff --git a/crates/rune/src/modules/option.rs b/crates/rune/src/modules/option.rs index 0858b1361..bde8aa696 100644 --- a/crates/rune/src/modules/option.rs +++ b/crates/rune/src/modules/option.rs @@ -1,7 +1,7 @@ //! The `std::option` module. use crate as rune; -use crate::runtime::{ControlFlow, Formatter, Function, Iterator, Panic, Shared, Value, VmResult}; +use crate::runtime::{ControlFlow, Formatter, Function, Iterator, Panic, Value, VmResult}; use crate::{ContextError, Module}; /// Construct the `std::option` module. @@ -182,7 +182,7 @@ fn into_iter(option: Option) -> Iterator { fn and_then(option: Option, then: Function) -> VmResult> { match option { // no need to clone v, passing the same reference forward - Some(v) => VmResult::Ok(vm_try!(then.call::<_, _>((v,)))), + Some(v) => VmResult::Ok(vm_try!(then.call((v,)))), None => VmResult::Ok(None), } } @@ -210,7 +210,7 @@ fn and_then(option: Option, then: Function) -> VmResult> { fn map(option: Option, then: Function) -> VmResult> { match option { // no need to clone v, passing the same reference forward - Some(v) => VmResult::Ok(Some(vm_try!(then.call::<_, _>((v,))))), + Some(v) => VmResult::Ok(Some(vm_try!(then.call((v,))))), None => VmResult::Ok(None), } } @@ -253,24 +253,20 @@ fn transpose(this: Option) -> VmResult { let value = match this { Some(value) => value, None => { - let none = Value::from(vm_try!(Shared::new(Option::::None))); - let result = Value::from(vm_try!(Shared::new(Result::::Ok(none)))); + let none = vm_try!(Value::try_from(Option::::None)); + let result = vm_try!(Value::try_from(Result::::Ok(none))); return VmResult::Ok(result); } }; - let result = vm_try!(vm_try!(value.into_result()).take()); - - match result { + match &*vm_try!(value.into_result_ref()) { Ok(ok) => { - let some = Value::from(vm_try!(Shared::new(Option::::Some(ok.clone())))); - let result = Value::from(vm_try!(Shared::new(Result::::Ok(some)))); + let some = vm_try!(Value::try_from(Some(ok.clone()))); + let result = vm_try!(Value::try_from(Ok(some))); VmResult::Ok(result) } Err(err) => { - let result = Value::from(vm_try!(Shared::new(Result::::Err( - err.clone() - )))); + let result = vm_try!(Value::try_from(Err(err.clone()))); VmResult::Ok(result) } } @@ -408,9 +404,9 @@ fn ok_or_else(this: Option, err: Function) -> VmResult) -> VmResult { +pub(crate) fn option_try(this: &Option) -> VmResult { VmResult::Ok(match this { - Some(value) => ControlFlow::Continue(value), - None => ControlFlow::Break(Value::Option(vm_try!(Shared::new(None)))), + Some(value) => ControlFlow::Continue(value.clone()), + None => ControlFlow::Break(vm_try!(Value::try_from(None))), }) } diff --git a/crates/rune/src/modules/result.rs b/crates/rune/src/modules/result.rs index 4ee7cc253..642778069 100644 --- a/crates/rune/src/modules/result.rs +++ b/crates/rune/src/modules/result.rs @@ -3,7 +3,7 @@ use crate as rune; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; -use crate::runtime::{ControlFlow, Formatter, Function, Panic, Shared, Value, VmResult}; +use crate::runtime::{ControlFlow, Formatter, Function, Panic, Value, VmResult}; use crate::{ContextError, Module}; /// Construct the `std::result` module. @@ -159,7 +159,7 @@ fn unwrap_or(this: Result, default: Value) -> Value { fn unwrap_or_else(this: Result, default: Function) -> VmResult { match this { Ok(value) => VmResult::Ok(value), - Err(error) => default.call::<_, Value>((error,)), + Err(error) => default.call((error,)), } } @@ -224,7 +224,7 @@ fn expect(result: Result, message: Value) -> VmResult { #[rune::function(instance)] fn and_then(this: &Result, op: Function) -> VmResult> { match this { - Ok(v) => VmResult::Ok(vm_try!(op.call::<_, _>((v,)))), + Ok(v) => VmResult::Ok(vm_try!(op.call((v,)))), Err(e) => VmResult::Ok(Err(e.clone())), } } @@ -251,7 +251,7 @@ fn and_then(this: &Result, op: Function) -> VmResult, then: Function) -> VmResult> { match this { - Ok(v) => VmResult::Ok(Ok(vm_try!(then.call::<_, _>((v,))))), + Ok(v) => VmResult::Ok(Ok(vm_try!(then.call((v,))))), Err(e) => VmResult::Ok(Err(e.clone())), } } @@ -269,9 +269,9 @@ fn map(this: &Result, then: Function) -> VmResult) -> VmResult { +pub(crate) fn result_try(this: &Result) -> VmResult { VmResult::Ok(match this { - Ok(value) => ControlFlow::Continue(value), - Err(error) => ControlFlow::Break(Value::Result(vm_try!(Shared::new(Err(error))))), + Ok(value) => ControlFlow::Continue(value.clone()), + Err(error) => ControlFlow::Break(vm_try!(Value::try_from(Err(error.clone())))), }) } diff --git a/crates/rune/src/modules/string.rs b/crates/rune/src/modules/string.rs index 34481aa1f..76bd43fb2 100644 --- a/crates/rune/src/modules/string.rs +++ b/crates/rune/src/modules/string.rs @@ -10,7 +10,7 @@ use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::alloc::string::FromUtf8Error; use crate::alloc::{String, Vec}; -use crate::runtime::{Bytes, Formatter, Iterator, Panic, Value, VmErrorKind, VmResult}; +use crate::runtime::{Bytes, Formatter, Iterator, Panic, Value, ValueKind, VmErrorKind, VmResult}; use crate::{Any, ContextError, Module}; /// Construct the `std::string` module. @@ -743,18 +743,18 @@ fn shrink_to_fit(s: &mut String) -> VmResult<()> { fn split(this: &str, value: Value) -> VmResult { const NAME: &str = "std::str::Split"; - let lines = match value { - Value::String(s) => { + let lines = match *vm_try!(value.borrow_kind_ref()) { + ValueKind::String(ref s) => { let mut out = Vec::new(); - for value in this.split(vm_try!(s.borrow_ref()).as_str()) { + for value in this.split(s.as_str()) { let value = vm_try!(String::try_from(value)); vm_try!(out.try_push(value)); } out } - Value::Char(pat) => { + ValueKind::Char(pat) => { let mut out = Vec::new(); for value in this.split(pat) { @@ -764,11 +764,10 @@ fn split(this: &str, value: Value) -> VmResult { out } - Value::Function(f) => { - let f = vm_try!(f.borrow_ref()); + ValueKind::Function(ref f) => { let mut err = None; - let iter = this.split(|c: char| match f.call::<_, bool>((c,)) { + let iter = this.split(|c: char| match f.call::((c,)) { VmResult::Ok(b) => b, VmResult::Err(e) => { if err.is_none() { @@ -792,9 +791,9 @@ fn split(this: &str, value: Value) -> VmResult { out } - actual => { + ref actual => { return VmResult::err([ - VmErrorKind::expected::(vm_try!(actual.type_info())), + VmErrorKind::expected::(actual.type_info()), VmErrorKind::bad_argument(0), ]) } @@ -980,31 +979,26 @@ fn chars(s: &str) -> VmResult { fn get(this: &str, key: Value) -> VmResult> { use crate::runtime::TypeOf; - let slice = match key { - Value::RangeFrom(range) => { - let range = vm_try!(range.borrow_ref()); + let slice = match &*vm_try!(key.borrow_kind_ref()) { + ValueKind::RangeFrom(range) => { let start = vm_try!(range.start.as_usize()); this.get(start..) } - Value::RangeFull(..) => this.get(..), - Value::RangeInclusive(range) => { - let range = vm_try!(range.borrow_ref()); + ValueKind::RangeFull(..) => this.get(..), + ValueKind::RangeInclusive(range) => { let start = vm_try!(range.start.as_usize()); let end = vm_try!(range.end.as_usize()); this.get(start..=end) } - Value::RangeToInclusive(range) => { - let range = vm_try!(range.borrow_ref()); + ValueKind::RangeToInclusive(range) => { let end = vm_try!(range.end.as_usize()); this.get(..=end) } - Value::RangeTo(range) => { - let range = vm_try!(range.borrow_ref()); + ValueKind::RangeTo(range) => { let end = vm_try!(range.end.as_usize()); this.get(..end) } - Value::Range(range) => { - let range = vm_try!(range.borrow_ref()); + ValueKind::Range(range) => { let start = vm_try!(range.start.as_usize()); let end = vm_try!(range.end.as_usize()); this.get(start..end) @@ -1012,7 +1006,7 @@ fn get(this: &str, key: Value) -> VmResult> { index => { return VmResult::err(VmErrorKind::UnsupportedIndexGet { target: String::type_info(), - index: vm_try!(index.type_info()), + index: index.type_info(), }) } }; diff --git a/crates/rune/src/modules/vec.rs b/crates/rune/src/modules/vec.rs index fa08e6873..db0aa8413 100644 --- a/crates/rune/src/modules/vec.rs +++ b/crates/rune/src/modules/vec.rs @@ -205,7 +205,7 @@ fn get(this: &Vec, index: Value) -> VmResult> { fn sort_by(vec: &mut Vec, comparator: &Function) -> VmResult<()> { let mut error = None; - vec.sort_by(|a, b| match comparator.call::<_, Ordering>((a, b)) { + vec.sort_by(|a, b| match comparator.call::((a, b)) { VmResult::Ok(ordering) => ordering, VmResult::Err(e) => { if error.is_none() { diff --git a/crates/rune/src/runtime.rs b/crates/rune/src/runtime.rs index 9850c05fe..1b3c25b52 100644 --- a/crates/rune/src/runtime.rs +++ b/crates/rune/src/runtime.rs @@ -4,10 +4,8 @@ mod tests; mod access; -pub(crate) use self::access::{Access, AccessKind}; -pub use self::access::{ - AccessError, BorrowMut, BorrowRef, NotAccessibleMut, NotAccessibleRef, RawAccessGuard, -}; +pub(crate) use self::access::{Access, AccessErrorKind, RawAccessGuard}; +pub use self::access::{AccessError, BorrowMut, BorrowRef, Snapshot}; mod any_obj; pub use self::any_obj::{AnyObj, AnyObjError, AnyObjVtable}; @@ -115,7 +113,8 @@ mod select; pub(crate) use self::select::Select; mod shared; -pub use self::shared::{Mut, RawMut, RawRef, Ref, Shared, SharedPointerGuard}; +pub(crate) use self::shared::Shared; +pub use self::shared::{Mut, RawMut, RawRef, Ref, SharedPointerGuard}; mod stack; pub use self::stack::{Stack, StackError}; @@ -146,7 +145,8 @@ pub(crate) use self::unit::UnitFn; pub use self::unit::{Unit, UnitStorage}; mod value; -pub use self::value::{EmptyStruct, Rtti, Struct, TupleStruct, Value, VariantRtti}; +pub(crate) use self::value::ValueKind; +pub use self::value::{EmptyStruct, Rtti, Struct, TupleStruct, TypeValue, Value, VariantRtti}; mod variant; pub use self::variant::{Variant, VariantData}; @@ -167,14 +167,16 @@ mod vm_error; #[cfg(feature = "emit")] pub(crate) use self::vm_error::VmErrorAt; pub(crate) use self::vm_error::VmErrorKind; -pub use self::vm_error::{try_result, TryFromResult, VmError, VmIntegerRepr, VmResult}; +pub use self::vm_error::{ + try_result, RuntimeError, TryFromResult, VmError, VmIntegerRepr, VmResult, +}; mod vm_execution; -pub use self::vm_execution::{ExecutionState, VmExecution, VmSendExecution}; +pub(crate) use self::vm_execution::ExecutionState; +pub use self::vm_execution::{VmExecution, VmSendExecution}; mod vm_halt; -pub(crate) use self::vm_halt::VmHalt; -pub use self::vm_halt::VmHaltInfo; +pub(crate) use self::vm_halt::{VmHalt, VmHaltInfo}; mod fmt; pub use self::fmt::Formatter; diff --git a/crates/rune/src/runtime/access.rs b/crates/rune/src/runtime/access.rs index 29e97e4ee..6df95aef5 100644 --- a/crates/rune/src/runtime/access.rs +++ b/crates/rune/src/runtime/access.rs @@ -1,6 +1,7 @@ use core::cell::Cell; use core::fmt; use core::future::Future; +use core::marker::PhantomData; use core::mem::ManuallyDrop; use core::ops; use core::pin::Pin; @@ -9,52 +10,53 @@ use core::task::{Context, Poll}; use crate::runtime::{AnyObjError, RawStr}; -/// Bitflag which if set indicates that the accessed value is an external -/// reference (exclusive or not). -const IS_REF_MASK: isize = 1isize; +/// Test if exclusively held. +const EXCLUSIVE: usize = 1usize.rotate_right(2); /// Sentinel value to indicate that access is taken. -const TAKEN: isize = (isize::max_value() ^ IS_REF_MASK) >> 1; -/// Panic if we reach this number of shared accesses and we try to add one more, -/// since it's the largest we can support. -const MAX_USES: isize = 0b11isize.rotate_right(2); +const MOVED: usize = 1usize.rotate_right(1); +/// Mask indicating if the value is exclusively set or moved. +const MASK: usize = EXCLUSIVE | MOVED; /// An error raised while downcasting. -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[allow(missing_docs)] #[non_exhaustive] -pub enum AccessError { - UnexpectedType { expected: RawStr, actual: RawStr }, - NotAccessibleRef { error: NotAccessibleRef }, - NotAccessibleMut { error: NotAccessibleMut }, - NotAccessibleTake { error: NotAccessibleTake }, - AnyObjError { error: AnyObjError }, +pub struct AccessError { + kind: AccessErrorKind, } -cfg_std! { - impl std::error::Error for AccessError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - AccessError::NotAccessibleRef { error, .. } => Some(error), - AccessError::NotAccessibleMut { error, .. } => Some(error), - AccessError::NotAccessibleTake { error, .. } => Some(error), - AccessError::AnyObjError { error, .. } => Some(error), - _ => None, - } - } +impl AccessError { + #[inline] + pub(crate) fn new(kind: AccessErrorKind) -> Self { + Self { kind } } } impl fmt::Display for AccessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - AccessError::UnexpectedType { expected, actual } => write!( + match &self.kind { + AccessErrorKind::UnexpectedType { expected, actual } => write!( f, "Expected data of type `{expected}`, but found `{actual}`", ), - AccessError::NotAccessibleRef { error } => error.fmt(f), - AccessError::NotAccessibleMut { error } => error.fmt(f), - AccessError::NotAccessibleTake { error } => error.fmt(f), - AccessError::AnyObjError { error } => error.fmt(f), + AccessErrorKind::NotAccessibleRef { error } => error.fmt(f), + AccessErrorKind::NotAccessibleMut { error } => error.fmt(f), + AccessErrorKind::NotAccessibleTake { error } => error.fmt(f), + AccessErrorKind::AnyObjError { error } => error.fmt(f), + } + } +} + +cfg_std! { + impl std::error::Error for AccessError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self.kind { + AccessErrorKind::NotAccessibleRef { error, .. } => Some(error), + AccessErrorKind::NotAccessibleMut { error, .. } => Some(error), + AccessErrorKind::NotAccessibleTake { error, .. } => Some(error), + AccessErrorKind::AnyObjError { error, .. } => Some(error), + _ => None, + } } } } @@ -62,35 +64,51 @@ impl fmt::Display for AccessError { impl From for AccessError { #[inline] fn from(error: NotAccessibleRef) -> Self { - AccessError::NotAccessibleRef { error } + AccessError::new(AccessErrorKind::NotAccessibleRef { error }) } } impl From for AccessError { #[inline] fn from(error: NotAccessibleMut) -> Self { - AccessError::NotAccessibleMut { error } + AccessError::new(AccessErrorKind::NotAccessibleMut { error }) } } impl From for AccessError { #[inline] fn from(error: NotAccessibleTake) -> Self { - AccessError::NotAccessibleTake { error } + AccessError::new(AccessErrorKind::NotAccessibleTake { error }) } } impl From for AccessError { #[inline] fn from(source: AnyObjError) -> Self { - AccessError::AnyObjError { error: source } + AccessError::new(AccessErrorKind::AnyObjError { error: source }) } } +impl From for AccessError { + #[inline] + fn from(kind: AccessErrorKind) -> Self { + AccessError::new(kind) + } +} + +#[derive(Debug, PartialEq)] +pub(crate) enum AccessErrorKind { + UnexpectedType { expected: RawStr, actual: RawStr }, + NotAccessibleRef { error: NotAccessibleRef }, + NotAccessibleMut { error: NotAccessibleMut }, + NotAccessibleTake { error: NotAccessibleTake }, + AnyObjError { error: AnyObjError }, +} + /// Error raised when tried to access for shared access but it was not /// accessible. -#[derive(Debug)] -pub struct NotAccessibleRef(Snapshot); +#[derive(Debug, PartialEq)] +pub(crate) struct NotAccessibleRef(Snapshot); impl fmt::Display for NotAccessibleRef { #[inline] @@ -105,8 +123,8 @@ cfg_std! { /// Error raised when tried to access for exclusive access but it was not /// accessible. -#[derive(Debug)] -pub struct NotAccessibleMut(Snapshot); +#[derive(Debug, PartialEq)] +pub(crate) struct NotAccessibleMut(Snapshot); impl fmt::Display for NotAccessibleMut { #[inline] @@ -123,8 +141,8 @@ cfg_std! { /// /// This requires exclusive access, but it's a scenario we structure separately /// for diagnostics purposes. -#[derive(Debug)] -pub struct NotAccessibleTake(Snapshot); +#[derive(Debug, PartialEq)] +pub(crate) struct NotAccessibleTake(Snapshot); impl fmt::Display for NotAccessibleTake { #[inline] @@ -137,222 +155,131 @@ cfg_std! { impl std::error::Error for NotAccessibleTake {} } -/// The kind of access to perform. -#[derive(Debug, Clone, Copy)] -pub(crate) enum AccessKind { - /// Access a reference. - Any, - /// Access something owned. - Owned, -} - /// Snapshot that can be used to indicate how the value was being accessed at /// the time of an error. -#[derive(Debug)] +#[derive(PartialEq)] #[repr(transparent)] -struct Snapshot(isize); +pub struct Snapshot(usize); impl fmt::Display for Snapshot { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 >> 1 { 0 => write!(f, "fully accessible")?, - 1 => write!(f, "exclusively accessed")?, - TAKEN => write!(f, "moved")?, - n if n < 0 => write!(f, "shared by {}", -n)?, - n => write!(f, "invalidly marked ({})", n)?, - } - - if self.0 & IS_REF_MASK == 1 { - write!(f, " (ref)")?; + EXCLUSIVE => write!(f, "exclusively accessed")?, + MOVED => write!(f, "moved")?, + n => write!(f, "shared by {}", n)?, } Ok(()) } } +impl fmt::Debug for Snapshot { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Snapshot({})", self) + } +} + /// Access flags. /// /// These accomplish the following things: -/// * Indicates if a value is a reference. /// * Indicates if a value is exclusively held. +/// * Indicates if a value is taken . /// * Indicates if a value is shared, and if so by how many. -/// -/// It has the following bit-pattern (assume isize is 16 bits for simplicity): -/// -/// ```text -/// S0000000_00000000_00000000_0000000F -/// | || -/// '-- Sign bit and number base ----'| -/// Reference Flag -' -/// -/// The reference flag is the LSB, and the rest is treated as a signed number -/// with the following properties: -/// * If the value is `0`, it is not being accessed. -/// * If the value is `1`, it is being exclusively accessed. -/// * If the value is negative `n`, it is being shared accessed by `-n` uses. -/// -/// This means that the maximum number of accesses for a 64-bit `isize` is -/// `(1 << 62) - 1` uses. -/// -/// ``` #[repr(transparent)] -pub(crate) struct Access(Cell); +pub(crate) struct Access(Cell); impl Access { /// Construct a new default access. - pub(crate) const fn new(is_ref: bool) -> Self { - let initial = if is_ref { 1 } else { 0 }; - Self(Cell::new(initial)) - } - - /// Test if access is guarding a reference. - #[inline] - pub(crate) fn is_ref(&self) -> bool { - self.0.get() & IS_REF_MASK != 0 + pub(crate) const fn new() -> Self { + Self(Cell::new(0)) } /// Test if we can have shared access without modifying the internal count. - #[inline] + #[inline(always)] pub(crate) fn is_shared(&self) -> bool { - self.get() <= 0 + self.0.get() & MASK == 0 } /// Test if we can have exclusive access without modifying the internal /// count. - #[inline] + #[inline(always)] pub(crate) fn is_exclusive(&self) -> bool { - self.get() == 0 + self.0.get() == 0 } /// Test if the data has been taken. - #[inline] + #[inline(always)] pub(crate) fn is_taken(&self) -> bool { - self.get() == TAKEN + self.0.get() & MOVED != 0 } /// Mark that we want shared access to the given access token. - /// - /// # Safety - /// - /// The returned guard must not outlive the access token that created it. - #[inline] - pub(crate) unsafe fn shared( - &self, - kind: AccessKind, - ) -> Result, NotAccessibleRef> { - if let AccessKind::Owned = kind { - if self.is_ref() { - return Err(NotAccessibleRef(Snapshot(self.0.get()))); - } - } - - let state = self.get(); + #[inline(always)] + pub(crate) fn shared(&self) -> Result, NotAccessibleRef> { + let state = self.0.get(); - if state == MAX_USES { + if state == MASK { crate::alloc::abort(); } - let n = state.wrapping_sub(1); - - if n >= 0 { - return Err(NotAccessibleRef(Snapshot(self.0.get()))); + if state & MASK != 0 { + return Err(NotAccessibleRef(Snapshot(state))); } - self.set(n); + self.0.set(state + 1); Ok(AccessGuard(self)) } /// Mark that we want exclusive access to the given access token. - /// - /// # Safety - /// - /// The returned guard must not outlive the access token that created it. - #[inline] - pub(crate) unsafe fn exclusive( - &self, - kind: AccessKind, - ) -> Result, NotAccessibleMut> { - if let AccessKind::Owned = kind { - if self.is_ref() { - return Err(NotAccessibleMut(Snapshot(self.0.get()))); - } - } - - let n = self.get(); + #[inline(always)] + pub(crate) fn exclusive(&self) -> Result, NotAccessibleMut> { + let state = self.0.get(); - if n != 0 { - return Err(NotAccessibleMut(Snapshot(self.0.get()))); + if state != 0 { + return Err(NotAccessibleMut(Snapshot(state))); } - self.set(n.wrapping_add(1)); + self.0.set(EXCLUSIVE); Ok(AccessGuard(self)) } /// Mark that we want to mark the given access as "taken". /// /// I.e. whatever guarded data is no longer available. - /// - /// # Safety - /// - /// The returned guard must not outlive the access token that created it. - #[inline] - pub(crate) unsafe fn take(&self, kind: AccessKind) -> Result { - if let AccessKind::Owned = kind { - if self.is_ref() { - return Err(NotAccessibleTake(Snapshot(self.0.get()))); - } - } - - let state = self.get(); + #[inline(always)] + pub(crate) fn take(&self) -> Result { + let state = self.0.get(); if state != 0 { - return Err(NotAccessibleTake(Snapshot(self.0.get()))); + return Err(NotAccessibleTake(Snapshot(state))); } - self.set(TAKEN); - Ok(RawTakeGuard { access: self }) + self.0.set(MOVED); + Ok(RawAccessGuard(self.into())) } - /// Release the current access level. - #[inline] + /// Release the current access, unless it's moved. + #[inline(always)] fn release(&self) { - let b = self.get(); - - let b = if b < 0 { - debug_assert!(b < 0); - b.wrapping_add(1) - } else { - debug_assert_eq!(b, 1, "borrow value should be exclusive (0)"); - b.wrapping_sub(1) - }; + let b = self.0.get(); - self.set(b); - } - - /// Untake the current access. - #[inline] - fn release_take(&self) { - let b = self.get(); - debug_assert_eq!(b, TAKEN, "borrow value should be TAKEN ({})", TAKEN); - self.set(0); - } + let b = if b & MASK == 0 { b - 1 } else { 0 }; - /// Get the current value of the flag. - #[inline] - fn get(&self) -> isize { - self.0.get() >> 1 + self.0.set(b); } - /// Set the current value of the flag. - #[inline] - fn set(&self, value: isize) { - self.0.set(self.0.get() & IS_REF_MASK | value << 1); + /// Get a snapshot of current access. + #[inline(always)] + pub(super) fn snapshot(&self) -> Snapshot { + Snapshot(self.0.get()) } } impl fmt::Debug for Access { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", Snapshot(self.get())) + write!(f, "{}", Snapshot(self.0.get())) } } @@ -386,19 +313,18 @@ impl<'a, T: ?Sized> BorrowRef<'a, T> { /// # Examples /// /// ``` - /// use rune::runtime::{BorrowRef, Shared}; + /// use rune::runtime::{BorrowRef, Bytes}; + /// use rune::alloc::try_vec; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.borrow_ref()?; - /// let value: BorrowRef<[u32]> = BorrowRef::map(vec, |vec| &vec[0..2]); + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes = bytes.borrow_bytes_ref()?; /// - /// assert_eq!(&*value, &[1u32, 2u32][..]); + /// let bytes: BorrowRef<[u8]> = BorrowRef::map(bytes, |bytes| &bytes[0..2]); + /// + /// assert_eq!(&bytes[..], &[1u8, 2u8][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn map(this: Self, m: M) -> BorrowRef<'a, U> - where - M: FnOnce(&T) -> &U, - { + pub fn map(this: Self, m: impl FnOnce(&T) -> &U) -> BorrowRef<'a, U> { BorrowRef { data: m(this.data), guard: this.guard, @@ -410,21 +336,32 @@ impl<'a, T: ?Sized> BorrowRef<'a, T> { /// # Examples /// /// ``` - /// use rune::runtime::{BorrowRef, Shared}; + /// use rune::runtime::{BorrowRef, Bytes}; + /// use rune::alloc::try_vec; + /// + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes = bytes.borrow_bytes_ref()?; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.borrow_ref()?; - /// let mut value: Option> = BorrowRef::try_map(vec, |vec| vec.get(0..2)); + /// let Ok(bytes) = BorrowRef::try_map(bytes, |bytes| bytes.get(0..2)) else { + /// panic!("Conversion failed"); + /// }; /// - /// assert_eq!(value.as_deref(), Some(&[1u32, 2u32][..])); + /// assert_eq!(&bytes[..], &[1u8, 2u8][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn try_map(this: Self, m: M) -> Option> - where - M: FnOnce(&T) -> Option<&U>, - { - Some(BorrowRef { - data: m(this.data)?, + pub fn try_map( + this: Self, + m: impl FnOnce(&T) -> Option<&U>, + ) -> Result, Self> { + let Some(data) = m(this.data) else { + return Err(BorrowRef { + data: this.data, + guard: this.guard, + }); + }; + + Ok(BorrowRef { + data, guard: this.guard, }) } @@ -449,7 +386,7 @@ where /// A guard around some specific access access. #[repr(transparent)] -pub struct AccessGuard<'a>(&'a Access); +pub(crate) struct AccessGuard<'a>(&'a Access); impl AccessGuard<'_> { /// Convert into a raw guard which does not have a lifetime associated with @@ -459,7 +396,7 @@ impl AccessGuard<'_> { /// /// Since we're losing track of the lifetime, caller must ensure that the /// access outlives the guard. - pub unsafe fn into_raw(self) -> RawAccessGuard { + pub(crate) unsafe fn into_raw(self) -> RawAccessGuard { RawAccessGuard(ptr::NonNull::from(ManuallyDrop::new(self).0)) } } @@ -470,9 +407,9 @@ impl Drop for AccessGuard<'_> { } } -/// A raw guard around some level of access. +/// A raw guard around some level of access which will be released once the guard is dropped. #[repr(transparent)] -pub struct RawAccessGuard(ptr::NonNull); +pub(crate) struct RawAccessGuard(ptr::NonNull); impl Drop for RawAccessGuard { fn drop(&mut self) { @@ -480,27 +417,14 @@ impl Drop for RawAccessGuard { } } -/// A taken access guard. -/// -/// This is created with [Access::take], and must not outlive the [Access] -/// instance it was created from. -pub(crate) struct RawTakeGuard { - access: *const Access, -} - -impl Drop for RawTakeGuard { - fn drop(&mut self) { - unsafe { (*self.access).release_take() } - } -} - /// Guard for data exclusively borrowed from a slot in the virtual machine. /// /// These guards are necessary, since we need to guarantee certain forms of /// access depending on what we do. Releasing the guard releases the access. pub struct BorrowMut<'a, T: ?Sized> { - data: &'a mut T, + data: ptr::NonNull, guard: AccessGuard<'a>, + _marker: PhantomData<&'a mut T>, } impl<'a, T: ?Sized> BorrowMut<'a, T> { @@ -514,8 +438,9 @@ impl<'a, T: ?Sized> BorrowMut<'a, T> { /// this guard is dropped. pub(crate) unsafe fn new(data: &'a mut T, access: &'a Access) -> Self { Self { - data, + data: ptr::NonNull::from(data), guard: AccessGuard(access), + _marker: PhantomData, } } @@ -524,22 +449,25 @@ impl<'a, T: ?Sized> BorrowMut<'a, T> { /// # Examples /// /// ``` - /// use rune::runtime::{BorrowMut, Shared}; + /// use rune::runtime::{BorrowMut, Bytes}; + /// use rune::alloc::try_vec; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.borrow_mut()?; - /// let value: BorrowMut<[u32]> = BorrowMut::map(vec, |vec| &mut vec[0..2]); + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes = bytes.borrow_bytes_mut()?; /// - /// assert_eq!(&*value, &mut [1u32, 2u32][..]); + /// let mut bytes: BorrowMut<[u8]> = BorrowMut::map(bytes, |bytes| &mut bytes[0..2]); + /// + /// assert_eq!(&mut bytes[..], &mut [1u8, 2u8][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn map(this: Self, m: M) -> BorrowMut<'a, U> - where - M: FnOnce(&mut T) -> &mut U, - { - BorrowMut { - data: m(this.data), - guard: this.guard, + pub fn map(mut this: Self, m: impl FnOnce(&mut T) -> &mut U) -> BorrowMut<'a, U> { + // SAFETY: This is safe per construction. + unsafe { + BorrowMut { + data: ptr::NonNull::from(m(this.data.as_mut())), + guard: this.guard, + _marker: PhantomData, + } } } @@ -548,23 +476,38 @@ impl<'a, T: ?Sized> BorrowMut<'a, T> { /// # Examples /// /// ``` - /// use rune::runtime::{BorrowMut, Shared}; + /// use rune::runtime::{BorrowMut, Bytes}; + /// use rune::alloc::try_vec; + /// + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes = bytes.borrow_bytes_mut()?; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.borrow_mut()?; - /// let mut value: Option> = BorrowMut::try_map(vec, |vec| vec.get_mut(0..2)); + /// let Ok(mut bytes) = BorrowMut::try_map(bytes, |bytes| bytes.get_mut(0..2)) else { + /// panic!("Conversion failed"); + /// }; /// - /// assert_eq!(value.as_deref_mut(), Some(&mut [1u32, 2u32][..])); + /// assert_eq!(&mut bytes[..], &mut [1u8, 2u8][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn try_map(this: Self, m: M) -> Option> - where - M: FnOnce(&mut T) -> Option<&mut U>, - { - Some(BorrowMut { - data: m(this.data)?, - guard: this.guard, - }) + pub fn try_map( + mut this: Self, + m: impl FnOnce(&mut T) -> Option<&mut U>, + ) -> Result, Self> { + unsafe { + let Some(data) = m(this.data.as_mut()) else { + return Err(BorrowMut { + data: this.data, + guard: this.guard, + _marker: PhantomData, + }); + }; + + Ok(BorrowMut { + data: ptr::NonNull::from(data), + guard: this.guard, + _marker: PhantomData, + }) + } } } @@ -572,13 +515,15 @@ impl ops::Deref for BorrowMut<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { - self.data + // SAFETY: This is correct per construction. + unsafe { self.data.as_ref() } } } impl ops::DerefMut for BorrowMut<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { - self.data + // SAFETY: This is correct per construction. + unsafe { self.data.as_mut() } } } @@ -606,75 +551,72 @@ where #[cfg(test)] mod tests { - use super::{Access, AccessKind}; + use super::Access; #[test] - fn test_non_ref() { - unsafe { - let access = Access::new(false); - - assert!(!access.is_ref()); - assert!(access.is_shared()); - assert!(access.is_exclusive()); + fn access_shared() { + let access = Access::new(); - let guard = access.shared(AccessKind::Any).unwrap(); + assert!(access.is_shared()); + assert!(access.is_exclusive()); + assert!(!access.is_taken()); - assert!(!access.is_ref()); - assert!(access.is_shared()); - assert!(!access.is_exclusive()); + let g1 = access.shared().unwrap(); + let g2 = access.shared().unwrap(); - drop(guard); + assert!(access.is_shared()); + assert!(!access.is_exclusive()); + assert!(!access.is_taken()); - assert!(!access.is_ref()); - assert!(access.is_shared()); - assert!(access.is_exclusive()); + drop(g1); - let guard = access.exclusive(AccessKind::Any).unwrap(); + assert!(access.is_shared()); + assert!(!access.is_exclusive()); + assert!(!access.is_taken()); - assert!(!access.is_ref()); - assert!(!access.is_shared()); - assert!(!access.is_exclusive()); + drop(g2); - drop(guard); - - assert!(!access.is_ref()); - assert!(access.is_shared()); - assert!(access.is_exclusive()); - } + assert!(access.is_shared()); + assert!(access.is_exclusive()); + assert!(!access.is_taken()); } #[test] - fn test_ref() { - unsafe { - let access = Access::new(true); + fn access_exclusive() { + let access = Access::new(); - assert!(access.is_ref()); - assert!(access.is_shared()); - assert!(access.is_exclusive()); + let guard = access.exclusive().unwrap(); + assert!(access.exclusive().is_err()); - let guard = access.shared(AccessKind::Any).unwrap(); + assert!(!access.is_shared()); + assert!(!access.is_exclusive()); + assert!(!access.is_taken()); - assert!(access.is_ref()); - assert!(access.is_shared()); - assert!(!access.is_exclusive()); + drop(guard); - drop(guard); + assert!(access.is_shared()); + assert!(access.is_exclusive()); + assert!(!access.is_taken()); + } - assert!(access.is_ref()); - assert!(access.is_shared()); - assert!(access.is_exclusive()); + #[test] + fn access_take() { + let access = Access::new(); - let guard = access.exclusive(AccessKind::Any).unwrap(); + let guard = access.exclusive().unwrap(); + assert!(access.take().is_err()); + drop(guard); - assert!(access.is_ref()); - assert!(!access.is_shared()); - assert!(!access.is_exclusive()); + let g = access.take().unwrap(); - drop(guard); + assert!(!access.is_shared()); + assert!(!access.is_exclusive()); + assert!(access.is_taken()); - assert!(access.is_ref()); - assert!(access.is_shared()); - assert!(access.is_exclusive()); - } + drop(g); + + assert!(access.is_shared()); + assert!(access.is_exclusive()); + assert!(!access.is_taken()); } } diff --git a/crates/rune/src/runtime/any_obj.rs b/crates/rune/src/runtime/any_obj.rs index 1acf2ade3..9cf266d22 100644 --- a/crates/rune/src/runtime/any_obj.rs +++ b/crates/rune/src/runtime/any_obj.rs @@ -13,7 +13,7 @@ use crate::hash::Hash; use crate::runtime::{AnyTypeInfo, FullTypeOf, MaybeTypeOf, RawStr, TypeInfo}; /// Errors raised during casting operations. -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[allow(missing_docs)] #[non_exhaustive] pub enum AnyObjError { @@ -223,7 +223,7 @@ impl AnyObj { /// /// ``` /// use rune::Any; - /// use rune::runtime::AnyObj; + /// use rune::runtime::{AnyObj, VmResult}; /// /// #[derive(Any)] /// struct Foo(u32); @@ -233,9 +233,11 @@ impl AnyObj { /// { /// let mut any = unsafe { AnyObj::from_mut(&mut v) }; /// - /// if let Some(v) = any.downcast_borrow_mut::() { - /// v.0 += 1; - /// } + /// let Ok(v) = any.downcast_borrow_mut::() else { + /// panic!("Conversion failed"); + /// }; + /// + /// v.0 += 1; /// } /// /// assert_eq!(v.0, 2); @@ -350,6 +352,63 @@ impl AnyObj { self.raw_as_ptr(TypeId::of::()).is_ok() } + /// Returns stored value if it is of type `T`, or `None` if it isn't. + /// + /// # Examples + /// + /// ``` + /// use rune::Any; + /// use rune::runtime::AnyObj; + /// + /// #[derive(Debug, PartialEq, Eq, Any)] + /// struct Thing(u32); + /// + /// let any = AnyObj::new(Thing(1u32))?; + /// + /// let Ok(thing) = any.downcast::() else { + /// panic!("Conversion failed"); + /// }; + /// + /// assert_eq!(thing, Thing(1)); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + #[inline] + pub fn downcast(self) -> Result + where + T: Any, + { + match self.vtable.kind { + // Only owned things can be taken. + AnyObjKind::Owned => (), + AnyObjKind::RefPtr => { + let error = AnyObjError::RefAsOwned { + name: self.type_name(), + }; + return Err((error, self)); + } + AnyObjKind::MutPtr => { + let error = AnyObjError::MutAsOwned { + name: self.type_name(), + }; + return Err((error, self)); + } + }; + + let this = ManuallyDrop::new(self); + + unsafe { + let Some(ptr) = (this.vtable.as_ptr)(this.data.as_ptr(), TypeId::of::()) else { + let this = ManuallyDrop::into_inner(this); + return Err((AnyObjError::Cast, this)); + }; + + Ok(Box::into_inner(Box::from_raw_in( + ptr.cast_mut().cast(), + rune_alloc::alloc::Global, + ))) + } + } + /// Returns some reference to the boxed value if it is of type `T`, or /// `None` if it isn't. /// @@ -357,7 +416,7 @@ impl AnyObj { /// /// ``` /// use rune::Any; - /// use rune::runtime::AnyObj; + /// use rune::runtime::{AnyObj, AnyObjError}; /// /// #[derive(Debug, PartialEq, Eq, Any)] /// struct Thing(u32); @@ -366,17 +425,21 @@ impl AnyObj { /// struct Other; /// /// let any = AnyObj::new(Thing(1u32))?; - /// assert_eq!(Some(&Thing(1u32)), any.downcast_borrow_ref::()); - /// assert_eq!(None, any.downcast_borrow_ref::()); + /// assert_eq!(Ok(&Thing(1u32)), any.downcast_borrow_ref::()); + /// assert_eq!(Err(AnyObjError::Cast), any.downcast_borrow_ref::()); /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] - pub fn downcast_borrow_ref(&self) -> Option<&T> + pub fn downcast_borrow_ref(&self) -> Result<&T, AnyObjError> where T: Any, { unsafe { - (self.vtable.as_ptr)(self.data.as_ptr(), TypeId::of::()).map(|v| &*(v as *const _)) + let Some(ptr) = (self.vtable.as_ptr)(self.data.as_ptr(), TypeId::of::()) else { + return Err(AnyObjError::Cast); + }; + + Ok(&*ptr.cast()) } } @@ -394,16 +457,26 @@ impl AnyObj { /// /// let mut any = AnyObj::new(Thing(1u32))?; /// any.downcast_borrow_mut::().unwrap().0 = 2; - /// assert_eq!(Some(&Thing(2u32)), any.downcast_borrow_ref::()); + /// assert_eq!(Ok(&Thing(2u32)), any.downcast_borrow_ref::()); /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] - pub fn downcast_borrow_mut(&mut self) -> Option<&mut T> + pub fn downcast_borrow_mut(&mut self) -> Result<&mut T, AnyObjError> where T: Any, { + if let AnyObjKind::RefPtr = self.vtable.kind { + return Err(AnyObjError::RefAsMut { + name: self.type_name(), + }); + } + unsafe { - (self.vtable.as_ptr)(self.data.as_ptr(), TypeId::of::()).map(|v| &mut *(v as *mut _)) + let Some(ptr) = (self.vtable.as_ptr)(self.data.as_ptr(), TypeId::of::()) else { + return Err(AnyObjError::Cast); + }; + + Ok(&mut *ptr.cast_mut().cast()) } } @@ -416,70 +489,6 @@ impl AnyObj { } } - /// Attempt to perform a conversion to a raw mutable pointer. - pub(crate) fn raw_as_mut(&mut self, expected: TypeId) -> Result<*mut (), AnyObjError> { - match self.vtable.kind { - // Only owned and mutable pointers can be treated as mutable. - AnyObjKind::Owned | AnyObjKind::MutPtr => (), - _ => { - return Err(AnyObjError::RefAsMut { - name: self.type_name(), - }) - } - } - - // Safety: invariants are checked at construction time. - // We have mutable access to the inner value because we have mutable - // access to the `Any`. - match unsafe { (self.vtable.as_ptr)(self.data.as_ptr(), expected) } { - Some(ptr) => Ok(ptr as *mut ()), - None => Err(AnyObjError::Cast), - } - } - - /// Attempt to perform a conversion to a raw mutable pointer with the intent - /// of taking it. - /// - /// If the conversion is not possible, we return a reconstructed `Any` as - /// the error variant. - pub(crate) fn raw_take(self, expected: TypeId) -> Result<*mut (), (AnyObjError, Self)> { - match self.vtable.kind { - // Only owned things can be taken. - AnyObjKind::Owned => (), - AnyObjKind::RefPtr => { - return Err(( - AnyObjError::RefAsOwned { - name: self.type_name(), - }, - self, - )) - } - AnyObjKind::MutPtr => { - return Err(( - AnyObjError::MutAsOwned { - name: self.type_name(), - }, - self, - )) - } - }; - - let this = ManuallyDrop::new(self); - - // Safety: invariants are checked at construction time. - // We have mutable access to the inner value because we have mutable - // access to the `Any`. - unsafe { - match (this.vtable.as_ptr)(this.data.as_ptr(), expected) { - Some(data) => Ok(data as *mut ()), - None => { - let this = ManuallyDrop::into_inner(this); - Err((AnyObjError::Cast, this)) - } - } - } - } - /// Debug format the current any type. pub fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (self.vtable.debug)(f) diff --git a/crates/rune/src/runtime/awaited.rs b/crates/rune/src/runtime/awaited.rs index 0a15de873..8f3333f1d 100644 --- a/crates/rune/src/runtime/awaited.rs +++ b/crates/rune/src/runtime/awaited.rs @@ -1,10 +1,10 @@ -use crate::runtime::{Future, Select, Shared, ToValue, Vm, VmResult}; +use crate::runtime::{Future, Select, ToValue, Vm, VmResult}; /// A stored await task. #[derive(Debug)] pub(crate) enum Awaited { /// A future to be awaited. - Future(Shared), + Future(Future), /// A select to be awaited. Select(Select), } @@ -14,7 +14,7 @@ impl Awaited { pub(crate) async fn into_vm(self, vm: &mut Vm) -> VmResult<()> { match self { Self::Future(future) => { - let value = vm_try!(vm_try!(future.borrow_mut()).await.with_vm(vm)); + let value = vm_try!(future.await.with_vm(vm)); vm_try!(vm.stack_mut().push(value)); } Self::Select(select) => { diff --git a/crates/rune/src/runtime/bytes.rs b/crates/rune/src/runtime/bytes.rs index 01fa7f420..05ba6e38e 100644 --- a/crates/rune/src/runtime/bytes.rs +++ b/crates/rune/src/runtime/bytes.rs @@ -12,7 +12,7 @@ use serde::ser; use crate as rune; use crate::alloc::prelude::*; use crate::alloc::{self, Box, Vec}; -use crate::runtime::{RawRef, Ref, UnsafeToRef, Value, VmResult}; +use crate::runtime::{RawRef, Ref, UnsafeToRef, Value, ValueKind, VmErrorKind, VmResult}; use crate::Any; /// A vector of bytes. @@ -341,18 +341,24 @@ impl AsRef<[u8]> for Bytes { } } -from_value!(Bytes, into_bytes); +from_value2!(Bytes, into_bytes_ref, into_bytes_mut, into_bytes); impl UnsafeToRef for [u8] { type Guard = RawRef; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let bytes = vm_try!(value.into_bytes()); - let bytes = vm_try!(bytes.into_ref()); - let (value, guard) = Ref::into_raw(bytes); - // Safety: we're holding onto the guard for the slice here, so it is - // live. - VmResult::Ok((value.as_ref().as_slice(), guard)) + let result = Ref::try_map(vm_try!(value.into_kind_ref()), |kind| match kind { + ValueKind::Bytes(bytes) => Some(bytes.as_slice()), + _ => None, + }); + + match result { + Ok(bytes) => { + let (value, guard) = Ref::into_raw(bytes); + VmResult::Ok((value.as_ref(), guard)) + } + Err(actual) => VmResult::err(VmErrorKind::expected::(actual.type_info())), + } } } @@ -437,17 +443,17 @@ impl<'de> de::Deserialize<'de> for Bytes { #[cfg(test)] mod tests { - use crate::runtime::{Bytes, Shared, Value}; + use crate::runtime::{Bytes, Value}; use crate::tests::prelude::*; #[test] #[allow(clippy::let_and_return)] fn test_clone_issue() -> Result<(), Box> { - let shared = Value::Bytes(Shared::new(Bytes::new())?); + let shared = Value::try_from(Bytes::new())?; let _ = { - let shared = shared.into_bytes().into_result()?; - let out = shared.borrow_ref()?.try_clone()?; + let shared = shared.into_bytes_ref()?; + let out = shared.try_clone()?; out }; diff --git a/crates/rune/src/runtime/const_value.rs b/crates/rune/src/runtime/const_value.rs index 81037fe71..c4ef14bbc 100644 --- a/crates/rune/src/runtime/const_value.rs +++ b/crates/rune/src/runtime/const_value.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::alloc::prelude::*; use crate::alloc::{self, Box, HashMap, String, Vec}; use crate::runtime::{ - self, Bytes, FromValue, Object, OwnedTuple, Shared, ToValue, TypeInfo, Value, VmErrorKind, + self, Bytes, FromValue, Object, OwnedTuple, ToValue, TypeInfo, Value, ValueKind, VmErrorKind, VmResult, }; @@ -42,46 +42,47 @@ impl ConstValue { /// We provide this associated method since a constant value can be /// converted into a value infallibly, which is not captured by the trait /// otherwise. - pub fn into_value(self) -> alloc::Result { + pub fn as_value(&self) -> alloc::Result { Ok(match self { - Self::Byte(b) => Value::Byte(b), - Self::Char(c) => Value::Char(c), - Self::Bool(b) => Value::Bool(b), - Self::Integer(n) => Value::Integer(n), - Self::Float(n) => Value::Float(n), - Self::String(string) => Value::String(Shared::new(string)?), - Self::Bytes(b) => Value::Bytes(Shared::new(b)?), - Self::Option(option) => Value::Option(Shared::new(match option { - Some(some) => Some(Box::into_inner(some).into_value()?), + Self::EmptyTuple => Value::empty()?, + Self::Byte(b) => Value::try_from(*b)?, + Self::Char(c) => Value::try_from(*c)?, + Self::Bool(b) => Value::try_from(*b)?, + Self::Integer(n) => Value::try_from(*n)?, + Self::Float(n) => Value::try_from(*n)?, + Self::String(string) => Value::try_from(string.try_clone()?)?, + Self::Bytes(b) => Value::try_from(b.try_clone()?)?, + Self::Option(option) => Value::try_from(match option { + Some(some) => Some(some.as_value()?), None => None, - })?), + })?, Self::Vec(vec) => { let mut v = runtime::Vec::with_capacity(vec.len())?; for value in vec { - v.push(value.into_value()?)?; + v.push(value.as_value()?)?; } - Value::Vec(Shared::new(v)?) + Value::try_from(v)? } - Self::EmptyTuple => Value::EmptyTuple, Self::Tuple(tuple) => { let mut t = Vec::try_with_capacity(tuple.len())?; - for value in Vec::from(tuple) { - t.try_push(value.into_value()?)?; + for value in tuple.iter() { + t.try_push(value.as_value()?)?; } - Value::Tuple(Shared::new(OwnedTuple::try_from(t)?)?) + Value::try_from(OwnedTuple::try_from(t)?)? } Self::Object(object) => { let mut o = Object::with_capacity(object.len())?; for (key, value) in object { - o.insert(key, value.into_value()?)?; + let key = key.try_clone()?; + o.insert(key, value.as_value()?)?; } - Value::Object(Shared::new(o)?) + Value::try_from(o)? } }) } @@ -134,24 +135,20 @@ impl TryClone for ConstValue { impl FromValue for ConstValue { fn from_value(value: Value) -> VmResult { - VmResult::Ok(match value { - Value::EmptyTuple => Self::EmptyTuple, - Value::Byte(b) => Self::Byte(b), - Value::Char(c) => Self::Char(c), - Value::Bool(b) => Self::Bool(b), - Value::Integer(n) => Self::Integer(n), - Value::Float(f) => Self::Float(f), - Value::String(s) => Self::String(vm_try!(s.take())), - Value::Option(option) => Self::Option(match vm_try!(option.take()) { + VmResult::Ok(match vm_try!(value.take_kind()) { + ValueKind::EmptyTuple => Self::EmptyTuple, + ValueKind::Byte(b) => Self::Byte(b), + ValueKind::Char(c) => Self::Char(c), + ValueKind::Bool(b) => Self::Bool(b), + ValueKind::Integer(n) => Self::Integer(n), + ValueKind::Float(f) => Self::Float(f), + ValueKind::String(s) => Self::String(s), + ValueKind::Option(option) => Self::Option(match option { Some(some) => Some(vm_try!(Box::try_new(vm_try!(Self::from_value(some))))), None => None, }), - Value::Bytes(b) => { - let b = vm_try!(b.take()); - Self::Bytes(b) - } - Value::Vec(vec) => { - let vec = vm_try!(vec.take()); + ValueKind::Bytes(b) => Self::Bytes(b), + ValueKind::Vec(vec) => { let mut const_vec = vm_try!(Vec::try_with_capacity(vec.len())); for value in vec { @@ -160,8 +157,7 @@ impl FromValue for ConstValue { Self::Vec(const_vec) } - Value::Tuple(tuple) => { - let tuple = vm_try!(tuple.take()); + ValueKind::Tuple(tuple) => { let mut const_tuple = vm_try!(Vec::try_with_capacity(tuple.len())); for value in Vec::from(tuple.into_inner()) { @@ -170,8 +166,7 @@ impl FromValue for ConstValue { Self::Tuple(vm_try!(const_tuple.try_into_boxed_slice())) } - Value::Object(object) => { - let object = vm_try!(object.take()); + ValueKind::Object(object) => { let mut const_object = vm_try!(HashMap::try_with_capacity(object.len())); for (key, value) in object { @@ -180,9 +175,9 @@ impl FromValue for ConstValue { Self::Object(const_object) } - value => { + actual => { return VmResult::err(VmErrorKind::ConstNotSupported { - actual: vm_try!(value.type_info()), + actual: actual.type_info(), }) } }) @@ -191,6 +186,6 @@ impl FromValue for ConstValue { impl ToValue for ConstValue { fn to_value(self) -> VmResult { - VmResult::Ok(vm_try!(ConstValue::into_value(self))) + VmResult::Ok(vm_try!(ConstValue::as_value(&self))) } } diff --git a/crates/rune/src/runtime/control_flow.rs b/crates/rune/src/runtime/control_flow.rs index ba0f87efc..b67d64ab9 100644 --- a/crates/rune/src/runtime/control_flow.rs +++ b/crates/rune/src/runtime/control_flow.rs @@ -1,6 +1,6 @@ use core::ops; -use crate as rune; +use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::runtime::{Formatter, FromValue, ProtocolCaller, ToValue, Value, VmResult}; use crate::Any; @@ -20,7 +20,9 @@ use crate::Any; /// assert_eq!(c.0, 42); /// assert_eq!(c, ControlFlow::Continue(42)); /// ``` -#[derive(Debug, Clone, Any)] +#[derive(Debug, Clone, TryClone, Any)] +#[rune(crate)] +#[try_clone(crate)] #[rune(builtin, static_type = CONTROL_FLOW_TYPE)] pub enum ControlFlow { /// Move on to the next phase of the operation as normal. @@ -80,7 +82,12 @@ impl ControlFlow { } } -from_value!(ControlFlow, into_control_flow); +from_value2!( + ControlFlow, + into_control_flow_ref, + into_control_flow_mut, + into_control_flow +); impl ToValue for ops::ControlFlow where @@ -107,9 +114,7 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - let value = vm_try!(value.into_control_flow()); - - VmResult::Ok(match vm_try!(value.take()) { + VmResult::Ok(match vm_try!(value.into_control_flow()) { ControlFlow::Continue(value) => { ops::ControlFlow::Continue(vm_try!(C::from_value(value))) } diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index 157eb3954..116ffcc3b 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -10,9 +10,10 @@ use musli::{Decode, Encode}; use serde::{Deserialize, Serialize}; use crate as rune; +use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::alloc::String; -use crate::runtime::{Formatter, ProtocolCaller, Value, VmErrorKind, VmResult}; +use crate::runtime::{Formatter, ProtocolCaller, Value, ValueKind, VmErrorKind, VmResult}; use crate::Any; /// Error raised when trying to parse a type string and it fails. @@ -39,7 +40,7 @@ impl fmt::Display for AlignmentFromStrError { } /// A format specification, wrapping an inner value. -#[derive(Any, Debug, Clone)] +#[derive(Any, Debug, Clone, TryClone)] #[rune(builtin, static_type = FORMAT_TYPE)] pub struct Format { /// The value being formatted. @@ -48,10 +49,11 @@ pub struct Format { pub(crate) spec: FormatSpec, } -from_value!(Format, into_format); +from_value2!(Format, into_format_ref, into_format_mut, into_format); /// A format specification. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, Clone, Copy, TryClone, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] #[non_exhaustive] pub struct FormatSpec { /// Formatting flags. @@ -206,22 +208,22 @@ impl FormatSpec { f: &mut Formatter, caller: &mut impl ProtocolCaller, ) -> VmResult<()> { - match value { - Value::Char(c) => { - vm_try!(f.buf_mut().try_push(*c)); + match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Char(c) => { + vm_try!(f.buf_mut().try_push(c)); vm_try!(self.format_fill(f, self.align, self.fill, None)); } - Value::String(s) => { - vm_try!(f.buf_mut().try_push_str(&vm_try!(s.borrow_ref()))); + ValueKind::String(ref s) => { + vm_try!(f.buf_mut().try_push_str(s)); vm_try!(self.format_fill(f, self.align, self.fill, None)); } - Value::Integer(n) => { - let (n, align, fill, sign) = self.int_traits(*n); + ValueKind::Integer(n) => { + let (n, align, fill, sign) = self.int_traits(n); vm_try!(self.format_number(f.buf_mut(), n)); vm_try!(self.format_fill(f, align, fill, sign)); } - Value::Float(n) => { - let (n, align, fill, sign) = self.float_traits(*n); + ValueKind::Float(n) => { + let (n, align, fill, sign) = self.float_traits(n); vm_try!(self.format_float(f.buf_mut(), n)); vm_try!(self.format_fill(f, align, fill, sign)); } @@ -239,22 +241,21 @@ impl FormatSpec { f: &mut Formatter, caller: &mut impl ProtocolCaller, ) -> VmResult<()> { - match value { - Value::String(s) => { - let s = vm_try!(s.borrow_ref()); - vm_write!(f, "{:?}", &*s); + match *vm_try!(value.borrow_kind_ref()) { + ValueKind::String(ref s) => { + vm_write!(f, "{s:?}"); } - Value::Integer(n) => { - let (n, align, fill, sign) = self.int_traits(*n); + ValueKind::Integer(n) => { + let (n, align, fill, sign) = self.int_traits(n); vm_try!(self.format_number(f.buf_mut(), n)); vm_try!(self.format_fill(f, align, fill, sign)); } - Value::Float(n) => { - let (n, align, fill, sign) = self.float_traits(*n); + ValueKind::Float(n) => { + let (n, align, fill, sign) = self.float_traits(n); vm_try!(self.format_float(f.buf_mut(), n)); vm_try!(self.format_fill(f, align, fill, sign)); } - value => { + _ => { vm_try!(value.string_debug_with(f, caller)); } } @@ -263,9 +264,9 @@ impl FormatSpec { } fn format_upper_hex(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match value { - Value::Integer(n) => { - let (n, align, fill, sign) = self.int_traits(*n); + match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Integer(n) => { + let (n, align, fill, sign) = self.int_traits(n); vm_write!(f.buf_mut(), "{:X}", n); vm_try!(self.format_fill(f, align, fill, sign)); } @@ -278,9 +279,9 @@ impl FormatSpec { } fn format_lower_hex(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match value { - Value::Integer(n) => { - let (n, align, fill, sign) = self.int_traits(*n); + match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Integer(n) => { + let (n, align, fill, sign) = self.int_traits(n); vm_write!(f.buf_mut(), "{:x}", n); vm_try!(self.format_fill(f, align, fill, sign)); } @@ -293,9 +294,9 @@ impl FormatSpec { } fn format_binary(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match value { - Value::Integer(n) => { - let (n, align, fill, sign) = self.int_traits(*n); + match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Integer(n) => { + let (n, align, fill, sign) = self.int_traits(n); vm_write!(f.buf_mut(), "{:b}", n); vm_try!(self.format_fill(f, align, fill, sign)); } @@ -308,9 +309,9 @@ impl FormatSpec { } fn format_pointer(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { - match value { - Value::Integer(n) => { - let (n, align, fill, sign) = self.int_traits(*n); + match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Integer(n) => { + let (n, align, fill, sign) = self.int_traits(n); vm_write!(f.buf_mut(), "{:p}", n as *const ()); vm_try!(self.format_fill(f, align, fill, sign)); } @@ -442,7 +443,8 @@ impl fmt::Display for Type { } /// The alignment requested. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, Clone, Copy, TryClone, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] #[non_exhaustive] pub enum Alignment { /// Left alignment. @@ -506,9 +508,10 @@ pub enum Flag { } /// Format specification flags. -#[derive(Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] +#[derive(Clone, Copy, TryClone, Default, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] #[repr(transparent)] #[musli(transparent)] +#[try_clone(copy)] pub struct Flags(u32); impl Flags { diff --git a/crates/rune/src/runtime/from_value.rs b/crates/rune/src/runtime/from_value.rs index d418fb381..3a0049e7c 100644 --- a/crates/rune/src/runtime/from_value.rs +++ b/crates/rune/src/runtime/from_value.rs @@ -2,10 +2,31 @@ use core::cmp::Ordering; use crate::alloc; use crate::runtime::{ - AnyObj, Mut, RawMut, RawRef, Ref, Shared, Value, VmError, VmErrorKind, VmResult, + AnyObj, Mut, RawMut, RawRef, Ref, Value, ValueKind, VmError, VmErrorKind, VmResult, }; use crate::Any; +/// Cheap conversion trait to convert something infallibly into a dynamic [`Value`]. +pub trait IntoValue { + /// Convert into a dynamic [`Value`]. + #[doc(hidden)] + fn into_value(self) -> Value; +} + +impl IntoValue for Value { + #[inline] + fn into_value(self) -> Value { + self + } +} + +impl IntoValue for &Value { + #[inline] + fn into_value(self) -> Value { + self.clone() + } +} + /// Derive macro for the [`FromValue`] trait for converting types from the /// dynamic `Value` container. /// @@ -69,11 +90,11 @@ pub use rune_macros::FromValue; /// assert_eq!(foo, 43); /// # Ok::<_, rune::support::Error>(()) /// ``` -pub fn from_value(value: Value) -> Result +pub fn from_value(value: impl IntoValue) -> Result where T: FromValue, { - T::from_value(value).into_result() + T::from_value(value.into_value()).into_result() } /// Trait for converting types from the dynamic [Value] container. @@ -182,7 +203,8 @@ where T: Any, { fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(vm_try!(value.into_any()).take_downcast())) + let value = vm_try!(value.into_any()); + VmResult::Ok(value) } } @@ -190,8 +212,9 @@ impl FromValue for Mut where T: Any, { + #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(vm_try!(value.into_any()).downcast_into_mut())) + VmResult::Ok(vm_try!(value.into_any_mut())) } } @@ -199,14 +222,15 @@ impl FromValue for Ref where T: Any, { + #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(vm_try!(value.into_any()).downcast_into_ref())) + VmResult::Ok(vm_try!(value.into_any_ref())) } } -impl FromValue for Shared { +impl FromValue for AnyObj { fn from_value(value: Value) -> VmResult { - value.into_any() + VmResult::Ok(vm_try!(value.into_any_obj())) } } @@ -224,44 +248,20 @@ where T: FromValue, { fn from_value(value: Value) -> VmResult { - let option = vm_try!(value.into_option()); - let option = vm_try!(option.take()); - VmResult::Ok(match option { - Some(some) => Some(vm_try!(T::from_value(some))), + VmResult::Ok(match &*vm_try!(value.into_option_ref()) { + Some(some) => Some(vm_try!(T::from_value(some.clone()))), None => None, }) } } -impl UnsafeToRef for Option { - type Guard = RawRef; - - unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let option = vm_try!(value.into_option()); - let option = vm_try!(option.into_ref()); - let (value, guard) = Ref::into_raw(option); - VmResult::Ok((value.as_ref(), guard)) - } -} - -impl UnsafeToMut for Option { - type Guard = RawMut; - - unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - let option = vm_try!(value.into_option()); - let option = vm_try!(option.into_mut()); - let (mut value, guard) = Mut::into_raw(option); - VmResult::Ok((value.as_mut(), guard)) - } -} +from_value_ref!(Option, into_option_ref, into_option_mut, into_option); impl FromValue for alloc::String { fn from_value(value: Value) -> VmResult { - match value { - Value::String(string) => VmResult::Ok(vm_try!(string.take())), - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + match vm_try!(value.take_kind()) { + ValueKind::String(string) => VmResult::Ok(string), + actual => VmResult::err(VmErrorKind::expected::(actual.type_info())), } } } @@ -276,15 +276,12 @@ impl FromValue for ::rust_alloc::string::String { impl FromValue for alloc::Box { fn from_value(value: Value) -> VmResult { - match value { - Value::String(string) => { - let string = vm_try!(string.take()); + match vm_try!(value.take_kind()) { + ValueKind::String(string) => { let string = vm_try!(string.try_into_boxed_str()); VmResult::Ok(string) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + actual => VmResult::err(VmErrorKind::expected::(actual.type_info())), } } } @@ -292,50 +289,59 @@ impl FromValue for alloc::Box { #[cfg(feature = "alloc")] impl FromValue for ::rust_alloc::boxed::Box { fn from_value(value: Value) -> VmResult { - match value { - Value::String(string) => { - let string = vm_try!(string.take()); - let string = ::rust_alloc::boxed::Box::from(string.as_str()); - VmResult::Ok(string) + match vm_try!(value.take_kind()) { + ValueKind::String(string) => { + VmResult::Ok(::rust_alloc::boxed::Box::::from(string.as_str())) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + actual => VmResult::err(VmErrorKind::expected::(actual.type_info())), } } } impl FromValue for Mut { fn from_value(value: Value) -> VmResult { - match value { - Value::String(string) => VmResult::Ok(vm_try!(string.into_mut())), - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + let result = Mut::try_map(vm_try!(value.into_kind_mut()), |kind| match kind { + ValueKind::String(string) => Some(string), + _ => None, + }); + + match result { + Ok(string) => VmResult::Ok(string), + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) + } } } } impl FromValue for Ref { fn from_value(value: Value) -> VmResult { - match value { - Value::String(string) => VmResult::Ok(vm_try!(string.into_ref())), - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + let result = Ref::try_map(vm_try!(value.into_kind_ref()), |kind| match kind { + ValueKind::String(string) => Some(string), + _ => None, + }); + + match result { + Ok(string) => VmResult::Ok(string), + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) + } } } } impl FromValue for Ref { fn from_value(value: Value) -> VmResult { - match value { - Value::String(string) => { - VmResult::Ok(Ref::map(vm_try!(string.into_ref()), |s| s.as_str())) + let result = Ref::try_map(vm_try!(value.into_kind_ref()), |kind| match kind { + ValueKind::String(string) => Some(string.as_str()), + _ => None, + }); + + match result { + Ok(string) => VmResult::Ok(string), + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), } } } @@ -344,15 +350,19 @@ impl UnsafeToRef for str { type Guard = RawRef; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - match value { - Value::String(string) => { - let string = vm_try!(string.into_ref()); + let result = Ref::try_map(vm_try!(value.into_kind_ref()), |kind| match kind { + ValueKind::String(string) => Some(string.as_str()), + _ => None, + }); + + match result { + Ok(string) => { let (string, guard) = Ref::into_raw(string); VmResult::Ok((string.as_ref(), guard)) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) + } } } } @@ -361,15 +371,19 @@ impl UnsafeToMut for str { type Guard = RawMut; unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - match value { - Value::String(string) => { - let string = vm_try!(string.into_mut()); + let result = Mut::try_map(vm_try!(value.into_kind_mut()), |kind| match kind { + ValueKind::String(string) => Some(string.as_mut_str()), + _ => None, + }); + + match result { + Ok(string) => { let (mut string, guard) = Mut::into_raw(string); - VmResult::Ok((string.as_mut().as_mut_str(), guard)) + VmResult::Ok((string.as_mut(), guard)) + } + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), } } } @@ -378,15 +392,19 @@ impl UnsafeToRef for alloc::String { type Guard = RawRef; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - match value { - Value::String(string) => { - let string = vm_try!(string.into_ref()); + let result = Ref::try_map(vm_try!(value.into_kind_ref()), |kind| match kind { + ValueKind::String(string) => Some(string), + _ => None, + }); + + match result { + Ok(string) => { let (string, guard) = Ref::into_raw(string); VmResult::Ok((string.as_ref(), guard)) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) + } } } } @@ -395,15 +413,21 @@ impl UnsafeToMut for alloc::String { type Guard = RawMut; unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - match value { - Value::String(string) => { - let string = vm_try!(string.into_mut()); + let kind = vm_try!(value.into_kind_mut()); + + let result = Mut::try_map(kind, |kind| match kind { + ValueKind::String(string) => Some(string), + _ => None, + }); + + match result { + Ok(string) => { let (mut string, guard) = Mut::into_raw(string); VmResult::Ok((string.as_mut(), guard)) } - actual => VmResult::err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), + Err(actual) => { + VmResult::err(VmErrorKind::expected::(actual.type_info())) + } } } } @@ -413,61 +437,42 @@ where T: FromValue, E: FromValue, { + #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(match vm_try!(vm_try!(value.into_result()).take()) { - Ok(ok) => Result::Ok(vm_try!(T::from_value(ok))), - Err(err) => Result::Err(vm_try!(E::from_value(err))), + VmResult::Ok(match &*vm_try!(value.into_result_ref()) { + Ok(ok) => Result::Ok(vm_try!(T::from_value(ok.clone()))), + Err(err) => Result::Err(vm_try!(E::from_value(err.clone()))), }) } } -impl UnsafeToRef for Result { - type Guard = RawRef; - - unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let result = vm_try!(value.into_result()); - let result = vm_try!(result.into_ref()); - let (value, guard) = Ref::into_raw(result); - VmResult::Ok((value.as_ref(), guard)) - } -} - -impl UnsafeToMut for Result { - type Guard = RawMut; - - unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - let result = vm_try!(value.into_result()); - let result = vm_try!(result.into_mut()); - let (mut value, guard) = Mut::into_raw(result); - VmResult::Ok((value.as_mut(), guard)) - } -} +from_value_ref!(Result, into_result_ref, into_result_mut, into_result); impl FromValue for u8 { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(value.into_byte())) + VmResult::Ok(vm_try!(value.as_byte())) } } impl FromValue for bool { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(value.into_bool())) + VmResult::Ok(vm_try!(value.as_bool())) } } impl FromValue for char { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(value.into_char())) + VmResult::Ok(vm_try!(value.as_char())) } } impl FromValue for i64 { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(value.into_integer())) + VmResult::Ok(vm_try!(value.as_integer())) } } @@ -476,7 +481,7 @@ macro_rules! impl_number { impl FromValue for $ty { #[inline] fn from_value(value: Value) -> VmResult { - value.try_into_integer() + VmResult::Ok(vm_try!(value.try_as_integer())) } } }; @@ -496,14 +501,14 @@ impl_number!(isize); impl FromValue for f64 { #[inline] fn from_value(value: Value) -> VmResult { - value.into_float() + VmResult::Ok(vm_try!(value.as_float())) } } impl FromValue for f32 { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(value.into_float()) as f32) + VmResult::Ok(vm_try!(value.as_float()) as f32) } } @@ -516,7 +521,6 @@ cfg_std! { { fn from_value(value: Value) -> VmResult { let object = vm_try!(value.into_object()); - let object = vm_try!(object.take()); let mut output = <$ty>::with_capacity(object.len()); @@ -544,7 +548,6 @@ macro_rules! impl_try_map { { fn from_value(value: Value) -> VmResult { let object = vm_try!(value.into_object()); - let object = vm_try!(object.take()); let mut output = vm_try!(<$ty>::try_with_capacity(object.len())); @@ -567,6 +570,6 @@ impl_try_map!(alloc::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::str impl FromValue for Ordering { #[inline] fn from_value(value: Value) -> VmResult { - value.into_ordering() + VmResult::Ok(vm_try!(value.as_ordering())) } } diff --git a/crates/rune/src/runtime/function.rs b/crates/rune/src/runtime/function.rs index bc452bf4b..fd337ec2f 100644 --- a/crates/rune/src/runtime/function.rs +++ b/crates/rune/src/runtime/function.rs @@ -9,7 +9,7 @@ use crate::alloc::{self, Box, Vec}; use crate::module; use crate::runtime::{ Args, Call, ConstValue, FromValue, FunctionHandler, OwnedTuple, Rtti, RuntimeContext, Stack, - Unit, Value, VariantRtti, Vm, VmCall, VmErrorKind, VmHalt, VmResult, + Unit, Value, ValueKind, VariantRtti, Vm, VmCall, VmErrorKind, VmHalt, VmResult, }; use crate::shared::AssertSend; use crate::Any; @@ -40,7 +40,7 @@ use crate::Hash; /// let build_some = build; /// assert_eq!(build_some(42), Some(42)); /// ``` -#[derive(Any)] +#[derive(Any, TryClone)] #[repr(transparent)] #[rune(builtin, static_type = FUNCTION_TYPE)] pub struct Function(FunctionImpl); @@ -172,12 +172,11 @@ impl Function { /// let value = vm.call(["main"], ())?; /// /// let value: Function = rune::from_value(value)?; - /// assert_eq!(value.call::<_, u32>((1, 2)).into_result()?, 3); + /// assert_eq!(value.call::((1, 2)).into_result()?, 3); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn call(&self, args: A) -> VmResult + pub fn call(&self, args: impl Args) -> VmResult where - A: Args, T: FromValue, { self.0.call(args) @@ -388,15 +387,14 @@ impl SyncFunction { /// let add = vm.call(["main"], ())?; /// let add: SyncFunction = rune::from_value(add)?; /// - /// let value = add.async_send_call::<_, u32>((1, 2)).await.into_result()?; + /// let value = add.async_send_call::((1, 2)).await.into_result()?; /// assert_eq!(value, 3); /// # Ok::<_, rune::support::Error>(()) /// # })?; /// # Ok::<_, rune::support::Error>(()) /// ``` - pub async fn async_send_call(&self, args: A) -> VmResult + pub async fn async_send_call(&self, args: impl Args + Send) -> VmResult where - A: Send + Args, T: Send + FromValue, { self.0.async_send_call(args).await @@ -426,12 +424,11 @@ impl SyncFunction { /// let add = vm.call(["main"], ())?; /// let add: SyncFunction = rune::from_value(add)?; /// - /// assert_eq!(add.call::<_, u32>((1, 2)).into_result()?, 3); + /// assert_eq!(add.call::((1, 2)).into_result()?, 3); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn call(&self, args: A) -> VmResult + pub fn call(&self, args: impl Args) -> VmResult where - A: Args, T: FromValue, { self.0.call(args) @@ -499,9 +496,8 @@ where OwnedTuple: TryFrom>, VmErrorKind: From<>>::Error>, { - fn call(&self, args: A) -> VmResult + fn call(&self, args: impl Args) -> VmResult where - A: Args, T: FromValue, { let value = match &self.inner { @@ -551,14 +547,14 @@ where T: 'a + Send + FromValue, { let future = async move { - let value = vm_try!(self.call(args)); + let value: Value = vm_try!(self.call(args)); - let value = match value { - Value::Future(future) => { - let future = vm_try!(future.take()); - vm_try!(future.await) + let value = 'out: { + if let ValueKind::Future(future) = &mut *vm_try!(value.borrow_kind_mut()) { + break 'out vm_try!(future.await); } - other => other, + + value }; T::from_value(value) @@ -843,7 +839,7 @@ where } } -#[derive(Clone)] +#[derive(Clone, TryClone)] struct FnHandler { /// The function handler. handler: Arc, @@ -857,7 +853,7 @@ impl fmt::Debug for FnHandler { } } -#[derive(Clone)] +#[derive(Clone, TryClone)] struct FnOffset { context: Arc, /// The unit where the function resides. @@ -874,11 +870,7 @@ struct FnOffset { impl FnOffset { /// Perform a call into the specified offset and return the produced value. - fn call(&self, args: A, extra: E) -> VmResult - where - A: Args, - E: Args, - { + fn call(&self, args: impl Args, extra: impl Args) -> VmResult { vm_try!(check_args(args.count(), self.args)); let mut vm = Vm::new(self.context.clone(), self.unit.clone()); @@ -957,13 +949,13 @@ where } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TryClone)] struct FnUnitStruct { /// The type of the empty. rtti: Arc, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TryClone)] struct FnTupleStruct { /// The type of the tuple. rtti: Arc, @@ -971,13 +963,13 @@ struct FnTupleStruct { args: usize, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TryClone)] struct FnUnitVariant { /// Runtime information fo variant. rtti: Arc, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TryClone)] struct FnTupleVariant { /// Runtime information fo variant. rtti: Arc, @@ -986,14 +978,18 @@ struct FnTupleVariant { } impl FromValue for SyncFunction { + #[inline] fn from_value(value: Value) -> VmResult { - let function = vm_try!(value.into_function()); - let function = vm_try!(function.take()); - function.into_sync() + vm_try!(value.into_function()).into_sync() } } -from_value!(Function, into_function); +from_value2!( + Function, + into_function_ref, + into_function_mut, + into_function +); fn check_args(actual: usize, expected: usize) -> VmResult<()> { if actual != expected { diff --git a/crates/rune/src/runtime/future.rs b/crates/rune/src/runtime/future.rs index 146cc5cea..4ff084edb 100644 --- a/crates/rune/src/runtime/future.rs +++ b/crates/rune/src/runtime/future.rs @@ -3,7 +3,6 @@ use core::future; use core::pin::Pin; use core::task::{Context, Poll}; -use crate as rune; use crate::alloc::{self, Box}; use crate::runtime::{ToValue, Value, VmErrorKind, VmResult}; use crate::Any; @@ -16,7 +15,9 @@ type DynFuture = dyn future::Future> + 'static; /// A type-erased future that can only be unsafely polled in combination with /// the virtual machine that created it. #[derive(Any)] -#[rune(builtin, static_type = FUTURE_TYPE, from_value = Value::into_future)] +#[rune(crate)] +#[rune(builtin, static_type = FUTURE_TYPE)] +#[rune(from_value = Value::into_future)] pub struct Future { future: Option>>, } diff --git a/crates/rune/src/runtime/generator.rs b/crates/rune/src/runtime/generator.rs index b494c03cc..dbff2b03f 100644 --- a/crates/rune/src/runtime/generator.rs +++ b/crates/rune/src/runtime/generator.rs @@ -1,7 +1,7 @@ use core::fmt; use core::iter; -use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{GeneratorState, Iterator, Value, Vm, VmErrorKind, VmExecution, VmResult}; use crate::Any; @@ -23,7 +23,9 @@ use crate::Any; /// assert!(g is Generator) /// ``` #[derive(Any)] -#[rune(builtin, static_type = GENERATOR_TYPE, from_value = Value::into_generator, from_value_params = [Vm])] +#[rune(crate)] +#[rune(builtin, static_type = GENERATOR_TYPE, from_value_params = [Vm])] +#[rune(from_value = Value::into_generator, from_value_ref = Value::into_generator_ref, from_value_mut = Value::into_generator_mut)] pub struct Generator where T: AsRef + AsMut, @@ -52,7 +54,7 @@ where /// Get the next value produced by this stream. #[allow(clippy::should_implement_trait)] pub fn next(&mut self) -> VmResult> { - VmResult::Ok(match vm_try!(self.resume(Value::EmptyTuple)) { + VmResult::Ok(match vm_try!(self.resume(vm_try!(Value::empty()))) { GeneratorState::Yielded(value) => Some(value), GeneratorState::Complete(_) => None, }) @@ -132,3 +134,15 @@ where .finish() } } + +impl TryClone for Generator +where + T: TryClone + AsRef + AsMut, +{ + #[inline] + fn try_clone(&self) -> Result { + Ok(Self { + execution: self.execution.try_clone()?, + }) + } +} diff --git a/crates/rune/src/runtime/generator_state.rs b/crates/rune/src/runtime/generator_state.rs index 28857d46a..55661e993 100644 --- a/crates/rune/src/runtime/generator_state.rs +++ b/crates/rune/src/runtime/generator_state.rs @@ -1,4 +1,5 @@ use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{ProtocolCaller, Value, VmResult}; use crate::Any; @@ -33,14 +34,14 @@ use crate::Any; /// assert_eq!(first, 1); /// /// // Additional resumes require a value. -/// let second = match execution.resume_with(Value::from(2i64)).into_result()? { +/// let second = match execution.resume_with(rune::to_value(2i64)?).into_result()? { /// GeneratorState::Yielded(second) => rune::from_value::(second)?, /// GeneratorState::Complete(..) => panic!("generator completed"), /// }; /// /// assert_eq!(second, 3); /// -/// let ret = match execution.resume_with(Value::from(42i64)).into_result()? { +/// let ret = match execution.resume_with(rune::to_value(42i64)?).into_result()? { /// GeneratorState::Complete(ret) => rune::from_value::(ret)?, /// GeneratorState::Yielded(..) => panic!("generator yielded"), /// }; @@ -48,7 +49,7 @@ use crate::Any; /// assert_eq!(ret, 42); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Debug)] +#[derive(Any, Debug, TryClone)] #[rune(builtin, static_type = GENERATOR_STATE_TYPE)] pub enum GeneratorState { /// The generator yielded. @@ -97,4 +98,9 @@ impl GeneratorState { } } -from_value!(GeneratorState, into_generator_state); +from_value2!( + GeneratorState, + into_generator_state_ref, + into_generator_state_mut, + into_generator_state +); diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index 6d7f4187b..5585fc071 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -5,6 +5,7 @@ use rune_macros::InstDisplay; use serde::{Deserialize, Serialize}; use crate as rune; +use crate::alloc; use crate::alloc::prelude::*; use crate::runtime::{Call, FormatSpec, Type, Value}; use crate::Hash; @@ -1485,15 +1486,15 @@ pub enum InstValue { impl InstValue { /// Convert into a value that can be pushed onto the stack. - pub fn into_value(self) -> Value { + pub fn into_value(self) -> alloc::Result { match self { - Self::EmptyTuple => Value::EmptyTuple, - Self::Bool(v) => Value::Bool(v), - Self::Byte(v) => Value::Byte(v), - Self::Char(v) => Value::Char(v), - Self::Integer(v) => Value::Integer(v), - Self::Float(v) => Value::Float(v), - Self::Type(v) => Value::Type(v), + Self::EmptyTuple => Value::empty(), + Self::Bool(v) => Value::try_from(v), + Self::Byte(v) => Value::try_from(v), + Self::Char(v) => Value::try_from(v), + Self::Integer(v) => Value::try_from(v), + Self::Float(v) => Value::try_from(v), + Self::Type(v) => Value::try_from(v), } } } diff --git a/crates/rune/src/runtime/iterator.rs b/crates/rune/src/runtime/iterator.rs index 353ae1e3e..e51aa0584 100644 --- a/crates/rune/src/runtime/iterator.rs +++ b/crates/rune/src/runtime/iterator.rs @@ -74,7 +74,8 @@ macro_rules! maybe { /// An owning iterator. #[derive(Any)] -#[rune(builtin, static_type = ITERATOR_TYPE, from_value = Value::into_iterator)] +#[rune(builtin, static_type = ITERATOR_TYPE)] +#[rune(from_value = Value::into_iterator, from_value_ref = Value::into_iterator_ref, from_value_mut = Value::into_iterator_mut)] pub struct Iterator { iter: IterRepr, } @@ -181,7 +182,7 @@ impl Iterator { #[inline] pub(crate) fn find(&mut self, find: Function) -> VmResult> { while let Some(value) = vm_try!(self.next()) { - if vm_try!(find.call::<_, bool>((value.clone(),))) { + if vm_try!(find.call::((value.clone(),))) { return VmResult::Ok(Some(value)); } } @@ -192,7 +193,7 @@ impl Iterator { #[inline] pub(crate) fn all(&mut self, find: Function) -> VmResult { while let Some(value) = vm_try!(self.next()) { - let result = vm_try!(find.call::<_, bool>((value.clone(),))); + let result = vm_try!(find.call::((value.clone(),))); if !result { return VmResult::Ok(false); @@ -205,7 +206,7 @@ impl Iterator { #[inline] pub(crate) fn any(&mut self, find: Function) -> VmResult { while let Some(value) = vm_try!(self.next()) { - if vm_try!(find.call::<_, bool>((value.clone(),))) { + if vm_try!(find.call::((value.clone(),))) { return VmResult::Ok(true); } } @@ -306,7 +307,7 @@ impl Iterator { #[inline] pub(crate) fn fold(mut self, mut accumulator: Value, f: Function) -> VmResult { while let Some(value) = vm_try!(self.next()) { - accumulator = vm_try!(f.call::<_, Value>((accumulator, value.clone()))); + accumulator = vm_try!(f.call((accumulator, value.clone()))); } VmResult::Ok(accumulator) @@ -319,7 +320,7 @@ impl Iterator { }; while let Some(value) = vm_try!(self.next()) { - accumulator = vm_try!(f.call::<_, Value>((accumulator, value.clone()))); + accumulator = vm_try!(f.call((accumulator, value.clone()))); } VmResult::Ok(Some(accumulator)) @@ -519,7 +520,7 @@ where fn next(&mut self) -> VmResult> { if let Some(value) = vm_try!(self.iter.next()) { - let out = vm_try!(self.map.call::<_, Value>((value,))); + let out = vm_try!(self.map.call::((value,))); return VmResult::Ok(Some(out)); } @@ -528,7 +529,7 @@ where fn next_back(&mut self) -> VmResult> { if let Some(value) = vm_try!(self.iter.next_back()) { - let out = vm_try!(self.map.call::<_, Value>((value,))); + let out = vm_try!(self.map.call::((value,))); return VmResult::Ok(Some(out)); } @@ -653,7 +654,7 @@ where fn next(&mut self) -> VmResult> { while let Some(value) = vm_try!(self.iter.next()) { - if vm_try!(self.filter.call::<_, bool>((value.clone(),))) { + if vm_try!(self.filter.call::((value.clone(),))) { return VmResult::Ok(Some(value)); } } @@ -663,7 +664,7 @@ where fn next_back(&mut self) -> VmResult> { while let Some(value) = vm_try!(self.iter.next_back()) { - if vm_try!(self.filter.call::<_, bool>((value.clone(),))) { + if vm_try!(self.filter.call::((value.clone(),))) { return VmResult::Ok(Some(value)); } } diff --git a/crates/rune/src/runtime/object.rs b/crates/rune/src/runtime/object.rs index 0d0390081..5a7753696 100644 --- a/crates/rune/src/runtime/object.rs +++ b/crates/rune/src/runtime/object.rs @@ -506,7 +506,7 @@ impl fmt::Debug for Object { } } -from_value!(Object, into_object); +from_value2!(Object, into_object_ref, into_object_mut, into_object); pub struct DebugStruct<'a> { item: &'a ItemBuf, diff --git a/crates/rune/src/runtime/panic.rs b/crates/rune/src/runtime/panic.rs index ebab121ac..5a707bb70 100644 --- a/crates/rune/src/runtime/panic.rs +++ b/crates/rune/src/runtime/panic.rs @@ -41,3 +41,10 @@ impl From for Panic { } } } + +impl PartialEq for Panic { + #[inline] + fn eq(&self, _: &Self) -> bool { + true + } +} diff --git a/crates/rune/src/runtime/protocol_caller.rs b/crates/rune/src/runtime/protocol_caller.rs index 330d49a74..e4fa9dde4 100644 --- a/crates/rune/src/runtime/protocol_caller.rs +++ b/crates/rune/src/runtime/protocol_caller.rs @@ -67,8 +67,8 @@ impl ProtocolCaller for EnvProtocolCaller { } let Some(handler) = context.function(hash) else { - return VmResult::err(VmErrorKind::MissingInstanceFunction { - hash, + return VmResult::err(VmErrorKind::MissingProtocolFunction { + protocol, instance: vm_try!(target.type_info()), }); }; diff --git a/crates/rune/src/runtime/range.rs b/crates/rune/src/runtime/range.rs index 95d37d35a..475022554 100644 --- a/crates/rune/src/runtime/range.rs +++ b/crates/rune/src/runtime/range.rs @@ -3,8 +3,10 @@ use core::fmt; use core::ops; use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{ - EnvProtocolCaller, FromValue, Iterator, ProtocolCaller, ToValue, Value, VmErrorKind, VmResult, + EnvProtocolCaller, FromValue, Iterator, ProtocolCaller, ToValue, Value, ValueKind, VmErrorKind, + VmResult, }; use crate::Any; @@ -51,8 +53,10 @@ use crate::Any; /// let _ = Range::new(start, end); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Clone)] -#[rune(builtin, constructor, from_value = Value::into_range, static_type = RANGE_TYPE)] +#[derive(Any, Clone, TryClone)] +#[try_clone(crate)] +#[rune(builtin, constructor, static_type = RANGE_TYPE)] +#[rune(from_value = Value::into_range, from_value_ref = Value::into_range_ref, from_value_mut = Value::into_range_mut)] pub struct Range { /// The start value of the range. #[rune(get, set)] @@ -91,19 +95,22 @@ impl Range { pub fn iter(&self) -> VmResult { const NAME: &str = "std::ops::Range"; - match (&self.start, &self.end) { - (Value::Byte(start), Value::Byte(end)) => { + match ( + &*vm_try!(self.start.borrow_kind_ref()), + &*vm_try!(self.end.borrow_kind_ref()), + ) { + (ValueKind::Byte(start), ValueKind::Byte(end)) => { VmResult::Ok(Iterator::from_double_ended(NAME, *start..*end)) } - (Value::Char(start), Value::Char(end)) => { + (ValueKind::Char(start), ValueKind::Char(end)) => { VmResult::Ok(Iterator::from_double_ended(NAME, *start..*end)) } - (Value::Integer(start), Value::Integer(end)) => { + (ValueKind::Integer(start), ValueKind::Integer(end)) => { VmResult::Ok(Iterator::from_double_ended(NAME, *start..*end)) } (start, end) => VmResult::err(VmErrorKind::UnsupportedIterRange { - start: vm_try!(start.type_info()), - end: vm_try!(end.type_info()), + start: start.type_info(), + end: end.type_info(), }), } } @@ -311,7 +318,7 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - let range = vm_try!(vm_try!(value.into_range()).take()); + let range = vm_try!(value.into_range()); let start = vm_try!(Idx::from_value(range.start)); let end = vm_try!(Idx::from_value(range.end)); VmResult::Ok(ops::Range { start, end }) diff --git a/crates/rune/src/runtime/range_from.rs b/crates/rune/src/runtime/range_from.rs index d7b0609a3..2c3d69938 100644 --- a/crates/rune/src/runtime/range_from.rs +++ b/crates/rune/src/runtime/range_from.rs @@ -3,8 +3,10 @@ use core::fmt; use core::ops; use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{ - EnvProtocolCaller, FromValue, Iterator, ProtocolCaller, ToValue, Value, VmErrorKind, VmResult, + EnvProtocolCaller, FromValue, Iterator, ProtocolCaller, ToValue, Value, ValueKind, VmErrorKind, + VmResult, }; use crate::Any; @@ -48,8 +50,10 @@ use crate::Any; /// let _ = RangeFrom::new(start); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Clone)] -#[rune(builtin, constructor, from_value = Value::into_range_from, static_type = RANGE_FROM_TYPE)] +#[derive(Any, Clone, TryClone)] +#[try_clone(crate)] +#[rune(builtin, constructor, static_type = RANGE_FROM_TYPE)] +#[rune(from_value = Value::into_range_from, from_value_ref = Value::into_range_from_ref, from_value_mut = Value::into_range_from_mut)] pub struct RangeFrom { /// The start value of the range. #[rune(get, set)] @@ -85,12 +89,12 @@ impl RangeFrom { pub fn iter(&self) -> VmResult { const NAME: &str = "std::ops::RangeFrom"; - match &self.start { - Value::Byte(start) => VmResult::Ok(Iterator::from(NAME, *start..)), - Value::Char(start) => VmResult::Ok(Iterator::from(NAME, *start..)), - Value::Integer(start) => VmResult::Ok(Iterator::from(NAME, *start..)), - start => VmResult::err(VmErrorKind::UnsupportedIterRangeFrom { - start: vm_try!(start.type_info()), + match *vm_try!(self.start.borrow_kind_ref()) { + ValueKind::Byte(start) => VmResult::Ok(Iterator::from(NAME, start..)), + ValueKind::Char(start) => VmResult::Ok(Iterator::from(NAME, start..)), + ValueKind::Integer(start) => VmResult::Ok(Iterator::from(NAME, start..)), + ref start => VmResult::err(VmErrorKind::UnsupportedIterRangeFrom { + start: start.type_info(), }), } } @@ -280,7 +284,7 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - let range = vm_try!(vm_try!(value.into_range_from()).take()); + let range = vm_try!(value.into_range_from()); let start = vm_try!(Idx::from_value(range.start)); VmResult::Ok(ops::RangeFrom { start }) } diff --git a/crates/rune/src/runtime/range_full.rs b/crates/rune/src/runtime/range_full.rs index 32d608942..c25768b1d 100644 --- a/crates/rune/src/runtime/range_full.rs +++ b/crates/rune/src/runtime/range_full.rs @@ -3,6 +3,7 @@ use core::fmt; use core::ops; use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{FromValue, ProtocolCaller, ToValue, Value, VmResult}; use crate::Any; @@ -29,8 +30,10 @@ use crate::Any; /// let _ = RangeFull::new(); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Default, Clone)] -#[rune(builtin, constructor, from_value = Value::into_range_full, static_type = RANGE_FULL_TYPE)] +#[derive(Any, Default, Clone, TryClone)] +#[try_clone(crate)] +#[rune(builtin, constructor, static_type = RANGE_FULL_TYPE)] +#[rune(from_value = Value::into_range_full, from_value_ref = Value::into_range_full_ref, from_value_mut = Value::into_range_full_mut)] pub struct RangeFull; impl RangeFull { @@ -101,7 +104,7 @@ impl ToValue for ops::RangeFull { impl FromValue for ops::RangeFull { #[inline] fn from_value(value: Value) -> VmResult { - let RangeFull = vm_try!(vm_try!(value.into_range_full()).take()); + let RangeFull = vm_try!(value.into_range_full()); VmResult::Ok(ops::RangeFull) } } diff --git a/crates/rune/src/runtime/range_inclusive.rs b/crates/rune/src/runtime/range_inclusive.rs index 7b477c7da..7022e8de6 100644 --- a/crates/rune/src/runtime/range_inclusive.rs +++ b/crates/rune/src/runtime/range_inclusive.rs @@ -3,8 +3,10 @@ use core::fmt; use core::ops; use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{ - EnvProtocolCaller, FromValue, Iterator, ProtocolCaller, ToValue, Value, VmErrorKind, VmResult, + EnvProtocolCaller, FromValue, Iterator, ProtocolCaller, ToValue, Value, ValueKind, VmErrorKind, + VmResult, }; use crate::Any; @@ -52,8 +54,10 @@ use crate::Any; /// let _ = RangeInclusive::new(start, end); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Clone)] -#[rune(builtin, constructor, from_value = Value::into_range_inclusive, static_type = RANGE_INCLUSIVE_TYPE)] +#[derive(Any, Clone, TryClone)] +#[try_clone(crate)] +#[rune(builtin, constructor, static_type = RANGE_INCLUSIVE_TYPE)] +#[rune(from_value = Value::into_range_inclusive, from_value_ref = Value::into_range_inclusive_ref, from_value_mut = Value::into_range_inclusive_mut)] pub struct RangeInclusive { /// The start value of the range. #[rune(get, set)] @@ -92,19 +96,22 @@ impl RangeInclusive { pub fn iter(&self) -> VmResult { const NAME: &str = "std::ops::RangeInclusive"; - match (&self.start, &self.end) { - (Value::Byte(start), Value::Byte(end)) => { + match ( + &*vm_try!(self.start.borrow_kind_ref()), + &*vm_try!(self.end.borrow_kind_ref()), + ) { + (ValueKind::Byte(start), ValueKind::Byte(end)) => { VmResult::Ok(Iterator::from_double_ended(NAME, *start..=*end)) } - (Value::Char(start), Value::Char(end)) => { + (ValueKind::Char(start), ValueKind::Char(end)) => { VmResult::Ok(Iterator::from_double_ended(NAME, *start..=*end)) } - (Value::Integer(start), Value::Integer(end)) => { + (ValueKind::Integer(start), ValueKind::Integer(end)) => { VmResult::Ok(Iterator::from_double_ended(NAME, *start..=*end)) } (start, end) => VmResult::err(VmErrorKind::UnsupportedIterRangeInclusive { - start: vm_try!(start.type_info()), - end: vm_try!(end.type_info()), + start: start.type_info(), + end: end.type_info(), }), } } @@ -312,7 +319,7 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - let range = vm_try!(vm_try!(value.into_range_inclusive()).take()); + let range = vm_try!(value.into_range_inclusive()); let start = vm_try!(Idx::from_value(range.start)); let end = vm_try!(Idx::from_value(range.end)); VmResult::Ok(start..=end) diff --git a/crates/rune/src/runtime/range_to.rs b/crates/rune/src/runtime/range_to.rs index a8e1b158b..48ab47f91 100644 --- a/crates/rune/src/runtime/range_to.rs +++ b/crates/rune/src/runtime/range_to.rs @@ -3,6 +3,7 @@ use core::fmt; use core::ops; use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{EnvProtocolCaller, FromValue, ProtocolCaller, ToValue, Value, VmResult}; use crate::Any; @@ -38,8 +39,11 @@ use crate::Any; /// let _ = RangeTo::new(end); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Clone)] -#[rune(builtin, constructor, from_value = Value::into_range_to, static_type = RANGE_TO_TYPE)] +#[derive(Any, Clone, TryClone)] +#[try_clone(crate)] +#[rune(crate)] +#[rune(builtin, constructor, static_type = RANGE_TO_TYPE)] +#[rune(from_value = Value::into_range_to, from_value_ref = Value::into_range_to_ref, from_value_mut = Value::into_range_to_mut)] pub struct RangeTo { /// The end value of the range. #[rune(get, set)] @@ -201,7 +205,7 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - let range = vm_try!(vm_try!(value.into_range_to()).take()); + let range = vm_try!(value.into_range_to()); let end = vm_try!(Idx::from_value(range.end)); VmResult::Ok(ops::RangeTo { end }) } diff --git a/crates/rune/src/runtime/range_to_inclusive.rs b/crates/rune/src/runtime/range_to_inclusive.rs index 305c14f13..97de71472 100644 --- a/crates/rune/src/runtime/range_to_inclusive.rs +++ b/crates/rune/src/runtime/range_to_inclusive.rs @@ -3,6 +3,7 @@ use core::fmt; use core::ops; use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{EnvProtocolCaller, FromValue, ProtocolCaller, ToValue, Value, VmResult}; use crate::Any; @@ -38,8 +39,9 @@ use crate::Any; /// let _ = RangeToInclusive::new(end); /// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Any, Clone)] -#[rune(builtin, constructor, from_value = Value::into_range_to_inclusive, static_type = RANGE_TO_INCLUSIVE_TYPE)] +#[derive(Any, Clone, TryClone)] +#[rune(builtin, constructor, static_type = RANGE_TO_INCLUSIVE_TYPE)] +#[rune(from_value = Value::into_range_to_inclusive, from_value_ref = Value::into_range_to_inclusive_ref, from_value_mut = Value::into_range_to_inclusive_mut)] pub struct RangeToInclusive { /// The end value of the range. #[rune(get, set)] @@ -201,7 +203,7 @@ where { #[inline] fn from_value(value: Value) -> VmResult { - let range = vm_try!(vm_try!(value.into_range_to_inclusive()).take()); + let range = vm_try!(value.into_range_to_inclusive()); let end = vm_try!(Idx::from_value(range.end)); VmResult::Ok(ops::RangeToInclusive { end }) } diff --git a/crates/rune/src/runtime/shared.rs b/crates/rune/src/runtime/shared.rs index 9eb095e64..cc19f12ff 100644 --- a/crates/rune/src/runtime/shared.rs +++ b/crates/rune/src/runtime/shared.rs @@ -1,4 +1,3 @@ -use core::any::{self, TypeId}; use core::cell::{Cell, UnsafeCell}; use core::fmt; use core::future::Future; @@ -15,21 +14,18 @@ use ::rust_alloc::sync::Arc; use crate::alloc::prelude::*; use crate::alloc::{self, Box}; -use crate::runtime::{ - Access, AccessError, AccessKind, AnyObj, AnyObjError, BorrowMut, BorrowRef, RawAccessGuard, -}; -use crate::Any; +use crate::runtime::{Access, AccessError, BorrowMut, BorrowRef, RawAccessGuard, Snapshot}; /// A shared value. -pub struct Shared { +pub(crate) struct Shared { inner: ptr::NonNull>, } impl Shared { /// Construct a new shared value. - pub fn new(data: T) -> alloc::Result { + pub(crate) fn new(data: T) -> alloc::Result { let shared = SharedBox { - access: Access::new(false), + access: Access::new(), count: Cell::new(1), data: data.into(), }; @@ -41,109 +37,30 @@ impl Shared { }) } - /// Return a debug formatter, that when printed will display detailed - /// diagnostics of this shared type. - pub fn debug(&self) -> SharedDebug<'_, T> { - SharedDebug { shared: self } - } - /// Test if the value is sharable. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// let shared = Shared::new(1u32)?; - /// assert!(shared.is_readable()); - /// - /// { - /// let guard = shared.borrow_ref().unwrap(); - /// assert!(shared.is_readable()); // Note: still readable. - /// } - /// - /// { - /// let guard = shared.borrow_mut().unwrap(); - /// assert!(!shared.is_readable()); - /// } - /// - /// assert!(shared.is_readable()); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - /// - /// # Taking inner value - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// let shared = Shared::new(1u32)?; - /// let shared2 = shared.clone(); - /// assert!(shared.is_readable()); - /// shared.take().unwrap(); - /// assert!(!shared2.is_readable()); - /// assert!(shared2.take().is_err()); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn is_readable(&self) -> bool { + pub(crate) fn is_readable(&self) -> bool { // Safety: Since we have a reference to this shared, we know that the // inner is available. unsafe { self.inner.as_ref().access.is_shared() } } /// Test if the value is exclusively accessible. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// let shared = Shared::new(1u32)?; - /// assert!(shared.is_writable()); - /// - /// { - /// let guard = shared.borrow_ref().unwrap(); - /// assert!(!shared.is_writable()); - /// } - /// - /// assert!(shared.is_writable()); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn is_writable(&self) -> bool { + pub(crate) fn is_writable(&self) -> bool { // Safety: Since we have a reference to this shared, we know that the // inner is available. unsafe { self.inner.as_ref().access.is_exclusive() } } + /// Get access snapshot of shared value. + pub(crate) fn snapshot(&self) -> Snapshot { + unsafe { self.inner.as_ref().access.snapshot() } + } + /// Take the interior value, if we have exlusive access to it and there /// are no other live exlusive or shared references. /// /// A value that has been taken can no longer be accessed. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// #[derive(Debug)] - /// struct Foo { - /// counter: isize, - /// } - /// - /// let a = Shared::new(Foo { counter: 0 })?; - /// let b = a.clone(); - /// - /// { - /// let mut a = a.borrow_mut().unwrap(); - /// // NB: this is prevented since we have a live reference. - /// assert!(b.take().is_err()); - /// a.counter += 1; - /// } - /// - /// let a = a.take().unwrap(); - /// assert_eq!(a.counter, 1); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn take(self) -> Result { + pub(crate) fn take(self) -> Result { // Safety: We know that interior value is alive since this container is // alive. // @@ -154,7 +71,7 @@ impl Shared { // NB: don't drop guard to avoid yielding access back. // This will prevent the value from being dropped in the shared // destructor and future illegal access of any kind. - let _ = ManuallyDrop::new(inner.access.take(AccessKind::Any)?); + let _ = ManuallyDrop::new(inner.access.take()?); // Read the pointer out without dropping the inner structure. // The data field will be invalid at this point, which should be @@ -171,49 +88,21 @@ impl Shared { /// /// This prevents other exclusive accesses from being performed while the /// guard returned from this function is live. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// #[derive(Debug)] - /// struct Foo { - /// counter: isize, - /// } - /// - /// let a = Shared::new(Foo { counter: 0 })?; - /// let b = a.clone(); - /// - /// b.borrow_mut().unwrap().counter += 1; - /// - /// { - /// // Consumes `a`. - /// let mut a = a.into_ref().unwrap(); - /// assert_eq!(a.counter, 1); - /// assert!(b.borrow_mut().is_err()); - /// } - /// - /// let mut b = b.borrow_mut().unwrap(); - /// b.counter += 1; - /// assert_eq!(b.counter, 2); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn into_ref(self) -> Result, AccessError> { + pub(crate) fn into_ref(self) -> Result, AccessError> { // NB: we default to a "safer" mode with `AccessKind::Owned`, where // references cannot be converted to an `Mut` in order to avoid // a potential soundness panic. - self.internal_into_ref(AccessKind::Owned) + self.internal_into_ref() } /// Internal implementation of into_ref. - pub(crate) fn internal_into_ref(self, kind: AccessKind) -> Result, AccessError> { + pub(crate) fn internal_into_ref(self) -> Result, AccessError> { // Safety: We know that interior value is alive since this container is // alive. // // Appropriate access is checked when constructing the guards. unsafe { - let guard = self.inner.as_ref().access.shared(kind)?.into_raw(); + let guard = self.inner.as_ref().access.shared()?.into_raw(); // NB: we need to prevent the Drop impl for Shared from being called, // since we are deconstructing its internals. @@ -232,46 +121,21 @@ impl Shared { /// /// This prevents other exclusive and shared accesses from being performed /// while the guard returned from this function is live. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// #[derive(Debug)] - /// struct Foo { - /// counter: isize, - /// } - /// - /// let a = Shared::new(Foo { counter: 0 })?; - /// let b = a.clone(); - /// - /// { - /// // Consumes `a`. - /// let mut a = a.into_mut().unwrap(); - /// a.counter += 1; - /// - /// assert!(b.borrow_ref().is_err()); - /// } - /// - /// assert_eq!(b.borrow_ref().unwrap().counter, 1); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn into_mut(self) -> Result, AccessError> { + pub(crate) fn into_mut(self) -> Result, AccessError> { // NB: we default to a "safer" mode with `AccessKind::Owned`, where // references cannot be converted to an `Mut` in order to avoid // a potential soundness panic. - self.internal_into_mut(AccessKind::Owned) + self.internal_into_mut() } /// Internal implementation of into_mut. - pub(crate) fn internal_into_mut(self, kind: AccessKind) -> Result, AccessError> { + pub(crate) fn internal_into_mut(self) -> Result, AccessError> { // Safety: We know that interior value is alive since this container is // alive. // // Appropriate access is checked when constructing the guards. unsafe { - let guard = self.inner.as_ref().access.exclusive(kind)?.into_raw(); + let guard = self.inner.as_ref().access.exclusive()?.into_raw(); // NB: we need to prevent the Drop impl for Shared from being called, // since we are deconstructing its internals. @@ -284,6 +148,25 @@ impl Shared { }) } } + + /// Deconstruct the shader value into a guard and shared box. + /// + /// # Safety + /// + /// The content of the shared value will be forcibly destructed once the + /// returned guard is dropped, use of the shared value after this point will + /// lead to undefined behavior. + pub(crate) unsafe fn into_drop_guard(self) -> (Self, SharedPointerGuard) { + // Increment the reference count by one, to prevent it from every being + // dropped. + SharedBox::inc(self.inner.as_ptr()); + + let guard = SharedPointerGuard { + _inner: RawDrop::take_shared_box(self.inner), + }; + + (self, guard) + } } impl Shared { @@ -291,41 +174,14 @@ impl Shared { /// /// This prevents other exclusive accesses from being performed while the /// guard returned from this function is live. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// #[derive(Debug)] - /// struct Foo { - /// counter: isize, - /// } - /// - /// let a = Shared::new(Foo { counter: 0 })?; - /// - /// a.borrow_mut().unwrap().counter += 1; - /// - /// { - /// let mut a_ref = a.borrow_ref().unwrap(); - /// assert_eq!(a_ref.counter, 1); - /// assert!(a.borrow_mut().is_err()); - /// assert!(a.borrow_ref().is_ok()); - /// } - /// - /// let mut a = a.borrow_mut().unwrap(); - /// a.counter += 1; - /// assert_eq!(a.counter, 2); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn borrow_ref(&self) -> Result, AccessError> { + pub(crate) fn borrow_ref(&self) -> Result, AccessError> { // Safety: We know that interior value is alive since this container is // alive. // // Appropriate access is checked when constructing the guards. unsafe { let inner = self.inner.as_ref(); - let guard = inner.access.shared(AccessKind::Any)?; + let guard = inner.access.shared()?; mem::forget(guard); Ok(BorrowRef::new(&*inner.data.get(), &inner.access)) } @@ -335,367 +191,20 @@ impl Shared { /// /// This prevents other shared or exclusive accesses from being performed /// while the guard returned from this function is live. - /// - /// # Examples - /// - /// ``` - /// use rune::runtime::Shared; - /// - /// #[derive(Debug)] - /// struct Foo { - /// counter: isize, - /// } - /// - /// let a = Shared::new(Foo { counter: 0 })?; - /// - /// { - /// let mut a_mut = a.borrow_mut().unwrap(); - /// a_mut.counter += 1; - /// assert_eq!(a_mut.counter, 1); - /// assert!(a.borrow_ref().is_err()); - /// } - /// - /// let a = a.borrow_ref().unwrap(); - /// assert_eq!(a.counter, 1); - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub fn borrow_mut(&self) -> Result, AccessError> { + pub(crate) fn borrow_mut(&self) -> Result, AccessError> { // Safety: We know that interior value is alive since this container is // alive. // // Appropriate access is checked when constructing the guards. unsafe { let inner = self.inner.as_ref(); - let guard = inner.access.exclusive(AccessKind::Any)?; + let guard = inner.access.exclusive()?; mem::forget(guard); Ok(BorrowMut::new(&mut *inner.data.get(), &inner.access)) } } } -impl Shared { - /// Construct a `Shared` from a pointer, that will be "taken" once the - /// returned guard is dropped. - /// - /// # Safety - /// - /// The reference must be valid for the duration of the guard. - /// - /// # Examples - /// - /// ``` - /// use rune::Any; - /// use rune::runtime::Shared; - /// - /// #[derive(Any)] - /// struct Thing(u32); - /// - /// let value = Thing(10u32); - /// - /// unsafe { - /// let (shared, guard) = Shared::from_ref(&value)?; - /// assert!(shared.downcast_borrow_mut::().is_err()); - /// assert_eq!(10u32, shared.downcast_borrow_ref::().unwrap().0); - /// - /// drop(guard); - /// - /// assert!(shared.downcast_borrow_mut::().is_err()); - /// assert!(shared.downcast_borrow_ref::().is_err()); - /// } - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub unsafe fn from_ref(data: &T) -> alloc::Result<(Self, SharedPointerGuard)> - where - T: Any, - { - Self::unsafe_from_any_pointer(AnyObj::from_ref(data)) - } - - /// Construct a `Shared` from a mutable pointer, that will be "taken" - /// once the returned guard is dropped. - /// - /// # Safety - /// - /// The reference must be valid for the duration of the guard. - /// - /// # Examples - /// - /// ``` - /// use rune::Any; - /// use rune::runtime::Shared; - /// - /// #[derive(Any)] - /// struct Thing(u32); - /// - /// let mut value = Thing(10u32); - /// - /// unsafe { - /// let (shared, guard) = Shared::from_mut(&mut value)?; - /// shared.downcast_borrow_mut::().unwrap().0 = 20; - /// - /// assert_eq!(20u32, shared.downcast_borrow_mut::().unwrap().0); - /// assert_eq!(20u32, shared.downcast_borrow_ref::().unwrap().0); - /// - /// drop(guard); - /// - /// assert!(shared.downcast_borrow_mut::().is_err()); - /// assert!(shared.downcast_borrow_ref::().is_err()); - /// } - /// # Ok::<_, rune::alloc::Error>(()) - /// ``` - pub unsafe fn from_mut(data: &mut T) -> alloc::Result<(Self, SharedPointerGuard)> - where - T: Any, - { - Self::unsafe_from_any_pointer(AnyObj::from_mut(data)) - } - - /// Construct a `Shared` from an Any which is expected to wrap a - /// pointer, that will be "taken" once the returned guard is dropped. - /// - /// # Safety - /// - /// The reference must be valid for the duration of the guard. - unsafe fn unsafe_from_any_pointer(any: AnyObj) -> alloc::Result<(Self, SharedPointerGuard)> { - let shared = SharedBox { - access: Access::new(true), - count: Cell::new(2), - data: any.into(), - }; - let inner = ptr::NonNull::from(Box::leak(Box::try_new(shared)?)); - - let guard = SharedPointerGuard { - _inner: RawDrop::take_shared_box(inner), - }; - - let value = Self { inner }; - Ok((value, guard)) - } - - /// Take the interior value, if we have exlusive access to it and there - /// exist no other references. - pub fn take_downcast(self) -> Result - where - T: Any, - { - // Safety: We know that interior value is alive since this container is - // alive. - // - // Appropriate access is checked when constructing the guards. - unsafe { - let inner = self.inner.as_ref(); - - // NB: don't drop guard to avoid yielding access back. - // This will prevent the value from being dropped in the shared - // destructor and future illegal access of any kind. - let guard = ManuallyDrop::new(inner.access.take(AccessKind::Any)?); - - // Read the pointer out without dropping the inner structure. - // Note that the data field will after this point be invalid. - // - // Future access is forever prevented since we never release - // exclusive access (see above). - let any = ptr::read(inner.data.get()); - - let expected = TypeId::of::(); - - let (e, any) = match any.raw_take(expected) { - Ok(value) => { - return Ok(Box::into_inner(Box::from_raw_in( - value as *mut T, - rune_alloc::alloc::Global, - ))) - } - Err((AnyObjError::Cast, any)) => { - let actual = any.type_name(); - - let e = AccessError::UnexpectedType { - actual, - expected: any::type_name::().into(), - }; - - (e, any) - } - Err((e, any)) => (e.into(), any), - }; - - // At this point type coercion has failed for one reason or another, - // so we reconstruct the state of the Shared container so that it - // can be more cleanly dropped. - - // Drop the guard to release exclusive access. - drop(ManuallyDrop::into_inner(guard)); - - // Write the potentially modified value back so that it can be used - // by other `Shared` users pointing to the same value. This - // conveniently also avoids dropping `any` which will be done by - // `Shared` as appropriate. - ptr::write(inner.data.get(), any); - Err(e) - } - } - - /// Get an shared, downcasted reference to the contained value. - pub fn downcast_borrow_ref(&self) -> Result, AccessError> - where - T: Any, - { - unsafe { - let inner = self.inner.as_ref(); - let guard = inner.access.shared(AccessKind::Any)?; - let expected = TypeId::of::(); - - let data = match (*inner.data.get()).raw_as_ptr(expected) { - Ok(data) => data, - Err(AnyObjError::Cast) => { - return Err(AccessError::UnexpectedType { - expected: any::type_name::().into(), - actual: (*inner.data.get()).type_name(), - }); - } - Err(e) => { - return Err(e.into()); - } - }; - - mem::forget(guard); - Ok(BorrowRef::new(&*(data as *const T), &inner.access)) - } - } - - /// Get an exclusive, downcasted reference to the contained value. - pub fn downcast_borrow_mut(&self) -> Result, AccessError> - where - T: Any, - { - unsafe { - let inner = self.inner.as_ref(); - let guard = inner.access.exclusive(AccessKind::Any)?; - let expected = TypeId::of::(); - - let data = match (*inner.data.get()).raw_as_mut(expected) { - Ok(data) => data, - Err(AnyObjError::Cast) => { - return Err(AccessError::UnexpectedType { - expected: any::type_name::().into(), - actual: (*inner.data.get()).type_name(), - }); - } - Err(e) => { - return Err(e.into()); - } - }; - - mem::forget(guard); - Ok(BorrowMut::new(&mut *(data as *mut T), &inner.access)) - } - } - - /// Get a shared value and downcast. - pub fn downcast_into_ref(self) -> Result, AccessError> - where - T: Any, - { - // NB: we default to a "safer" mode with `AccessKind::Owned`, where - // references cannot be converted to an `Mut` in order to avoid - // a potential soundness panic. - self.internal_downcast_into_ref(AccessKind::Owned) - } - - /// Internal implementation of `downcast_into_ref`. - pub(crate) fn internal_downcast_into_ref( - self, - kind: AccessKind, - ) -> Result, AccessError> - where - T: Any, - { - unsafe { - let (data, guard) = { - let inner = self.inner.as_ref(); - let guard = inner.access.shared(kind)?; - let expected = TypeId::of::(); - - match (*inner.data.get()).raw_as_ptr(expected) { - Ok(data) => (data, guard), - Err(AnyObjError::Cast) => { - return Err(AccessError::UnexpectedType { - expected: any::type_name::().into(), - actual: (*inner.data.get()).type_name(), - }); - } - Err(e) => { - return Err(e.into()); - } - } - }; - - let guard = guard.into_raw(); - // NB: we need to prevent the Drop impl for Shared from being called, - // since we are deconstructing its internals. - let this = ManuallyDrop::new(self); - - Ok(Ref { - data: ptr::NonNull::new_unchecked(data as *const T as *mut T), - guard: Some(guard), - inner: RawDrop::decrement_shared_box(this.inner), - }) - } - } - - /// Get an exclusive value and downcast. - pub fn downcast_into_mut(self) -> Result, AccessError> - where - T: Any, - { - // NB: we default to a "safer" mode with `AccessKind::Owned`, where - // references cannot be converted to an `Mut` in order to avoid - // a potential soundness panic. - self.internal_downcast_into_mut(AccessKind::Owned) - } - - /// Internal implementation of `downcast_into_mut`. - pub(crate) fn internal_downcast_into_mut( - self, - kind: AccessKind, - ) -> Result, AccessError> - where - T: Any, - { - unsafe { - let (data, guard) = { - let inner = self.inner.as_ref(); - let guard = inner.access.exclusive(kind)?; - let expected = TypeId::of::(); - - match (*inner.data.get()).raw_as_mut(expected) { - Ok(data) => (data, guard), - Err(AnyObjError::Cast) => { - return Err(AccessError::UnexpectedType { - expected: any::type_name::().into(), - actual: (*inner.data.get()).type_name(), - }); - } - Err(e) => { - return Err(e.into()); - } - } - }; - - let guard = guard.into_raw(); - // NB: we need to prevent the Drop impl for Shared from being called, - // since we are deconstructing its internals. - let this = ManuallyDrop::new(self); - - Ok(Mut { - data: ptr::NonNull::new_unchecked(data as *mut T), - guard: Some(guard), - inner: RawDrop::decrement_shared_box(this.inner), - }) - } - } -} - impl TryClone for Shared { #[inline] fn try_clone(&self) -> alloc::Result { @@ -740,38 +249,6 @@ where } } -/// A debug helper that prints detailed diagnostics on the type being debugged. -/// -/// Constructed using [debug][Shared::debug]. -pub struct SharedDebug<'a, T: ?Sized> { - shared: &'a Shared, -} - -impl fmt::Debug for SharedDebug<'_, T> -where - T: Any + fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - // Safety: by virtue of holding onto a shared we can safely access - // `inner` because it must outlive any `Shared` instances. - unsafe { - let inner = self.shared.inner.as_ref(); - let mut debug = fmt.debug_struct("Shared"); - - debug.field("access", &inner.access); - debug.field("count", &inner.count.get()); - - if !inner.access.is_shared() { - debug.field("data", &any::type_name::()); - } else { - debug.field("data", &&*inner.data.get()); - } - - debug.finish() - } - } -} - /// The boxed internals of [Shared]. #[repr(C)] struct SharedBox { @@ -909,15 +386,15 @@ impl RawDrop { /// # Safety /// /// Should only be constructed over a pointer that is lively owned. - fn take_shared_box(inner: ptr::NonNull>) -> Self { - unsafe fn drop_fn_impl(data: *const ()) { - let shared = data as *mut () as *mut SharedBox; + fn take_shared_box(inner: ptr::NonNull>) -> Self { + unsafe fn drop_fn_impl(data: *const ()) { + let shared = data as *mut () as *mut SharedBox; // Mark the shared box for exclusive access. let _ = ManuallyDrop::new( (*shared) .access - .take(AccessKind::Any) + .take() .expect("raw pointers must not be shared"), ); @@ -930,7 +407,7 @@ impl RawDrop { Self { data: inner.as_ptr() as *const (), - drop_fn: drop_fn_impl, + drop_fn: drop_fn_impl::, } } } @@ -1020,13 +497,14 @@ impl Ref { /// # Examples /// /// ``` - /// use rune::runtime::{Shared, Ref}; + /// use rune::runtime::{Bytes, Ref}; + /// use rune::alloc::try_vec; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.into_ref()?; - /// let value: Ref<[u32]> = Ref::map(vec, |vec| &vec[0..2]); + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes: Ref = rune::from_value(bytes)?; + /// let value: Ref<[u8]> = Ref::map(bytes, |vec| &vec[0..2]); /// - /// assert_eq!(&*value, &[1u32, 2u32][..]); + /// assert_eq!(&*value, &[1, 2][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] @@ -1055,16 +533,21 @@ impl Ref { /// # Examples /// /// ``` - /// use rune::runtime::{Shared, Ref}; + /// use rune::runtime::{Bytes, Ref}; + /// use rune::alloc::try_vec; + /// + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes: Ref = rune::from_value(bytes)?; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.into_ref()?; - /// let value: Option> = Ref::try_map(vec, |vec| vec.get(0..2)); + /// let Ok(value) = Ref::try_map(bytes, |bytes| bytes.get(0..2)) else { + /// panic!("Conversion failed"); + /// }; /// - /// assert_eq!(value.as_deref(), Some(&[1u32, 2u32][..])); + /// assert_eq!(&value[..], &[1, 2][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn try_map(this: Self, f: F) -> Option> + #[inline] + pub fn try_map(this: Self, f: F) -> Result, Ref> where F: FnOnce(&T) -> Option<&U>, { @@ -1075,11 +558,44 @@ impl Ref { // Safety: this follows the same safety guarantees as when the managed // ref was acquired. And since we have a managed reference to `T`, we're // permitted to do any sort of projection to `U`. - f(unsafe { data.as_ref() }).map(|data| Ref { - data: data.into(), - guard, - inner, - }) + + unsafe { + let Some(data) = f(data.as_ref()) else { + return Err(Ref { data, guard, inner }); + }; + + Ok(Ref { + data: data.into(), + guard, + inner, + }) + } + } + + #[inline] + pub(crate) fn result_map(this: Self, f: F) -> Result, (E, Ref)> + where + F: FnOnce(&T) -> Result<&U, E>, + { + let Self { + data, guard, inner, .. + } = this; + + // Safety: this follows the same safety guarantees as when the managed + // ref was acquired. And since we have a managed reference to `T`, we're + // permitted to do any sort of projection to `U`. + unsafe { + let data = match f(data.as_ref()) { + Ok(data) => data, + Err(e) => return Err((e, Ref { data, guard, inner })), + }; + + Ok(Ref { + data: data.into(), + guard, + inner, + }) + } } /// Convert into a raw pointer and associated raw access guard. @@ -1097,6 +613,20 @@ impl Ref { (this.data, guard) } + + /// Convert a raw reference and guard into a regular reference. + /// + /// # Safety + /// + /// The caller is responsible for ensuring that the raw reference is + /// associated with the specific pointer. + pub unsafe fn from_raw(data: ptr::NonNull, guard: RawRef) -> Self { + Self { + data, + guard: guard._guard, + inner: guard._inner, + } + } } impl AsRef for Ref { @@ -1158,13 +688,14 @@ impl Mut { /// # Examples /// /// ``` - /// use rune::runtime::{Mut, Shared}; + /// use rune::runtime::{Bytes, Mut}; + /// use rune::alloc::try_vec; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.into_mut()?; - /// let value: Mut<[u32]> = Mut::map(vec, |vec| &mut vec[0..2]); + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes: Mut = rune::from_value(bytes)?; + /// let value: Mut<[u8]> = Mut::map(bytes, |bytes| &mut bytes[0..2]); /// - /// assert_eq!(&*value, &mut [1u32, 2u32][..]); + /// assert_eq!(&*value, &mut [1, 2][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn map(this: Self, f: F) -> Mut @@ -1195,16 +726,21 @@ impl Mut { /// # Examples /// /// ``` - /// use rune::runtime::{Mut, Shared}; + /// use rune::runtime::{Bytes, Mut}; + /// use rune::alloc::try_vec; /// - /// let vec = Shared::>::new(vec![1, 2, 3, 4])?; - /// let vec = vec.into_mut()?; - /// let mut value: Option> = Mut::try_map(vec, |vec| vec.get_mut(0..2)); + /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?; + /// let bytes: Mut = rune::from_value(bytes)?; /// - /// assert_eq!(value.as_deref_mut(), Some(&mut [1u32, 2u32][..])); + /// let Ok(mut value) = Mut::try_map(bytes, |bytes| bytes.get_mut(0..2)) else { + /// panic!("Conversion failed"); + /// }; + /// + /// assert_eq!(&mut value[..], &mut [1, 2][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn try_map(this: Self, f: F) -> Option> + #[inline] + pub fn try_map(this: Self, f: F) -> Result, Mut> where F: FnOnce(&mut T) -> Option<&mut U>, { @@ -1218,11 +754,46 @@ impl Mut { // Safety: this follows the same safety guarantees as when the managed // ref was acquired. And since we have a managed reference to `T`, we're // permitted to do any sort of projection to `U`. - f(unsafe { data.as_mut() }).map(|data| Mut { - data: data.into(), + unsafe { + let Some(data) = f(data.as_mut()) else { + return Err(Mut { data, guard, inner }); + }; + + Ok(Mut { + data: data.into(), + guard, + inner, + }) + } + } + + #[inline] + pub(crate) fn result_map(this: Self, f: F) -> Result, (E, Mut)> + where + F: FnOnce(&mut T) -> Result<&mut U, E>, + { + let Self { + mut data, guard, inner, - }) + .. + } = this; + + // Safety: this follows the same safety guarantees as when the managed + // ref was acquired. And since we have a managed reference to `T`, we're + // permitted to do any sort of projection to `U`. + unsafe { + let data = match f(data.as_mut()) { + Ok(data) => data, + Err(error) => return Err((error, Mut { data, guard, inner })), + }; + + Ok(Mut { + data: data.into(), + guard, + inner, + }) + } } /// Convert into a raw pointer and associated raw access guard. @@ -1240,6 +811,21 @@ impl Mut { (this.data, guard) } + + /// Convert a raw mutable reference and guard into a regular mutable + /// reference. + /// + /// # Safety + /// + /// The caller is responsible for ensuring that the raw mutable reference is + /// associated with the specific pointer. + pub unsafe fn from_raw(data: ptr::NonNull, guard: RawMut) -> Self { + Self { + data, + guard: guard._guard, + inner: guard._inner, + } + } } impl AsRef for Mut { @@ -1302,9 +888,9 @@ pub struct RawMut { _inner: RawDrop, } -/// A guard for an `Any` containing a pointer. +/// A drop guard for a shared value. /// -/// Constructing using [Shared::from_ref] or [Shared::from_mut]. +/// Once this is dropped, the shared value will be destructed. pub struct SharedPointerGuard { _inner: RawDrop, } diff --git a/crates/rune/src/runtime/stack.rs b/crates/rune/src/runtime/stack.rs index 61d22ba91..f4cb41f47 100644 --- a/crates/rune/src/runtime/stack.rs +++ b/crates/rune/src/runtime/stack.rs @@ -10,7 +10,7 @@ use crate::alloc::{self, Vec}; use crate::runtime::{InstAddress, Value}; /// An error raised when interacting with the stack. -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[non_exhaustive] pub struct StackError; @@ -46,7 +46,9 @@ impl Stack { /// let mut stack = Stack::new(); /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); - /// assert!(matches!(stack.pop()?, Value::String(..))); + /// let value = stack.pop()?; + /// let value: String = rune::from_value(value)?; + /// assert_eq!(value, "Hello World"); /// # Ok::<_, rune::support::Error>(()) /// ``` pub const fn new() -> Self { @@ -65,7 +67,9 @@ impl Stack { /// let mut stack = Stack::with_capacity(16)?; /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); - /// assert!(matches!(stack.pop()?, Value::String(..))); + /// let value = stack.pop()?; + /// let value: String = rune::from_value(value)?; + /// assert_eq!(value, "Hello World"); /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn with_capacity(capacity: usize) -> alloc::Result { @@ -145,11 +149,15 @@ impl Stack { /// let mut stack = Stack::new(); /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); - /// assert!(matches!(stack.pop()?, Value::String(..))); + /// assert_eq!(rune::from_value::(stack.pop()?)?, "Hello World"); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn push(&mut self, value: Value) -> alloc::Result<()> { - self.stack.try_push(value)?; + pub fn push(&mut self, value: T) -> alloc::Result<()> + where + Value: TryFrom, + alloc::Error: From<>::Error>, + { + self.stack.try_push(Value::try_from(value)?)?; Ok(()) } @@ -162,7 +170,9 @@ impl Stack { /// let mut stack = Stack::new(); /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); - /// assert!(matches!(stack.pop()?, Value::String(..))); + /// let value = stack.pop()?; + /// let value: String = rune::from_value(value)?; + /// assert_eq!(value, "Hello World"); /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn pop(&mut self) -> Result { @@ -186,11 +196,11 @@ impl Stack { /// stack.push(rune::to_value(String::from("foo"))?); /// stack.push(rune::to_value(())?); /// - /// let mut it = stack.drain(2)?; + /// let values = stack.drain(2)?.collect::>(); /// - /// assert!(matches!(it.next(), Some(Value::String(..)))); - /// assert!(matches!(it.next(), Some(Value::EmptyTuple))); - /// assert!(matches!(it.next(), None)); + /// assert_eq!(values.len(), 2); + /// assert_eq!(rune::from_value::(&values[0])?, "foo"); + /// assert_eq!(rune::from_value(&values[1])?, ()); /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn drain( @@ -221,13 +231,17 @@ impl Stack { /// /// let mut stack = Stack::new(); /// - /// stack.extend([Value::from(42i64), Value::try_from(String::try_from("foo")?)?, Value::EmptyTuple]); + /// stack.extend([ + /// rune::to_value(42i64)?, + /// rune::to_value(String::try_from("foo")?)?, + /// rune::to_value(())? + /// ]); /// - /// let mut it = stack.drain(2)?; + /// let values = stack.drain(2)?.collect::>(); /// - /// assert!(matches!(it.next(), Some(Value::String(..)))); - /// assert!(matches!(it.next(), Some(Value::EmptyTuple))); - /// assert!(matches!(it.next(), None)); + /// assert_eq!(values.len(), 2); + /// assert_eq!(rune::from_value::(&values[0])?, "foo"); + /// assert_eq!(rune::from_value(&values[1])?, ()); /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn extend(&mut self, iter: I) -> alloc::Result<()> diff --git a/crates/rune/src/runtime/stream.rs b/crates/rune/src/runtime/stream.rs index f8c8787a8..3901a5f70 100644 --- a/crates/rune/src/runtime/stream.rs +++ b/crates/rune/src/runtime/stream.rs @@ -1,12 +1,14 @@ use core::fmt; -use crate as rune; -use crate::runtime::{GeneratorState, Shared, Value, Vm, VmErrorKind, VmExecution, VmResult}; +use crate::alloc::clone::TryClone; +use crate::runtime::{GeneratorState, Mut, Value, Vm, VmErrorKind, VmExecution, VmResult}; use crate::Any; /// A stream with a stored virtual machine. #[derive(Any)] -#[rune(builtin, static_type = STREAM_TYPE, from_value = Value::into_stream, from_value_params = [Vm])] +#[rune(crate)] +#[rune(builtin, static_type = STREAM_TYPE, from_value_params = [Vm])] +#[rune(from_value = Value::into_stream, from_value_ref = Value::into_stream_ref, from_value_mut = Value::into_stream_mut)] pub struct Stream where T: AsRef + AsMut, @@ -34,14 +36,14 @@ where /// Get the next value produced by this stream. pub async fn next(&mut self) -> VmResult> { - VmResult::Ok(match vm_try!(self.resume(Value::EmptyTuple).await) { + VmResult::Ok(match vm_try!(self.resume(vm_try!(Value::empty())).await) { GeneratorState::Yielded(value) => Some(value), GeneratorState::Complete(_) => None, }) } - pub(crate) async fn next_shared(this: Shared>) -> VmResult> { - vm_try!(this.borrow_mut()).next().await + pub(crate) async fn next_shared(mut this: Mut>) -> VmResult> { + this.next().await } /// Get the next value produced by this stream. @@ -65,10 +67,10 @@ where } pub(crate) async fn resume_shared( - this: Shared>, + mut this: Mut>, value: Value, ) -> VmResult { - vm_try!(this.borrow_mut()).resume(value).await + this.resume(value).await } } @@ -91,3 +93,14 @@ where .finish() } } + +impl TryClone for Stream +where + T: TryClone + AsRef + AsMut, +{ + fn try_clone(&self) -> crate::alloc::Result { + Ok(Self { + execution: self.execution.try_clone()?, + }) + } +} diff --git a/crates/rune/src/runtime/tests.rs b/crates/rune/src/runtime/tests.rs index 964c92842..9910f7493 100644 --- a/crates/rune/src/runtime/tests.rs +++ b/crates/rune/src/runtime/tests.rs @@ -1,5 +1,5 @@ use crate as rune; -use crate::runtime::{AnyObj, Shared}; +use crate::runtime::{AnyObj, Shared, Value}; use crate::Any; use crate::support::Result; @@ -9,17 +9,17 @@ struct Foo(isize); #[test] fn test_take() -> Result<()> { - let thing = Shared::new(AnyObj::new(Foo(0))?)?; - let _ = thing.take().unwrap(); + let thing = Value::try_from(AnyObj::new(Foo(0))?)?; + let _ = thing.into_any_obj()?; Ok(()) } #[test] fn test_clone_take() -> Result<()> { - let thing = Shared::new(AnyObj::new(Foo(0))?)?; + let thing = Value::try_from(AnyObj::new(Foo(0))?)?; let thing2 = thing.clone(); - assert_eq!(Foo(0), thing2.take_downcast::()?); - assert!(thing.take().is_err()); + assert_eq!(Foo(0), thing2.into_any::()?); + assert!(thing.into_any_obj().is_err()); Ok(()) } @@ -31,14 +31,14 @@ fn test_from_ref() -> Result<()> { let value = Thing(10u32); unsafe { - let (shared, guard) = Shared::from_ref(&value)?; - assert!(shared.downcast_borrow_mut::().is_err()); - assert_eq!(10u32, shared.downcast_borrow_ref::()?.0); + let (value, guard) = Value::from_ref(&value)?; + assert!(value.clone().into_any_mut::().is_err()); + assert_eq!(10u32, value.clone().into_any_ref::()?.0); drop(guard); - assert!(shared.downcast_borrow_mut::().is_err()); - assert!(shared.downcast_borrow_ref::().is_err()); + assert!(value.clone().into_any_mut::().is_err()); + assert!(value.clone().into_any_ref::().is_err()); } Ok(()) @@ -52,17 +52,175 @@ fn test_from_mut() -> Result<()> { let mut value = Thing(10u32); unsafe { - let (shared, guard) = Shared::from_mut(&mut value)?; - shared.downcast_borrow_mut::()?.0 = 20; + let (value, guard) = Value::from_mut(&mut value)?; + value.clone().into_any_mut::()?.0 = 20; - assert_eq!(20u32, shared.downcast_borrow_mut::()?.0); - assert_eq!(20u32, shared.downcast_borrow_ref::()?.0); + assert_eq!(20u32, value.clone().into_any_mut::()?.0); + assert_eq!(20u32, value.clone().into_any_ref::()?.0); drop(guard); - assert!(shared.downcast_borrow_mut::().is_err()); - assert!(shared.downcast_borrow_ref::().is_err()); + assert!(value.clone().into_any_mut::().is_err()); + assert!(value.clone().into_any_ref::().is_err()); } Ok(()) } + +#[test] +fn shared_take() -> crate::support::Result<()> { + #[derive(Debug)] + struct Foo { + counter: isize, + } + + let a = Shared::new(Foo { counter: 0 })?; + let b = a.clone(); + + { + let mut a = a.borrow_mut()?; + // NB: this is prevented since we have a live reference. + assert!(b.take().is_err()); + a.counter += 1; + } + + let a = a.take()?; + assert_eq!(a.counter, 1); + Ok(()) +} + +#[test] +fn shared_borrow_ref() -> crate::support::Result<()> { + #[derive(Debug)] + struct Foo { + counter: isize, + } + + let a = Shared::new(Foo { counter: 0 })?; + + a.borrow_mut()?.counter += 1; + + { + let a_ref = a.borrow_ref()?; + assert_eq!(a_ref.counter, 1); + assert!(a.borrow_mut().is_err()); + assert!(a.borrow_ref().is_ok()); + } + + let mut a = a.borrow_mut()?; + a.counter += 1; + assert_eq!(a.counter, 2); + Ok(()) +} + +#[test] +fn shared_borrow_mut() -> crate::support::Result<()> { + #[derive(Debug)] + struct Foo { + counter: isize, + } + + let a = Shared::new(Foo { counter: 0 })?; + + { + let mut a_mut = a.borrow_mut()?; + a_mut.counter += 1; + assert_eq!(a_mut.counter, 1); + assert!(a.borrow_ref().is_err()); + } + + let a = a.borrow_ref()?; + assert_eq!(a.counter, 1); + Ok(()) +} + +#[test] +fn shared_into_ref() -> crate::support::Result<()> { + #[derive(Debug)] + struct Foo { + counter: isize, + } + + let a = Shared::new(Foo { counter: 0 })?; + let b = a.clone(); + + b.borrow_mut()?.counter += 1; + + { + // Consumes `a`. + let a = a.into_ref()?; + assert_eq!(a.counter, 1); + assert!(b.borrow_mut().is_err()); + } + + let mut b = b.borrow_mut()?; + b.counter += 1; + assert_eq!(b.counter, 2); + Ok(()) +} + +#[test] +fn shared_into_mut() -> crate::support::Result<()> { + #[derive(Debug)] + struct Foo { + counter: isize, + } + + let a = Shared::new(Foo { counter: 0 })?; + let b = a.clone(); + + { + // Consumes `a`. + let mut a = a.into_mut().unwrap(); + a.counter += 1; + + assert!(b.borrow_ref().is_err()); + } + + assert_eq!(b.borrow_ref().unwrap().counter, 1); + Ok(()) +} + +#[test] +fn shared_is_readable() -> crate::support::Result<()> { + let shared = Shared::new(1u32)?; + assert!(shared.is_readable()); + + { + let _guard = shared.borrow_ref()?; + assert!(shared.is_readable()); // Note: still readable. + } + + { + let _guard = shared.borrow_mut()?; + assert!(!shared.is_readable()); + } + + assert!(shared.is_readable()); + Ok(()) +} + +#[test] +fn shared_is_writable_take() -> crate::support::Result<()> { + let shared = Shared::new(1u32)?; + let shared2 = shared.clone(); + assert!(shared.is_readable()); + shared.take()?; + assert!(!shared2.is_readable()); + assert!(shared2.take().is_err()); + Ok(()) +} + +#[test] +fn shared_is_writable() -> crate::support::Result<()> { + let shared = Shared::new(1u32)?; + assert!(shared.is_writable()); + + { + let _guard = shared.borrow_ref()?; + assert!(!shared.is_writable()); + } + + assert!(shared.is_writable()); + Ok(()) +} diff --git a/crates/rune/src/runtime/to_value.rs b/crates/rune/src/runtime/to_value.rs index cf976e23e..e745f8c45 100644 --- a/crates/rune/src/runtime/to_value.rs +++ b/crates/rune/src/runtime/to_value.rs @@ -1,11 +1,8 @@ use core::any; -use core::cmp::Ordering; use crate::alloc::prelude::*; use crate::alloc::{self, HashMap}; -use crate::runtime::{ - AnyObj, Object, Shared, Value, VmError, VmErrorKind, VmIntegerRepr, VmResult, -}; +use crate::runtime::{AnyObj, Object, Value, VmError, VmErrorKind, VmIntegerRepr, VmResult}; use crate::Any; /// Derive macro for the [`ToValue`] trait for converting types into the dynamic @@ -161,10 +158,12 @@ where T: ToValue, { fn to_value(self) -> VmResult { - VmResult::Ok(Value::from(vm_try!(Shared::new(match self { + let option = match self { Some(some) => Some(vm_try!(some.to_value())), None => None, - })))) + }; + + VmResult::Ok(vm_try!(Value::try_from(option))) } } @@ -173,14 +172,14 @@ where impl ToValue for alloc::Box { fn to_value(self) -> VmResult { let this = alloc::String::from(self); - VmResult::Ok(Value::from(vm_try!(Shared::new(this)))) + VmResult::Ok(vm_try!(Value::try_from(this))) } } impl ToValue for &str { fn to_value(self) -> VmResult { let this = vm_try!(alloc::String::try_from(self)); - VmResult::Ok(Value::from(vm_try!(Shared::new(this)))) + VmResult::Ok(vm_try!(Value::try_from(this))) } } @@ -188,7 +187,7 @@ impl ToValue for &str { impl ToValue for ::rust_alloc::boxed::Box { fn to_value(self) -> VmResult { let this = vm_try!(self.try_to_string()); - VmResult::Ok(Value::from(vm_try!(Shared::new(this)))) + VmResult::Ok(vm_try!(Value::try_from(this))) } } @@ -196,7 +195,8 @@ impl ToValue for ::rust_alloc::boxed::Box { impl ToValue for ::rust_alloc::string::String { fn to_value(self) -> VmResult { let string = vm_try!(alloc::String::try_from(self)); - VmResult::Ok(Value::from(vm_try!(Shared::new(string)))) + let value = vm_try!(Value::try_from(string)); + VmResult::Ok(value) } } @@ -219,16 +219,12 @@ where E: ToValue, { fn to_value(self) -> VmResult { - VmResult::Ok(match self { - Ok(ok) => { - let ok = vm_try!(ok.to_value()); - Value::from(vm_try!(Shared::new(Ok(ok)))) - } - Err(err) => { - let err = vm_try!(err.to_value()); - Value::from(vm_try!(Shared::new(Err(err)))) - } - }) + let result = match self { + Ok(ok) => Ok(vm_try!(ok.to_value())), + Err(err) => Err(vm_try!(err.to_value())), + }; + + VmResult::Ok(vm_try!(Value::try_from(result))) } } @@ -238,8 +234,8 @@ macro_rules! number_value_trait { ($ty:ty) => { impl ToValue for $ty { fn to_value(self) -> VmResult { - match self.try_into() { - Ok(number) => VmResult::Ok(Value::Integer(number)), + match ::try_from(self) { + Ok(number) => VmResult::Ok(vm_try!(Value::try_from(number))), Err(..) => VmResult::err(VmErrorKind::IntegerToValueCoercionError { from: VmIntegerRepr::from(self), to: any::type_name::(), @@ -264,7 +260,7 @@ number_value_trait!(isize); impl ToValue for f32 { #[inline] fn to_value(self) -> VmResult { - VmResult::Ok(Value::Float(self as f64)) + VmResult::Ok(vm_try!(Value::try_from(self as f64))) } } @@ -284,7 +280,7 @@ macro_rules! impl_map { vm_try!(output.insert(key, vm_try!(value.to_value()))); } - VmResult::Ok(Value::from(vm_try!(Shared::new(output)))) + VmResult::Ok(vm_try!(Value::try_from(output))) } } }; @@ -297,10 +293,3 @@ cfg_std! { impl_map!(::std::collections::HashMap<::rust_alloc::string::String, T>); impl_map!(::std::collections::HashMap); } - -impl ToValue for Ordering { - #[inline] - fn to_value(self) -> VmResult { - VmResult::Ok(Value::Ordering(self)) - } -} diff --git a/crates/rune/src/runtime/tuple.rs b/crates/rune/src/runtime/tuple.rs index 20657e9b9..c2513de3d 100644 --- a/crates/rune/src/runtime/tuple.rs +++ b/crates/rune/src/runtime/tuple.rs @@ -7,7 +7,7 @@ use crate::alloc::clone::TryClone; use crate::alloc::{self, Box}; use crate::runtime::{ ConstValue, FromValue, Mut, RawMut, RawRef, Ref, ToValue, UnsafeToMut, UnsafeToRef, Value, - VmErrorKind, VmResult, + ValueKind, VmErrorKind, VmResult, }; #[cfg(feature = "alloc")] use crate::runtime::{Hasher, ProtocolCaller}; @@ -233,8 +233,8 @@ impl TryFrom> for OwnedTuple { let mut out = alloc::Vec::try_with_capacity(inner.len())?; - for value in alloc::Vec::from(inner) { - out.try_push(value.into_value()?)?; + for value in inner.iter() { + out.try_push(value.as_value()?)?; } Ok(Self { @@ -266,8 +266,8 @@ impl TryFrom<::rust_alloc::boxed::Box<[ConstValue]>> for OwnedTuple { let mut out = alloc::Vec::try_with_capacity(inner.len())?; - for value in inner.into_vec() { - out.try_push(value.into_value()?)?; + for value in inner.iter() { + out.try_push(value.as_value()?)?; } Ok(Self { @@ -278,10 +278,10 @@ impl TryFrom<::rust_alloc::boxed::Box<[ConstValue]>> for OwnedTuple { impl FromValue for OwnedTuple { fn from_value(value: Value) -> VmResult { - match value { - Value::EmptyTuple => VmResult::Ok(Self::new()), - Value::Tuple(tuple) => VmResult::Ok(vm_try!(tuple.take())), - actual => VmResult::err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + match vm_try!(value.take_kind()) { + ValueKind::EmptyTuple => VmResult::Ok(Self::new()), + ValueKind::Tuple(tuple) => VmResult::Ok(tuple), + actual => VmResult::err(VmErrorKind::expected::(actual.type_info())), } } } @@ -299,7 +299,7 @@ macro_rules! impl_tuple { impl ToValue for () { fn to_value(self) -> VmResult { - VmResult::Ok(Value::from(())) + VmResult::Ok(vm_try!(Value::empty())) } } }; @@ -312,7 +312,7 @@ macro_rules! impl_tuple { $($ty: FromValue,)* { fn from_value(value: Value) -> VmResult { - let tuple = vm_try!(vm_try!(value.into_tuple()).into_ref()); + let tuple = vm_try!(value.into_tuple_ref()); let [$($var,)*] = &tuple[..] else { return VmResult::err(VmErrorKind::ExpectedTupleLength { @@ -342,62 +342,50 @@ macro_rules! impl_tuple { repeat_macro!(impl_tuple); -impl FromValue for Mut { +impl FromValue for Ref { fn from_value(value: Value) -> VmResult { - match value { - Value::EmptyTuple => VmResult::Ok(Mut::from_static(Tuple::new_mut(&mut []))), - Value::Tuple(tuple) => { - let tuple = vm_try!(tuple.into_mut()); - let tuple = Mut::map(tuple, |this| &mut **this); - VmResult::Ok(tuple) - } - actual => VmResult::err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + let result = Ref::try_map(vm_try!(value.into_kind_ref()), |kind| match kind { + ValueKind::EmptyTuple => Some(Tuple::new(&[])), + ValueKind::Tuple(tuple) => Some(&**tuple), + _ => None, + }); + + match result { + Ok(tuple) => VmResult::Ok(tuple), + Err(actual) => VmResult::err(VmErrorKind::expected::(actual.type_info())), } } } -impl FromValue for Ref { +impl FromValue for Mut { fn from_value(value: Value) -> VmResult { - match value { - Value::EmptyTuple => VmResult::Ok(Ref::from_static(Tuple::new(&[]))), - Value::Tuple(tuple) => { - let tuple = vm_try!(tuple.into_ref()); - let tuple = Ref::map(tuple, |this| &**this); - VmResult::Ok(tuple) - } - actual => VmResult::err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + let result = Mut::try_map(vm_try!(value.into_kind_mut()), |kind| match kind { + ValueKind::EmptyTuple => Some(Tuple::new_mut(&mut [])), + ValueKind::Tuple(tuple) => Some(&mut **tuple), + _ => None, + }); + + match result { + Ok(tuple) => VmResult::Ok(tuple), + Err(actual) => VmResult::err(VmErrorKind::expected::(actual.type_info())), } } } impl UnsafeToRef for Tuple { - type Guard = Option; + type Guard = RawRef; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - match value { - Value::EmptyTuple => VmResult::Ok((Tuple::new(&[]), None)), - Value::Tuple(tuple) => { - let tuple = Ref::map(vm_try!(tuple.into_ref()), |tuple| &**tuple); - let (value, guard) = Ref::into_raw(tuple); - VmResult::Ok((value.as_ref(), Some(guard))) - } - actual => VmResult::err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } + let (value, guard) = Ref::into_raw(vm_try!(Ref::from_value(value))); + VmResult::Ok((value.as_ref(), guard)) } } impl UnsafeToMut for Tuple { - type Guard = Option; + type Guard = RawMut; unsafe fn unsafe_to_mut<'a>(value: Value) -> VmResult<(&'a mut Self, Self::Guard)> { - match value { - Value::EmptyTuple => VmResult::Ok((Tuple::new_mut(&mut []), None)), - Value::Tuple(tuple) => { - let tuple = Mut::map(vm_try!(tuple.into_mut()), |tuple| &mut **tuple); - let (mut value, guard) = Mut::into_raw(tuple); - VmResult::Ok((value.as_mut(), Some(guard))) - } - actual => VmResult::err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } + let (mut value, guard) = Mut::into_raw(vm_try!(Mut::from_value(value))); + VmResult::Ok((value.as_mut(), guard)) } } diff --git a/crates/rune/src/runtime/type_.rs b/crates/rune/src/runtime/type_.rs index 4bf2fda4d..e096297f6 100644 --- a/crates/rune/src/runtime/type_.rs +++ b/crates/rune/src/runtime/type_.rs @@ -33,7 +33,7 @@ impl InstallWith for Type {} impl FromValue for Type { #[inline] fn from_value(value: Value) -> VmResult { - VmResult::Ok(vm_try!(value.into_type())) + VmResult::Ok(vm_try!(value.as_type())) } } diff --git a/crates/rune/src/runtime/unit.rs b/crates/rune/src/runtime/unit.rs index 8aefaf7b3..aadd86c1d 100644 --- a/crates/rune/src/runtime/unit.rs +++ b/crates/rune/src/runtime/unit.rs @@ -23,9 +23,8 @@ use crate::runtime::{ }; use crate::Hash; -pub use self::storage::{ - ArrayUnit, BadInstruction, BadJump, EncodeError, UnitEncoder, UnitStorage, -}; +pub use self::storage::{ArrayUnit, EncodeError, UnitEncoder, UnitStorage}; +pub(crate) use self::storage::{BadInstruction, BadJump}; #[cfg(feature = "byte-code")] pub use self::byte_code::ByteCodeUnit; diff --git a/crates/rune/src/runtime/unit/storage.rs b/crates/rune/src/runtime/unit/storage.rs index 94bf2cd03..d0762d84f 100644 --- a/crates/rune/src/runtime/unit/storage.rs +++ b/crates/rune/src/runtime/unit/storage.rs @@ -48,24 +48,30 @@ pub trait UnitEncoder: self::sealed::Sealed { /// Instruction storage used by a [`Unit`][super::Unit]. pub trait UnitStorage: self::sealed::Sealed + fmt::Debug + Default { /// Iterator over instructions and their corresponding instruction offsets. + #[doc(hidden)] type Iter<'this>: Iterator where Self: 'this; /// Size of unit storage. This can be seen as the instruction pointer which /// is just beyond the last instruction. + #[doc(hidden)] fn end(&self) -> usize; /// Get the number of bytes which is used to store unit bytecode. + #[doc(hidden)] fn bytes(&self) -> usize; /// Iterate over all instructions. + #[doc(hidden)] fn iter(&self) -> Self::Iter<'_>; /// Get the instruction at the given instruction pointer. + #[doc(hidden)] fn get(&self, ip: usize) -> Result, BadInstruction>; /// Translate the given jump offset. + #[doc(hidden)] fn translate(&self, jump: usize) -> Result; } @@ -191,7 +197,7 @@ enum EncodeErrorKind { /// Error indicating that a bad instruction was located at the given instruction /// pointer. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct BadInstruction { pub(crate) ip: usize, } @@ -209,7 +215,7 @@ cfg_std! { /// Error indicating that a bad instruction was located at the given instruction /// pointer. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct BadJump { pub(crate) jump: usize, } diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 461369c19..667ae0267 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -5,21 +5,22 @@ use core::borrow::Borrow; use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use core::fmt; use core::hash; -use core::ptr; use ::rust_alloc::sync::Arc; +use crate as rune; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::alloc::{self, String}; use crate::compile::ItemBuf; use crate::runtime::vm::CallResult; use crate::runtime::{ - AccessKind, AnyObj, Bytes, ConstValue, ControlFlow, EnvProtocolCaller, Format, Formatter, - FromValue, FullTypeOf, Function, Future, Generator, GeneratorState, Iterator, MaybeTypeOf, Mut, - Object, OwnedTuple, Protocol, ProtocolCaller, Range, RangeFrom, RangeFull, RangeInclusive, - RangeTo, RangeToInclusive, RawMut, RawRef, Ref, Shared, Stream, ToValue, Type, TypeInfo, - Variant, Vec, Vm, VmError, VmErrorKind, VmIntegerRepr, VmResult, + AccessError, AccessErrorKind, AnyObj, AnyObjError, BorrowMut, BorrowRef, Bytes, ConstValue, + ControlFlow, EnvProtocolCaller, Format, Formatter, FromValue, FullTypeOf, Function, Future, + Generator, GeneratorState, Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, Protocol, + ProtocolCaller, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Ref, + RuntimeError, Shared, SharedPointerGuard, Snapshot, Stream, ToValue, Type, TypeInfo, Variant, + Vec, Vm, VmErrorKind, VmIntegerRepr, VmResult, }; #[cfg(feature = "alloc")] use crate::runtime::{Hasher, Tuple}; @@ -27,6 +28,196 @@ use crate::{Any, Hash}; use ::serde::{Deserialize, Serialize}; +/// Macro used to generate coersions for [`Value`]. +macro_rules! into_base { + ( + $(#[$($meta:meta)*])* + $kind:ident($ty:ty), + $into_ref:ident, + $into_mut:ident, + $borrow_ref:ident, + $borrow_mut:ident, + ) => { + $(#[$($meta)*])* + /// + /// This ensures that the value has read access to the underlying value + /// and does not consume it. + #[inline] + pub fn $into_ref(self) -> Result, RuntimeError> { + let result = Ref::try_map(self.into_kind_ref()?, |kind| match kind { + ValueKind::$kind(bytes) => Some(bytes), + _ => None, + }); + + match result { + Ok(bytes) => Ok(bytes), + Err(actual) => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + + $(#[$($meta)*])* + /// + /// This ensures that the value has write access to the underlying value + /// and does not consume it. + #[inline] + pub fn $into_mut(self) -> Result, RuntimeError> { + let result = Mut::try_map(self.into_kind_mut()?, |kind| match kind { + ValueKind::$kind(bytes) => Some(bytes), + _ => None, + }); + + match result { + Ok(bytes) => Ok(bytes), + Err(actual) => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + + $(#[$($meta)*])* + /// + /// This ensures that the value has read access to the underlying value + /// and does not consume it. + #[inline] + pub fn $borrow_ref(&self) -> Result, RuntimeError> { + let result = BorrowRef::try_map(self.borrow_kind_ref()?, |kind| match kind { + ValueKind::$kind(bytes) => Some(bytes), + _ => None, + }); + + match result { + Ok(bytes) => Ok(bytes), + Err(actual) => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + + $(#[$($meta)*])* + /// + /// This ensures that the value has write access to the underlying value + /// and does not consume it. + #[inline] + pub fn $borrow_mut(&self) -> Result, RuntimeError> { + let result = BorrowMut::try_map(self.borrow_kind_mut()?, |kind| match kind { + ValueKind::$kind(bytes) => Some(bytes), + _ => None, + }); + + match result { + Ok(bytes) => Ok(bytes), + Err(actual) => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + } +} + +macro_rules! into { + ( + $(#[$($meta:meta)*])* + $kind:ident($ty:ty), + $into_ref:ident, + $into_mut:ident, + $borrow_ref:ident, + $borrow_mut:ident, + $into:ident, + ) => { + into_base! { + $(#[$($meta)*])* + $kind($ty), + $into_ref, + $into_mut, + $borrow_ref, + $borrow_mut, + } + + $(#[$($meta)*])* + /// + /// This consumes the underlying value. + #[inline] + pub fn $into(self) -> Result<$ty, RuntimeError> { + match self.take_kind()? { + ValueKind::$kind(value) => Ok(value), + actual => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + } +} + +macro_rules! copy_into { + ( + $(#[$($meta:meta)*])* + $kind:ident($ty:ty), + $into_ref:ident, + $into_mut:ident, + $borrow_ref:ident, + $borrow_mut:ident, + $as:ident, + ) => { + into_base! { + $(#[$($meta)*])* + $kind($ty), + $into_ref, + $into_mut, + $borrow_ref, + $borrow_mut, + } + + $(#[$($meta)*])* + /// + /// This copied the underlying value. + #[inline] + pub fn $as(&self) -> Result<$ty, RuntimeError> { + match *self.borrow_kind_ref()? { + ValueKind::$kind(value) => Ok(value), + ref actual => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + } +} + +macro_rules! clone_into { + ( + $(#[$($meta:meta)*])* + $kind:ident($ty:ty), + $into_ref:ident, + $into_mut:ident, + $borrow_ref:ident, + $borrow_mut:ident, + $as:ident, + ) => { + into_base! { + $(#[$($meta)*])* + $kind($ty), + $into_ref, + $into_mut, + $borrow_ref, + $borrow_mut, + } + + $(#[$($meta)*])* + /// + /// This clones the underlying value. + #[inline] + pub fn $as(&self) -> Result<$ty, RuntimeError> { + match &*self.borrow_kind_ref()? { + ValueKind::$kind(value) => Ok(value.clone()), + actual => { + Err(RuntimeError::expected::<$ty>(actual.type_info())) + } + } + } + } +} + // Small helper function to build errors. fn err(error: E) -> VmResult where @@ -36,6 +227,8 @@ where } /// A empty with a well-defined type. +#[derive(TryClone)] +#[try_clone(crate)] pub struct EmptyStruct { /// The type hash of the empty. pub(crate) rtti: Arc, @@ -60,6 +253,7 @@ impl fmt::Debug for EmptyStruct { } /// A tuple with a well-defined type. +#[derive(TryClone)] pub struct TupleStruct { /// The type hash of the tuple. pub(crate) rtti: Arc, @@ -106,6 +300,7 @@ impl fmt::Debug for TupleStruct { } /// An object with a well-defined type. +#[derive(TryClone)] pub struct Struct { /// The type hash of the object. pub(crate) rtti: Arc, @@ -241,78 +436,176 @@ impl Ord for Rtti { /// An entry on the stack. #[derive(Clone)] -pub enum Value { - /// A boolean. - Bool(bool), - /// A single byte. - Byte(u8), - /// A character. - Char(char), - /// A number. - Integer(i64), - /// A float. - Float(f64), - /// A type hash. Describes a type in the virtual machine. - Type(Type), - /// Ordering. - Ordering(Ordering), - /// A UTF-8 string. - String(Shared), - /// A byte string. - Bytes(Shared), - /// A vector containing any values. - Vec(Shared), - /// The unit value. - EmptyTuple, - /// A tuple. - Tuple(Shared), - /// An object. - Object(Shared), - /// A range `start..` - RangeFrom(Shared), - /// A full range `..` - RangeFull(Shared), - /// A full range `start..=end` - RangeInclusive(Shared), - /// A full range `..=end` - RangeToInclusive(Shared), - /// A full range `..end` - RangeTo(Shared), - /// A range `start..end`. - Range(Shared), - /// A control flow indicator. - ControlFlow(Shared), - /// A stored future. - Future(Shared), - /// A Stream. - Stream(Shared>), - /// A stored generator. - Generator(Shared>), - /// Generator state. - GeneratorState(Shared), - /// An empty value indicating nothing. - Option(Shared>), - /// A stored result in a slot. - Result(Shared>), - /// An struct with a well-defined type. - EmptyStruct(Shared), - /// A tuple with a well-defined type. - TupleStruct(Shared), - /// An struct with a well-defined type. - Struct(Shared), - /// The variant of an enum. - Variant(Shared), - /// A stored function pointer. - Function(Shared), - /// A value being formatted. - Format(Shared), - /// An iterator. - Iterator(Shared), - /// An opaque value that can be downcasted. - Any(Shared), +pub struct Value { + inner: Shared, } impl Value { + /// Construct an Any that wraps a pointer. + /// + /// # Safety + /// + /// Caller must ensure that the returned `Value` doesn't outlive the + /// reference it is wrapping. + /// + /// This would be an example of incorrect use: + /// + /// ```no_run + /// use rune::Any; + /// use rune::runtime::Value; + /// + /// #[derive(Any)] + /// struct Foo(u32); + /// + /// let mut v = Foo(1u32); + /// + /// unsafe { + /// let (any, guard) = unsafe { Value::from_ref(&v)? }; + /// drop(v); + /// // any use of `any` beyond here is undefined behavior. + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` + /// + /// # Examples + /// + /// ``` + /// use rune::Any; + /// use rune::runtime::Value; + /// + /// #[derive(Any)] + /// struct Foo(u32); + /// + /// let mut v = Foo(1u32); + /// + /// unsafe { + /// let (any, guard) = Value::from_ref(&mut v)?; + /// let b = any.into_any_ref::().unwrap(); + /// assert_eq!(b.0, 1u32); + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub unsafe fn from_ref(data: &T) -> alloc::Result<(Self, SharedPointerGuard)> + where + T: Any, + { + let value = Shared::new(ValueKind::Any(AnyObj::from_ref(data)))?; + let (inner, guard) = Shared::into_drop_guard(value); + Ok((Self { inner }, guard)) + } + + /// Construct a value that wraps a mutable pointer. + /// + /// # Safety + /// + /// Caller must ensure that the returned `Value` doesn't outlive the + /// reference it is wrapping. + /// + /// This would be an example of incorrect use: + /// + /// ```no_run + /// use rune::Any; + /// use rune::runtime::Value; + /// + /// #[derive(Any)] + /// struct Foo(u32); + /// + /// let mut v = Foo(1u32); + /// unsafe { + /// let (any, guard) = Value::from_mut(&mut v)?; + /// drop(v); + /// // any use of value beyond here is undefined behavior. + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` + /// + /// # Examples + /// + /// ``` + /// use rune::Any; + /// use rune::runtime::{Value, VmResult}; + /// + /// #[derive(Any)] + /// struct Foo(u32); + /// + /// let mut v = Foo(1u32); + /// + /// unsafe { + /// let (mut any, guard) = Value::from_mut(&mut v)?; + /// + /// if let Ok(mut v) = any.into_any_mut::() { + /// v.0 += 1; + /// } + /// } + /// + /// assert_eq!(v.0, 2); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub unsafe fn from_mut(data: &mut T) -> alloc::Result<(Self, SharedPointerGuard)> + where + T: Any, + { + let obj = AnyObj::from_mut(data); + let value = Shared::new(ValueKind::Any(obj))?; + let (inner, guard) = Shared::into_drop_guard(value); + Ok((Self { inner }, guard)) + } + + /// Test if the value is writable. + pub fn is_writable(&self) -> bool { + self.inner.is_writable() + } + + /// Test if the value is readable. + pub fn is_readable(&self) -> bool { + self.inner.is_readable() + } + + /// Get snapshot of value. + /// + /// The snapshot details how the value is currently being access. + #[allow(unused)] + pub fn snapshot(&self) -> Snapshot { + self.inner.snapshot() + } + + /// Construct an empty value. + pub(crate) fn empty() -> alloc::Result { + Ok(Self { + inner: Shared::new(ValueKind::EmptyTuple)?, + }) + } + + /// Test if the value is empty. + pub(crate) fn is_empty(&self) -> Result { + Ok(matches!(&*self.inner.borrow_ref()?, ValueKind::EmptyTuple)) + } + + /// Take the kind of the value. + pub(crate) fn take_kind(self) -> Result { + self.inner.take() + } + + /// Borrow the kind of the value as a mutable reference. + pub(crate) fn borrow_kind_mut(&self) -> Result, AccessError> { + self.inner.borrow_mut() + } + + /// Take the kind of the value as an owned mutable reference. + pub(crate) fn into_kind_mut(self) -> Result, AccessError> { + self.inner.into_mut() + } + + /// Borrow the kind of the value as a reference. + pub(crate) fn borrow_kind_ref(&self) -> Result, AccessError> { + self.inner.borrow_ref() + } + + /// Take the kind of the value as an owned reference. + pub(crate) fn into_kind_ref(self) -> Result, AccessError> { + self.inner.into_ref() + } + /// Format the value using the [Protocol::STRING_DISPLAY] protocol. /// /// Requires a work buffer `buf` which will be used in case the value @@ -335,38 +628,34 @@ impl Value { f: &mut Formatter, caller: &mut impl ProtocolCaller, ) -> VmResult<()> { - match self { - Value::Format(format) => { - let format = vm_try!(format.borrow_ref()); - vm_try!(format.spec.format(&format.value, f, caller)); - } - Value::Char(c) => { + match &*vm_try!(self.borrow_kind_ref()) { + ValueKind::Char(c) => { vm_try!(f.push(*c)); } - Value::String(string) => { - vm_try!(f.push_str(&vm_try!(string.borrow_ref()))); + ValueKind::Format(format) => { + vm_try!(format.spec.format(&format.value, f, caller)); } - Value::Integer(integer) => { + ValueKind::Integer(integer) => { let mut buffer = itoa::Buffer::new(); vm_try!(f.push_str(buffer.format(*integer))); } - Value::Float(float) => { + ValueKind::Float(float) => { let mut buffer = ryu::Buffer::new(); vm_try!(f.push_str(buffer.format(*float))); } - Value::Bool(bool) => { - return VmResult::Ok(vm_write!(f, "{}", bool)); + ValueKind::Bool(bool) => { + vm_write!(f, "{bool}"); } - Value::Byte(byte) => { + ValueKind::Byte(byte) => { let mut buffer = itoa::Buffer::new(); vm_try!(f.push_str(buffer.format(*byte))); } - value => { - let result = vm_try!(caller.call_protocol_fn( - Protocol::STRING_DISPLAY, - value.clone(), - (f,), - )); + ValueKind::String(string) => { + vm_try!(f.push_str(string)); + } + _ => { + let result = + vm_try!(caller.call_protocol_fn(Protocol::STRING_DISPLAY, self.clone(), (f,),)); return VmResult::Ok(vm_try!(<()>::from_value(result))); } @@ -375,6 +664,75 @@ impl Value { VmResult::Ok(()) } + /// Perform a shallow clone of the value using the [`CLONE`] protocol. + /// + /// This requires read access to the underlying value. + /// + /// You must use [Vm::with] to specify which virtual machine this function + /// is called inside. + /// + /// # Panics + /// + /// This function will panic if called outside of a virtual machine. + /// + /// [`CLONE`]: Protocol::CLONE + pub fn clone_(&self) -> VmResult { + self.clone_with(&mut EnvProtocolCaller) + } + + pub(crate) fn clone_with(&self, caller: &mut impl ProtocolCaller) -> VmResult { + let inner = match &*vm_try!(self.inner.borrow_ref()) { + ValueKind::EmptyTuple => ValueKind::EmptyTuple, + ValueKind::Bool(value) => ValueKind::Bool(*value), + ValueKind::Byte(value) => ValueKind::Byte(*value), + ValueKind::Char(value) => ValueKind::Char(*value), + ValueKind::Integer(value) => ValueKind::Integer(*value), + ValueKind::Float(value) => ValueKind::Float(*value), + ValueKind::Type(value) => ValueKind::Type(*value), + ValueKind::Ordering(value) => ValueKind::Ordering(*value), + ValueKind::String(value) => ValueKind::String(vm_try!(value.try_clone())), + ValueKind::Bytes(value) => ValueKind::Bytes(vm_try!(value.try_clone())), + ValueKind::Vec(value) => ValueKind::Vec(vm_try!(value.try_clone())), + ValueKind::Tuple(value) => ValueKind::Tuple(vm_try!(value.try_clone())), + ValueKind::Object(value) => ValueKind::Object(vm_try!(value.try_clone())), + ValueKind::RangeFrom(value) => ValueKind::RangeFrom(vm_try!(value.try_clone())), + ValueKind::RangeFull(value) => ValueKind::RangeFull(vm_try!(value.try_clone())), + ValueKind::RangeInclusive(value) => { + ValueKind::RangeInclusive(vm_try!(value.try_clone())) + } + ValueKind::RangeToInclusive(value) => { + ValueKind::RangeToInclusive(vm_try!(value.try_clone())) + } + ValueKind::RangeTo(value) => ValueKind::RangeTo(vm_try!(value.try_clone())), + ValueKind::Range(value) => ValueKind::Range(vm_try!(value.try_clone())), + ValueKind::ControlFlow(value) => ValueKind::ControlFlow(vm_try!(value.try_clone())), + ValueKind::Stream(value) => ValueKind::Stream(vm_try!(value.try_clone())), + ValueKind::Generator(value) => ValueKind::Generator(vm_try!(value.try_clone())), + ValueKind::GeneratorState(value) => { + ValueKind::GeneratorState(vm_try!(value.try_clone())) + } + ValueKind::Option(value) => ValueKind::Option(vm_try!(value.try_clone())), + ValueKind::Result(value) => ValueKind::Result(vm_try!(value.try_clone())), + ValueKind::EmptyStruct(value) => ValueKind::EmptyStruct(vm_try!(value.try_clone())), + ValueKind::TupleStruct(value) => ValueKind::TupleStruct(vm_try!(value.try_clone())), + ValueKind::Struct(value) => ValueKind::Struct(vm_try!(value.try_clone())), + ValueKind::Variant(value) => ValueKind::Variant(vm_try!(value.try_clone())), + ValueKind::Function(value) => ValueKind::Function(vm_try!(value.try_clone())), + ValueKind::Format(value) => ValueKind::Format(vm_try!(value.try_clone())), + _ => { + return VmResult::Ok(vm_try!(caller.call_protocol_fn( + Protocol::CLONE, + self.clone(), + () + ))); + } + }; + + VmResult::Ok(Self { + inner: vm_try!(Shared::new(inner)), + }) + } + /// Debug format the value using the [`STRING_DEBUG`] protocol. /// /// You must use [Vm::with] to specify which virtual machine this function @@ -395,108 +753,106 @@ impl Value { f: &mut Formatter, caller: &mut impl ProtocolCaller, ) -> VmResult<()> { - match self { - Value::Bool(value) => { - vm_write!(f, "{:?}", value); + match &*vm_try!(self.inner.borrow_ref()) { + ValueKind::EmptyTuple => { + vm_write!(f, "()"); } - Value::Byte(value) => { + ValueKind::Bool(value) => { vm_write!(f, "{:?}", value); } - Value::Char(value) => { + ValueKind::Byte(value) => { vm_write!(f, "{:?}", value); } - Value::Integer(value) => { + ValueKind::Char(value) => { vm_write!(f, "{:?}", value); } - Value::Float(value) => { + ValueKind::Integer(value) => { vm_write!(f, "{:?}", value); } - Value::Type(value) => { + ValueKind::Float(value) => { vm_write!(f, "{:?}", value); } - Value::String(value) => { + ValueKind::Type(value) => { vm_write!(f, "{:?}", value); } - Value::Bytes(value) => { + ValueKind::String(value) => { vm_write!(f, "{:?}", value); } - Value::Vec(value) => { - let value = vm_try!(value.borrow_ref()); - vm_try!(Vec::string_debug_with(&value, f, caller)); + ValueKind::Bytes(value) => { + vm_write!(f, "{:?}", value); } - Value::EmptyTuple => { - vm_write!(f, "()"); + ValueKind::Vec(value) => { + vm_try!(Vec::string_debug_with(value, f, caller)); } - Value::Tuple(value) => { + ValueKind::Tuple(value) => { vm_write!(f, "{:?}", value); } - Value::Object(value) => { + ValueKind::Object(value) => { vm_write!(f, "{:?}", value); } - Value::RangeFrom(value) => { + ValueKind::RangeFrom(value) => { vm_write!(f, "{:?}", value); } - Value::RangeFull(value) => { + ValueKind::RangeFull(value) => { vm_write!(f, "{:?}", value); } - Value::RangeInclusive(value) => { + ValueKind::RangeInclusive(value) => { vm_write!(f, "{:?}", value); } - Value::RangeToInclusive(value) => { + ValueKind::RangeToInclusive(value) => { vm_write!(f, "{:?}", value); } - Value::RangeTo(value) => { + ValueKind::RangeTo(value) => { vm_write!(f, "{:?}", value); } - Value::Range(value) => { + ValueKind::Range(value) => { vm_write!(f, "{:?}", value); } - Value::ControlFlow(value) => { - let value = vm_try!(value.borrow_ref()); - vm_try!(ControlFlow::string_debug_with(&value, f, caller)); + ValueKind::ControlFlow(value) => { + vm_try!(ControlFlow::string_debug_with(value, f, caller)); } - Value::Future(value) => { + ValueKind::Future(value) => { vm_write!(f, "{:?}", value); } - Value::Stream(value) => { + ValueKind::Stream(value) => { vm_write!(f, "{:?}", value); } - Value::Generator(value) => { + ValueKind::Generator(value) => { vm_write!(f, "{:?}", value); } - Value::GeneratorState(value) => { + ValueKind::GeneratorState(value) => { vm_write!(f, "{:?}", value); } - Value::Option(value) => { + ValueKind::Option(value) => { vm_write!(f, "{:?}", value); } - Value::Result(value) => { + ValueKind::Result(value) => { vm_write!(f, "{:?}", value); } - Value::EmptyStruct(value) => { + ValueKind::EmptyStruct(value) => { vm_write!(f, "{:?}", value); } - Value::TupleStruct(value) => { + ValueKind::TupleStruct(value) => { vm_write!(f, "{:?}", value); } - Value::Struct(value) => { + ValueKind::Struct(value) => { vm_write!(f, "{:?}", value); } - Value::Variant(value) => { + ValueKind::Variant(value) => { vm_write!(f, "{:?}", value); } - Value::Function(value) => { + ValueKind::Function(value) => { vm_write!(f, "{:?}", value); } - Value::Format(value) => { + ValueKind::Format(value) => { vm_write!(f, "{:?}", value); } - Value::Iterator(value) => { + ValueKind::Iterator(value) => { vm_write!(f, "{:?}", value); } - value => { + _ => { let result = - vm_try!(caller.call_protocol_fn(Protocol::STRING_DEBUG, value.clone(), (f,),)); + vm_try!(caller.call_protocol_fn(Protocol::STRING_DEBUG, self.clone(), (f,))); vm_try!(<()>::from_value(result)); return VmResult::Ok(()); @@ -520,45 +876,10 @@ impl Value { } pub(crate) fn into_iter_with(self, caller: &mut impl ProtocolCaller) -> VmResult { - let target = match self { - Value::Iterator(iterator) => return VmResult::Ok(vm_try!(iterator.take())), - Value::Vec(vec) => { - return VmResult::Ok(Vec::iter_ref(Ref::map(vm_try!(vec.into_ref()), |vec| { - &**vec - }))) - } - Value::Object(object) => { - return VmResult::Ok(Object::rune_iter(vm_try!(object.into_ref()))) - } - target => target, - }; - - let value = vm_try!(caller.call_protocol_fn(Protocol::INTO_ITER, target, ())); + let value = vm_try!(caller.call_protocol_fn(Protocol::INTO_ITER, self, ())); Iterator::from_value(value) } - /// Coerce into a future, or convert into a future using the - /// [Protocol::INTO_FUTURE] protocol. - /// - /// You must use [Vm::with] to specify which virtual machine this function - /// is called inside. - /// - /// # Errors - /// - /// This function errors in case the provided type cannot be converted into - /// a future without the use of a [`Vm`] and one is not provided through the - /// environment. - #[inline] - pub fn into_future(self) -> VmResult> { - let target = match self { - Value::Future(future) => return VmResult::Ok(future), - target => target, - }; - - let value = vm_try!(EnvProtocolCaller.call_protocol_fn(Protocol::INTO_FUTURE, target, ())); - VmResult::Ok(vm_try!(Shared::new(vm_try!(Future::from_value(value))))) - } - /// Retrieves a human readable type name for the current value. /// /// You must use [Vm::with] to specify which virtual machine this function @@ -597,521 +918,493 @@ impl Value { /// Construct a vector. pub fn vec(vec: alloc::Vec) -> VmResult { - VmResult::Ok(Self::Vec(vm_try!(Shared::new(Vec::from(vec))))) + let data = Vec::from(vec); + + VmResult::Ok(vm_try!(Value::try_from(data))) } /// Construct a tuple. pub fn tuple(vec: alloc::Vec) -> VmResult { - VmResult::Ok(Self::Tuple(vm_try!(Shared::new(vm_try!( - OwnedTuple::try_from(vec) - ))))) + let data = vm_try!(OwnedTuple::try_from(vec)); + + VmResult::Ok(vm_try!(Value::try_from(data))) } /// Construct an empty. pub fn empty_struct(rtti: Arc) -> VmResult { - VmResult::Ok(Self::EmptyStruct(vm_try!(Shared::new(EmptyStruct { - rtti - })))) + VmResult::Ok(vm_try!(Value::try_from(EmptyStruct { rtti }))) } /// Construct a typed tuple. pub fn tuple_struct(rtti: Arc, vec: alloc::Vec) -> VmResult { - VmResult::Ok(Self::TupleStruct(vm_try!(Shared::new(TupleStruct { - rtti, - data: vm_try!(OwnedTuple::try_from(vec)), - })))) + let data = vm_try!(OwnedTuple::try_from(vec)); + + VmResult::Ok(vm_try!(Value::try_from(TupleStruct { rtti, data }))) } /// Construct an empty variant. pub fn unit_variant(rtti: Arc) -> VmResult { - VmResult::Ok(Self::Variant(vm_try!(Shared::new(Variant::unit(rtti))))) + VmResult::Ok(vm_try!(Value::try_from(Variant::unit(rtti)))) } /// Construct a tuple variant. pub fn tuple_variant(rtti: Arc, vec: alloc::Vec) -> VmResult { - VmResult::Ok(Self::Variant(vm_try!(Shared::new(Variant::tuple( - rtti, - vm_try!(OwnedTuple::try_from(vec)) - ))))) - } - - /// Take the interior value. - pub fn take(self) -> VmResult { - VmResult::Ok(match self { - Self::Bool(value) => Self::Bool(value), - Self::Byte(value) => Self::Byte(value), - Self::Char(value) => Self::Char(value), - Self::Integer(value) => Self::Integer(value), - Self::Float(value) => Self::Float(value), - Self::Type(value) => Self::Type(value), - Self::Ordering(value) => Self::Ordering(value), - Self::String(value) => Self::String(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Bytes(value) => Self::Bytes(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Vec(value) => Self::Vec(vm_try!(Shared::new(vm_try!(value.take())))), - Self::EmptyTuple => Self::EmptyTuple, - Self::Tuple(value) => Self::Tuple(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Object(value) => Self::Object(vm_try!(Shared::new(vm_try!(value.take())))), - Self::RangeFrom(value) => Self::RangeFrom(vm_try!(Shared::new(vm_try!(value.take())))), - Self::RangeFull(value) => Self::RangeFull(vm_try!(Shared::new(vm_try!(value.take())))), - Self::RangeInclusive(value) => { - Self::RangeInclusive(vm_try!(Shared::new(vm_try!(value.take())))) - } - Self::RangeToInclusive(value) => { - Self::RangeToInclusive(vm_try!(Shared::new(vm_try!(value.take())))) - } - Self::RangeTo(value) => Self::RangeTo(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Range(value) => Self::Range(vm_try!(Shared::new(vm_try!(value.take())))), - Self::ControlFlow(value) => { - Self::ControlFlow(vm_try!(Shared::new(vm_try!(value.take())))) - } - Self::Future(value) => Self::Future(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Stream(value) => Self::Stream(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Generator(value) => Self::Generator(vm_try!(Shared::new(vm_try!(value.take())))), - Self::GeneratorState(value) => { - Self::GeneratorState(vm_try!(Shared::new(vm_try!(value.take())))) - } - Self::Option(value) => Self::Option(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Result(value) => Self::Result(vm_try!(Shared::new(vm_try!(value.take())))), - Self::EmptyStruct(value) => { - Self::EmptyStruct(vm_try!(Shared::new(vm_try!(value.take())))) - } - Self::TupleStruct(value) => { - Self::TupleStruct(vm_try!(Shared::new(vm_try!(value.take())))) - } - Self::Struct(value) => Self::Struct(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Variant(value) => Self::Variant(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Function(value) => Self::Function(vm_try!(Shared::new(vm_try!(value.take())))), - Self::Format(value) => Self::Format(value), - Self::Iterator(value) => Self::Iterator(value), - Self::Any(value) => Self::Any(vm_try!(Shared::new(vm_try!(value.take())))), - }) + let data = vm_try!(OwnedTuple::try_from(vec)); + + VmResult::Ok(vm_try!(Value::try_from(Variant::tuple(rtti, data)))) } - /// Try to coerce value into a unit. - #[inline] - pub fn into_unit(self) -> VmResult<()> { - match self { - Value::EmptyTuple => VmResult::Ok(()), - actual => err(VmErrorKind::expected::<()>(vm_try!(actual.type_info()))), - } + /// Drop the interior value. + pub(crate) fn drop(self) -> VmResult<()> { + drop(vm_try!(self.inner.take())); + VmResult::Ok(()) } - /// Try to coerce value into a boolean. - #[inline] - pub fn as_bool(&self) -> VmResult { - match self { - Self::Bool(b) => VmResult::Ok(*b), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } + /// Move the interior value. + pub(crate) fn move_(self) -> VmResult { + let inner = vm_try!(self.inner.take()); + + VmResult::Ok(Value { + inner: vm_try!(Shared::new(inner)), + }) } - /// Try to coerce value into a boolean. + /// Try to coerce value into a usize. #[inline] - pub fn into_bool(self) -> VmResult { - match self { - Self::Bool(b) => VmResult::Ok(b), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } + pub fn as_usize(&self) -> Result { + self.try_as_integer() } - /// Try to coerce value into a byte. + /// Get the value as a string. #[inline] - pub fn as_byte(&self) -> VmResult { - match self { - Self::Byte(b) => VmResult::Ok(*b), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn as_string(&self) -> Result, RuntimeError> { + let result = BorrowRef::try_map(self.inner.borrow_ref()?, |kind| match kind { + ValueKind::String(string) => Some(string.as_str()), + _ => None, + }); + + match result { + Ok(s) => Ok(s), + Err(actual) => Err(RuntimeError::expected::(actual.type_info())), } } - /// Try to coerce value into a byte. + /// Take the current value as a string. #[inline] - pub fn into_byte(self) -> VmResult { - match self { - Self::Byte(b) => VmResult::Ok(b), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn into_string(self) -> Result { + match self.inner.take()? { + ValueKind::String(string) => Ok(string), + actual => Err(RuntimeError::expected::(actual.type_info())), } } - /// Try to coerce value into a character. + /// Coerce into type value. + #[doc(hidden)] #[inline] - pub fn as_char(&self) -> VmResult { - match self { - Self::Char(c) => VmResult::Ok(*c), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn into_type_value(self) -> Result { + match self.inner.take()? { + ValueKind::EmptyTuple => Ok(TypeValue::EmptyTuple), + ValueKind::Tuple(tuple) => Ok(TypeValue::Tuple(tuple)), + ValueKind::Object(object) => Ok(TypeValue::Object(object)), + ValueKind::EmptyStruct(empty) => Ok(TypeValue::EmptyStruct(empty)), + ValueKind::TupleStruct(tuple) => Ok(TypeValue::TupleStruct(tuple)), + ValueKind::Struct(object) => Ok(TypeValue::Struct(object)), + ValueKind::Variant(object) => Ok(TypeValue::Variant(object)), + kind => Ok(TypeValue::NotTyped(NotTypedValueKind(kind))), } } - /// Try to coerce value into a character. + /// Coerce into a unit. #[inline] - pub fn into_char(self) -> VmResult { - match self { - Self::Char(c) => VmResult::Ok(c), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn into_unit(&self) -> Result<(), RuntimeError> { + match *self.inner.borrow_ref()? { + ValueKind::EmptyTuple => Ok(()), + ref actual => Err(RuntimeError::expected::<()>(actual.type_info())), } } - /// Try to coerce value into an integer. + copy_into! { + /// Coerce into [`Ordering`]. + Ordering(Ordering), + into_ordering_ref, + into_ordering_mut, + borrow_ordering_ref, + borrow_ordering_mut, + as_ordering, + } + + copy_into! { + /// Coerce into [`bool`]. + Bool(bool), + into_bool_ref, + into_bool_mut, + borrow_bool_ref, + borrow_bool_mut, + as_bool, + } + + copy_into! { + /// Coerce into [`u8`] byte. + Byte(u8), + into_byte_ref, + into_byte_mut, + borrow_byte_ref, + borrow_byte_mut, + as_byte, + } + + copy_into! { + /// Coerce into [`char`]. + Char(char), + into_char_ref, + into_char_mut, + borrow_char_ref, + borrow_char_mut, + as_char, + } + + copy_into! { + /// Coerce into [`i64`] integer. + Integer(i64), + into_integer_ref, + into_integer_mut, + borrow_integer_ref, + borrow_integer_mut, + as_integer, + } + + copy_into! { + /// Coerce into [`f64`] float. + Float(f64), + into_float_ref, + into_float_mut, + borrow_float_ref, + borrow_float_mut, + as_float, + } + + copy_into! { + /// Coerce into [`Type`]. + Type(Type), + into_type_ref, + into_type_mut, + borrow_type_ref, + borrow_type_mut, + as_type, + } + + clone_into! { + /// Coerce into [`Option`]. + Option(Option), + into_option_ref, + into_option_mut, + borrow_option_ref, + borrow_option_mut, + as_option, + } + + clone_into! { + /// Coerce into [`Result`]. + Result(Result), + into_result_ref, + into_result_mut, + borrow_result_ref, + borrow_result_mut, + as_result, + } + + into! { + /// Coerce into [`Vec`]. + Vec(Vec), + into_vec_ref, + into_vec_mut, + borrow_vec_ref, + borrow_vec_mut, + into_vec, + } + + into! { + /// Coerce into [`Bytes`]. + Bytes(Bytes), + into_bytes_ref, + into_bytes_mut, + borrow_bytes_ref, + borrow_bytes_mut, + into_bytes, + } + + into! { + /// Coerce into a [`ControlFlow`]. + ControlFlow(ControlFlow), + into_control_flow_ref, + into_control_flow_mut, + borrow_control_flow_ref, + borrow_control_flow_mut, + into_control_flow, + } + + into! { + /// Coerce into a [`Function`]. + Function(Function), + into_function_ref, + into_function_mut, + borrow_function_ref, + borrow_function_mut, + into_function, + } + + into! { + /// Coerce into a [`GeneratorState`]. + GeneratorState(GeneratorState), + into_generator_state_ref, + into_generator_state_mut, + borrow_generator_state_ref, + borrow_generator_state_mut, + into_generator_state, + } + + into! { + /// Coerce into a [`Generator`]. + Generator(Generator), + into_generator_ref, + into_generator_mut, + borrow_generator_ref, + borrow_generator_mut, + into_generator, + } + + into! { + /// Coerce into a [`Iterator`]. + Iterator(Iterator), + into_iterator_ref, + into_iterator_mut, + borrow_iterator_ref, + borrow_iterator_mut, + into_iterator, + } + + into! { + /// Coerce into a [`Format`]. + Format(Format), + into_format_ref, + into_format_mut, + borrow_format_ref, + borrow_format_mut, + into_format, + } + + into! { + /// Coerce into [`Tuple`]. + Tuple(OwnedTuple), + into_tuple_ref, + into_tuple_mut, + borrow_tuple_ref, + borrow_tuple_mut, + into_tuple, + } + + into! { + /// Coerce into a [`Object`]. + Object(Object), + into_object_ref, + into_object_mut, + borrow_object_ref, + borrow_object_mut, + into_object, + } + + into! { + /// Coerce into a [`RangeFrom`]. + RangeFrom(RangeFrom), + into_range_from_ref, + into_range_from_mut, + borrow_range_from_ref, + borrow_range_from_mut, + into_range_from, + } + + into! { + /// Coerce into a [`RangeFull`]. + RangeFull(RangeFull), + into_range_full_ref, + into_range_full_mut, + borrow_range_full_ref, + borrow_range_full_mut, + into_range_full, + } + + into! { + /// Coerce into a [`RangeToInclusive`]. + RangeToInclusive(RangeToInclusive), + into_range_to_inclusive_ref, + into_range_to_inclusive_mut, + borrow_range_to_inclusive_ref, + borrow_range_to_inclusive_mut, + into_range_to_inclusive, + } + + into! { + /// Coerce into a [`RangeInclusive`]. + RangeInclusive(RangeInclusive), + into_range_inclusive_ref, + into_range_inclusive_mut, + borrow_range_inclusive_ref, + borrow_range_inclusive_mut, + into_range_inclusive, + } + + into! { + /// Coerce into a [`RangeTo`]. + RangeTo(RangeTo), + into_range_to_ref, + into_range_to_mut, + borrow_range_to_ref, + borrow_range_to_mut, + into_range_to, + } + + into! { + /// Coerce into a [`Range`]. + Range(Range), + into_range_ref, + into_range_mut, + borrow_range_ref, + borrow_range_mut, + into_range, + } + + into! { + /// Coerce into a [`Stream`]. + Stream(Stream), + into_stream_ref, + into_stream_mut, + borrow_stream_ref, + borrow_stream_mut, + into_stream, + } + + into_base! { + /// Coerce into a [`Future`]. + Future(Future), + into_future_ref, + into_future_mut, + borrow_future_ref, + borrow_future_mut, + } + + /// Coerce into an [`AnyObj`]. + /// + /// This consumes the underlying value. #[inline] - pub fn as_integer(&self) -> VmResult { - match self { - Self::Integer(integer) => VmResult::Ok(*integer), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn into_any_obj(self) -> Result { + match self.take_kind()? { + ValueKind::Any(value) => Ok(value), + ref actual => Err(RuntimeError::expected_any(actual.type_info())), } } - /// Try to coerce value into an integer. + /// Coerce into a future, or convert into a future using the + /// [Protocol::INTO_FUTURE] protocol. + /// + /// You must use [Vm::with] to specify which virtual machine this function + /// is called inside. + /// + /// # Errors + /// + /// This function errors in case the provided type cannot be converted into + /// a future without the use of a [`Vm`] and one is not provided through the + /// environment. #[inline] - pub fn into_integer(self) -> VmResult { - match self { - Self::Integer(integer) => VmResult::Ok(integer), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } + pub fn into_future(self) -> VmResult { + let target = match vm_try!(self.inner.take()) { + ValueKind::Future(future) => return VmResult::Ok(future), + target => vm_try!(Value::try_from(target)), + }; + + let value = vm_try!(EnvProtocolCaller.call_protocol_fn(Protocol::INTO_FUTURE, target, ())); + VmResult::Ok(vm_try!(Future::from_value(value))) } - /// Try to coerce value into a float. + /// Try to coerce value into a typed value. #[inline] - pub fn as_float(&self) -> VmResult { - match self { - Self::Float(float) => VmResult::Ok(*float), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn into_any(self) -> Result + where + T: Any, + { + let any = match self.inner.take()? { + ValueKind::Any(any) => any, + actual => return Err(RuntimeError::expected_any(actual.type_info())), + }; + + match any.downcast::() { + Ok(any) => Ok(any), + Err((AnyObjError::Cast, any)) => { + Err(RuntimeError::from(AccessErrorKind::UnexpectedType { + expected: any::type_name::().into(), + actual: any.type_name(), + })) + } + Err((error, _)) => Err(RuntimeError::from(AccessError::from(error))), } } - /// Try to coerce value into a float. + /// Try to coerce value into a typed reference. #[inline] - pub fn into_float(self) -> VmResult { - match self { - Self::Float(float) => VmResult::Ok(float), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + pub fn into_any_ref(self) -> Result, RuntimeError> + where + T: Any, + { + let result = Ref::try_map(self.into_kind_ref()?, |kind| match kind { + ValueKind::Any(any) => Some(any), + _ => None, + }); + + let any = match result { + Ok(any) => any, + Err(actual) => return Err(RuntimeError::expected_any(actual.type_info())), + }; + + let result = Ref::result_map(any, |any| any.downcast_borrow_ref()); + + match result { + Ok(value) => Ok(value), + Err((AnyObjError::Cast, any)) => { + Err(RuntimeError::from(AccessErrorKind::UnexpectedType { + expected: any::type_name::().into(), + actual: any.type_name(), + })) + } + Err((error, _)) => Err(RuntimeError::from(AccessError::from(error))), } } - /// Try to coerce value into a type. + /// Try to coerce value into a typed mutable reference. #[inline] - pub fn as_type(&self) -> VmResult { - match self { - Self::Type(ty) => VmResult::Ok(*ty), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a type. - #[inline] - pub fn into_type(self) -> VmResult { - match self { - Self::Type(ty) => VmResult::Ok(ty), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a usize. - #[inline] - pub fn as_usize(&self) -> VmResult { - self.try_as_integer() - } - - /// Try to coerce value into a usize. - #[inline] - pub fn into_usize(self) -> VmResult { - self.try_into_integer() - } - - /// Try to coerce value into an [Ordering]. - #[inline] - pub fn as_ordering(&self) -> VmResult { - match self { - Self::Ordering(ty) => VmResult::Ok(*ty), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into an [Ordering]. - #[inline] - pub fn into_ordering(self) -> VmResult { - match self { - Self::Ordering(ty) => VmResult::Ok(ty), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a result. - #[inline] - pub fn into_result(self) -> VmResult>> { - match self { - Self::Result(result) => VmResult::Ok(result), - actual => err(VmErrorKind::expected::>(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a result. - #[inline] - pub fn as_result(&self) -> VmResult<&Shared>> { - match self { - Self::Result(result) => VmResult::Ok(result), - actual => err(VmErrorKind::expected::>(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a generator. - #[inline] - pub fn into_generator(self) -> VmResult>> { - match self { - Value::Generator(generator) => VmResult::Ok(generator), - actual => err(VmErrorKind::expected::>(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a stream. - #[inline] - pub fn into_stream(self) -> VmResult>> { - match self { - Value::Stream(stream) => VmResult::Ok(stream), - actual => err(VmErrorKind::expected::>(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a future. - #[inline] - pub fn into_generator_state(self) -> VmResult> { - match self { - Value::GeneratorState(state) => VmResult::Ok(state), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into an option. - #[inline] - pub fn into_option(self) -> VmResult>> { - match self { - Self::Option(option) => VmResult::Ok(option), - actual => err(VmErrorKind::expected::>(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a string. - #[inline] - pub fn into_string(self) -> VmResult> { - match self { - Self::String(string) => VmResult::Ok(string), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into bytes. - #[inline] - pub fn into_bytes(self) -> VmResult> { - match self { - Self::Bytes(bytes) => VmResult::Ok(bytes), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a vector. - #[inline] - pub fn into_vec(self) -> VmResult> { - match self { - Self::Vec(vec) => VmResult::Ok(vec), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a tuple. - #[inline] - pub fn into_tuple(self) -> VmResult> { - match self { - Self::EmptyTuple => VmResult::Ok(vm_try!(Shared::new(OwnedTuple::new()))), - Self::Tuple(tuple) => VmResult::Ok(tuple), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into an object. - #[inline] - pub fn into_object(self) -> VmResult> { - match self { - Self::Object(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a [`RangeFrom`]. - #[inline] - pub fn into_range_from(self) -> VmResult> { - match self { - Self::RangeFrom(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a [`RangeFull`]. - #[inline] - pub fn into_range_full(self) -> VmResult> { - match self { - Self::RangeFull(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a [`RangeToInclusive`]. - #[inline] - pub fn into_range_to_inclusive(self) -> VmResult> { - match self { - Self::RangeToInclusive(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a [`RangeInclusive`]. - #[inline] - pub fn into_range_inclusive(self) -> VmResult> { - match self { - Self::RangeInclusive(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a [`RangeTo`]. - #[inline] - pub fn into_range_to(self) -> VmResult> { - match self { - Self::RangeTo(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::( - vm_try!(actual.type_info()), - )), - } - } - - /// Try to coerce value into a [`Range`]. - #[inline] - pub fn into_range(self) -> VmResult> { - match self { - Self::Range(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a [`ControlFlow`]. - #[inline] - pub fn into_control_flow(self) -> VmResult> { - match self { - Self::ControlFlow(object) => VmResult::Ok(object), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a function pointer. - #[inline] - pub fn into_function(self) -> VmResult> { - match self { - Self::Function(function) => VmResult::Ok(function), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into a format spec. - #[inline] - pub fn into_format(self) -> VmResult> { - match self { - Value::Format(format) => VmResult::Ok(format), - actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into an iterator. - #[inline] - pub fn into_iterator(self) -> VmResult> { - match self { - Value::Iterator(format) => VmResult::Ok(format), - actual => err(VmErrorKind::expected::(vm_try!( - actual.type_info() - ))), - } - } - - /// Try to coerce value into an opaque value. - #[inline] - pub fn into_any(self) -> VmResult> { - match self { - Self::Any(any) => VmResult::Ok(any), - actual => err(VmErrorKind::expected_any(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a ref and an associated guard. - /// - /// # Safety - /// - /// This coerces a strong guard to the value into its raw components. - /// - /// It is up to the caller to ensure that the returned pointer does not - /// outlive the returned guard, not the virtual machine the value belongs - /// to. - #[inline] - pub fn into_any_ptr(self) -> VmResult<(ptr::NonNull, RawRef)> - where - T: Any, - { - match self { - Self::Any(any) => { - let any = vm_try!(any.internal_downcast_into_ref::(AccessKind::Any)); - let (data, guard) = Ref::into_raw(any); - VmResult::Ok((data, guard)) - } - actual => err(VmErrorKind::expected_any(vm_try!(actual.type_info()))), - } - } - - /// Try to coerce value into a ref and an associated guard. - /// - /// # Safety - /// - /// This coerces a strong guard to the value into its raw components. - /// - /// It is up to the caller to ensure that the returned pointer does not - /// outlive the returned guard, not the virtual machine the value belongs - /// to. - #[inline] - pub fn into_any_mut(self) -> VmResult<(ptr::NonNull, RawMut)> - where - T: Any, - { - match self { - Self::Any(any) => { - let any = vm_try!(any.internal_downcast_into_mut::(AccessKind::Any)); - let (data, guard) = Mut::into_raw(any); - VmResult::Ok((data, guard)) - } - actual => err(VmErrorKind::expected_any(vm_try!(actual.type_info()))), + pub fn into_any_mut(self) -> Result, RuntimeError> + where + T: Any, + { + let result = Mut::try_map(self.into_kind_mut()?, |kind| match kind { + ValueKind::Any(any) => Some(any), + _ => None, + }); + + let any = match result { + Ok(any) => any, + Err(actual) => return Err(RuntimeError::expected_any(actual.type_info())), + }; + + let result = Mut::result_map(any, |any| any.downcast_borrow_mut()); + + match result { + Ok(value) => Ok(value), + Err((AnyObjError::Cast, any)) => { + Err(RuntimeError::from(AccessErrorKind::UnexpectedType { + expected: any::type_name::().into(), + actual: any.type_name(), + })) + } + Err((error, _)) => Err(RuntimeError::from(AccessError::from(error))), } } @@ -1119,97 +1412,13 @@ impl Value { /// /// One notable feature is that the type of a variant is its container /// *enum*, and not the type hash of the variant itself. - pub fn type_hash(&self) -> Result { - Ok(match self { - Self::Bool(..) => crate::runtime::static_type::BOOL_TYPE.hash, - Self::Byte(..) => crate::runtime::static_type::BYTE_TYPE.hash, - Self::Char(..) => crate::runtime::static_type::CHAR_TYPE.hash, - Self::Integer(..) => crate::runtime::static_type::INTEGER_TYPE.hash, - Self::Float(..) => crate::runtime::static_type::FLOAT_TYPE.hash, - Self::Type(..) => crate::runtime::static_type::TYPE.hash, - Self::Ordering(..) => crate::runtime::static_type::ORDERING_TYPE.hash, - Self::String(..) => crate::runtime::static_type::STRING_TYPE.hash, - Self::Bytes(..) => crate::runtime::static_type::BYTES_TYPE.hash, - Self::Vec(..) => crate::runtime::static_type::VEC_TYPE.hash, - Self::EmptyTuple => crate::runtime::static_type::TUPLE_TYPE.hash, - Self::Tuple(..) => crate::runtime::static_type::TUPLE_TYPE.hash, - Self::Object(..) => crate::runtime::static_type::OBJECT_TYPE.hash, - Self::RangeFrom(..) => crate::runtime::static_type::RANGE_FROM_TYPE.hash, - Self::RangeFull(..) => crate::runtime::static_type::RANGE_FULL_TYPE.hash, - Self::RangeInclusive(..) => crate::runtime::static_type::RANGE_INCLUSIVE_TYPE.hash, - Self::RangeToInclusive(..) => crate::runtime::static_type::RANGE_TO_INCLUSIVE_TYPE.hash, - Self::RangeTo(..) => crate::runtime::static_type::RANGE_TO_TYPE.hash, - Self::Range(..) => crate::runtime::static_type::RANGE_TYPE.hash, - Self::ControlFlow(..) => crate::runtime::static_type::CONTROL_FLOW_TYPE.hash, - Self::Future(..) => crate::runtime::static_type::FUTURE_TYPE.hash, - Self::Stream(..) => crate::runtime::static_type::STREAM_TYPE.hash, - Self::Generator(..) => crate::runtime::static_type::GENERATOR_TYPE.hash, - Self::GeneratorState(..) => crate::runtime::static_type::GENERATOR_STATE_TYPE.hash, - Self::Result(..) => crate::runtime::static_type::RESULT_TYPE.hash, - Self::Option(..) => crate::runtime::static_type::OPTION_TYPE.hash, - Self::Function(..) => crate::runtime::static_type::FUNCTION_TYPE.hash, - Self::Format(..) => crate::runtime::static_type::FORMAT_TYPE.hash, - Self::Iterator(..) => crate::runtime::static_type::ITERATOR_TYPE.hash, - Self::EmptyStruct(empty) => empty.borrow_ref()?.rtti.hash, - Self::TupleStruct(tuple) => tuple.borrow_ref()?.rtti.hash, - Self::Struct(object) => object.borrow_ref()?.rtti.hash, - Self::Variant(variant) => variant.borrow_ref()?.rtti().enum_hash, - Self::Any(any) => any.borrow_ref()?.type_hash(), - }) + pub fn type_hash(&self) -> Result { + Ok(self.inner.borrow_ref()?.type_hash()) } /// Get the type information for the current value. - pub fn type_info(&self) -> VmResult { - VmResult::Ok(match self { - Self::Bool(..) => TypeInfo::StaticType(crate::runtime::static_type::BOOL_TYPE), - Self::Byte(..) => TypeInfo::StaticType(crate::runtime::static_type::BYTE_TYPE), - Self::Char(..) => TypeInfo::StaticType(crate::runtime::static_type::CHAR_TYPE), - Self::Integer(..) => TypeInfo::StaticType(crate::runtime::static_type::INTEGER_TYPE), - Self::Float(..) => TypeInfo::StaticType(crate::runtime::static_type::FLOAT_TYPE), - Self::Type(..) => TypeInfo::StaticType(crate::runtime::static_type::TYPE), - Self::Ordering(..) => TypeInfo::StaticType(crate::runtime::static_type::ORDERING_TYPE), - Self::String(..) => TypeInfo::StaticType(crate::runtime::static_type::STRING_TYPE), - Self::Bytes(..) => TypeInfo::StaticType(crate::runtime::static_type::BYTES_TYPE), - Self::Vec(..) => TypeInfo::StaticType(crate::runtime::static_type::VEC_TYPE), - Self::EmptyTuple => TypeInfo::StaticType(crate::runtime::static_type::TUPLE_TYPE), - Self::Tuple(..) => TypeInfo::StaticType(crate::runtime::static_type::TUPLE_TYPE), - Self::Object(..) => TypeInfo::StaticType(crate::runtime::static_type::OBJECT_TYPE), - Self::RangeFrom(..) => { - TypeInfo::StaticType(crate::runtime::static_type::RANGE_FROM_TYPE) - } - Self::RangeFull(..) => { - TypeInfo::StaticType(crate::runtime::static_type::RANGE_FULL_TYPE) - } - Self::RangeInclusive(..) => { - TypeInfo::StaticType(crate::runtime::static_type::RANGE_INCLUSIVE_TYPE) - } - Self::RangeToInclusive(..) => { - TypeInfo::StaticType(crate::runtime::static_type::RANGE_TO_INCLUSIVE_TYPE) - } - Self::RangeTo(..) => TypeInfo::StaticType(crate::runtime::static_type::RANGE_TO_TYPE), - Self::Range(..) => TypeInfo::StaticType(crate::runtime::static_type::RANGE_TYPE), - Self::ControlFlow(..) => { - TypeInfo::StaticType(crate::runtime::static_type::CONTROL_FLOW_TYPE) - } - Self::Future(..) => TypeInfo::StaticType(crate::runtime::static_type::FUTURE_TYPE), - Self::Stream(..) => TypeInfo::StaticType(crate::runtime::static_type::STREAM_TYPE), - Self::Generator(..) => { - TypeInfo::StaticType(crate::runtime::static_type::GENERATOR_TYPE) - } - Self::GeneratorState(..) => { - TypeInfo::StaticType(crate::runtime::static_type::GENERATOR_STATE_TYPE) - } - Self::Option(..) => TypeInfo::StaticType(crate::runtime::static_type::OPTION_TYPE), - Self::Result(..) => TypeInfo::StaticType(crate::runtime::static_type::RESULT_TYPE), - Self::Function(..) => TypeInfo::StaticType(crate::runtime::static_type::FUNCTION_TYPE), - Self::Format(..) => TypeInfo::StaticType(crate::runtime::static_type::FORMAT_TYPE), - Self::Iterator(..) => TypeInfo::StaticType(crate::runtime::static_type::ITERATOR_TYPE), - Self::EmptyStruct(empty) => vm_try!(empty.borrow_ref()).type_info(), - Self::TupleStruct(tuple) => vm_try!(tuple.borrow_ref()).type_info(), - Self::Struct(object) => vm_try!(object.borrow_ref()).type_info(), - Self::Variant(empty) => vm_try!(empty.borrow_ref()).type_info(), - Self::Any(any) => vm_try!(any.borrow_ref()).type_info(), - }) + pub fn type_info(&self) -> Result { + Ok(self.inner.borrow_ref()?.type_info()) } /// Perform a partial equality test between two values. @@ -1223,143 +1432,116 @@ impl Value { /// /// This function will error if called outside of a virtual machine context. pub fn partial_eq(a: &Value, b: &Value) -> VmResult { - Value::partial_eq_with(a, b, &mut EnvProtocolCaller) + Self::partial_eq_with(a, b, &mut EnvProtocolCaller) } /// Perform a total equality test between two values. /// /// This is the basis for the eq operation (`partial_eq` / '=='). pub(crate) fn partial_eq_with( - a: &Value, + &self, b: &Value, caller: &mut impl ProtocolCaller, ) -> VmResult { - match (a, b) { - (Self::Bool(a), Self::Bool(b)) => return VmResult::Ok(a == b), - (Self::Byte(a), Self::Byte(b)) => return VmResult::Ok(a == b), - (Self::Char(a), Self::Char(b)) => return VmResult::Ok(a == b), - (Self::Integer(a), Self::Integer(b)) => return VmResult::Ok(a == b), - (Self::Float(a), Self::Float(b)) => return VmResult::Ok(a == b), - (Self::Type(a), Self::Type(b)) => return VmResult::Ok(a == b), - (Self::Bytes(a), Self::Bytes(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return VmResult::Ok(*a == *b); - } - (Self::Vec(a), b) => { - let a = vm_try!(a.borrow_ref()); - return Vec::partial_eq_with(&a, b.clone(), caller); - } - (Self::EmptyTuple, Self::EmptyTuple) => return VmResult::Ok(true), - (Self::Tuple(a), b) => { - let a = vm_try!(a.borrow_ref()); - return Vec::partial_eq_with(&a, b.clone(), caller); - } - (Self::Object(a), b) => { - let a = vm_try!(a.borrow_ref()); - return Object::partial_eq_with(&a, b.clone(), caller); - } - (Self::RangeFrom(a), Self::RangeFrom(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFrom::partial_eq_with(&a, &b, caller); - } - (Self::RangeFull(a), Self::RangeFull(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFull::partial_eq_with(&a, &b, caller); - } - (Self::RangeInclusive(a), Self::RangeInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeInclusive::partial_eq_with(&a, &b, caller); - } - (Self::RangeToInclusive(a), Self::RangeToInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeToInclusive::partial_eq_with(&a, &b, caller); - } - (Self::RangeTo(a), Self::RangeTo(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeTo::partial_eq_with(&a, &b, caller); - } - (Self::Range(a), Self::Range(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Range::partial_eq_with(&a, &b, caller); - } - (Self::ControlFlow(a), Self::ControlFlow(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return ControlFlow::partial_eq_with(&a, &b, caller); - } - (Self::EmptyStruct(a), Self::EmptyStruct(b)) => { - if vm_try!(a.borrow_ref()).rtti.hash == vm_try!(b.borrow_ref()).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); + { + let a = vm_try!(self.borrow_kind_ref()); + + match (&*a, &*vm_try!(b.borrow_kind_ref())) { + (ValueKind::EmptyTuple, ValueKind::EmptyTuple) => return VmResult::Ok(true), + (ValueKind::Bool(a), ValueKind::Bool(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Byte(a), ValueKind::Byte(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Char(a), ValueKind::Char(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Integer(a), ValueKind::Integer(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Float(a), ValueKind::Float(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Type(a), ValueKind::Type(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Bytes(a), ValueKind::Bytes(b)) => { + return VmResult::Ok(*a == *b); } - } - (Self::TupleStruct(a), Self::TupleStruct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - - if a.rtti.hash == b.rtti.hash { - return Vec::eq_with(&a.data, &b.data, Value::partial_eq_with, caller); + (ValueKind::RangeFrom(a), ValueKind::RangeFrom(b)) => { + return RangeFrom::partial_eq_with(a, b, caller); } - } - (Self::Struct(a), Self::Struct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - - if a.rtti.hash == b.rtti.hash { - return Object::eq_with(&a.data, &b.data, Value::partial_eq_with, caller); + (ValueKind::RangeFull(a), ValueKind::RangeFull(b)) => { + return RangeFull::partial_eq_with(a, b, caller); } - } - (Self::Variant(a), Self::Variant(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - - if a.rtti().enum_hash == b.rtti().enum_hash { - return Variant::partial_eq_with(&a, &b, caller); + (ValueKind::RangeInclusive(a), ValueKind::RangeInclusive(b)) => { + return RangeInclusive::partial_eq_with(a, b, caller); } - } - (Self::String(a), Self::String(b)) => { - return VmResult::Ok(*vm_try!(a.borrow_ref()) == *vm_try!(b.borrow_ref())); - } - (Self::Option(a), Self::Option(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Some(a), Some(b)) => return Self::partial_eq_with(a, b, caller), + (ValueKind::RangeToInclusive(a), ValueKind::RangeToInclusive(b)) => { + return RangeToInclusive::partial_eq_with(a, b, caller); + } + (ValueKind::RangeTo(a), ValueKind::RangeTo(b)) => { + return RangeTo::partial_eq_with(a, b, caller); + } + (ValueKind::Range(a), ValueKind::Range(b)) => { + return Range::partial_eq_with(a, b, caller); + } + (ValueKind::ControlFlow(a), ValueKind::ControlFlow(b)) => { + return ControlFlow::partial_eq_with(a, b, caller); + } + (ValueKind::EmptyStruct(a), ValueKind::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); + } + } + (ValueKind::TupleStruct(a), ValueKind::TupleStruct(b)) => { + if a.rtti.hash == b.rtti.hash { + return Vec::eq_with(&a.data, &b.data, Value::partial_eq_with, caller); + } + } + (ValueKind::Struct(a), ValueKind::Struct(b)) => { + if a.rtti.hash == b.rtti.hash { + return Object::eq_with(&a.data, &b.data, Value::partial_eq_with, caller); + } + } + (ValueKind::Variant(a), ValueKind::Variant(b)) => { + if a.rtti().enum_hash == b.rtti().enum_hash { + return Variant::partial_eq_with(a, b, caller); + } + } + (ValueKind::String(a), ValueKind::String(b)) => { + return VmResult::Ok(*a == *b); + } + (ValueKind::Option(a), ValueKind::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), - } - } - (Self::Result(a), Self::Result(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Ok(a), Ok(b)) => return Self::partial_eq_with(a, b, caller), - (Err(a), Err(b)) => return Self::partial_eq_with(a, b, caller), + }, + (ValueKind::Result(a), ValueKind::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), - } + }, + _ => {} } - (a, b) => { - match vm_try!(caller.try_call_protocol_fn( - Protocol::PARTIAL_EQ, - a.clone(), - (b.clone(),) - )) { - CallResult::Ok(value) => return bool::from_value(value), - CallResult::Unsupported(..) => {} + + match &*a { + ValueKind::Vec(a) => { + return Vec::partial_eq_with(a, b.clone(), caller); + } + ValueKind::Tuple(a) => { + return Vec::partial_eq_with(a, b.clone(), caller); } + ValueKind::Object(a) => { + return Object::partial_eq_with(a, b.clone(), caller); + } + _ => {} } } + if let CallResult::Ok(value) = + vm_try!(caller.try_call_protocol_fn(Protocol::PARTIAL_EQ, self.clone(), (b.clone(),))) + { + return <_>::from_value(value); + } + err(VmErrorKind::UnsupportedBinaryOperation { op: "partial_eq", - lhs: vm_try!(a.type_info()), + lhs: vm_try!(self.type_info()), rhs: vm_try!(b.type_info()), }) } @@ -1376,19 +1558,19 @@ impl Value { hasher: &mut Hasher, caller: &mut impl ProtocolCaller, ) -> VmResult<()> { - match self { - Value::Integer(value) => { + match &*vm_try!(self.borrow_kind_ref()) { + ValueKind::Integer(value) => { hasher.write_i64(*value); return VmResult::Ok(()); } - Value::Byte(value) => { + ValueKind::Byte(value) => { hasher.write_u8(*value); return VmResult::Ok(()); } // Care must be taken whan hashing floats, to ensure that `hash(v1) // === hash(v2)` if `eq(v1) === eq(v2)`. Hopefully we accomplish // this by rejecting NaNs and rectifying subnormal values of zero. - Value::Float(value) => { + ValueKind::Float(value) => { if value.is_nan() { return VmResult::err(VmErrorKind::IllegalFloatOperation { value: *value }); } @@ -1397,31 +1579,27 @@ impl Value { hasher.write_f64((zero as u8 as f64) * 0.0 + (!zero as u8 as f64) * *value); return VmResult::Ok(()); } - Value::String(string) => { - let string = vm_try!(string.borrow_ref()); - hasher.write_str(&string); + ValueKind::String(string) => { + hasher.write_str(string); return VmResult::Ok(()); } - Value::Bytes(bytes) => { - let bytes = vm_try!(bytes.borrow_ref()); - hasher.write(&bytes); + ValueKind::Bytes(bytes) => { + hasher.write(bytes); return VmResult::Ok(()); } - Value::Tuple(tuple) => { - let tuple = vm_try!(tuple.borrow_ref()); - return Tuple::hash_with(&tuple, hasher, caller); + ValueKind::Tuple(tuple) => { + return Tuple::hash_with(tuple, hasher, caller); } - Value::Vec(vec) => { - let vec = vm_try!(vec.borrow_ref()); - return Vec::hash_with(&vec, hasher, caller); - } - value => { - match vm_try!(caller.try_call_protocol_fn(Protocol::HASH, value.clone(), (hasher,))) - { - CallResult::Ok(value) => return <()>::from_value(value), - CallResult::Unsupported(..) => {} - } + ValueKind::Vec(vec) => { + return Vec::hash_with(vec, hasher, caller); } + _ => {} + } + + if let CallResult::Ok(value) = + vm_try!(caller.try_call_protocol_fn(Protocol::HASH, self.clone(), (hasher,))) + { + return <_>::from_value(value); } err(VmErrorKind::UnsupportedUnaryOperation { @@ -1448,77 +1626,58 @@ impl Value { /// /// This is the basis for the eq operation (`==`). pub(crate) fn eq_with(&self, b: &Value, caller: &mut impl ProtocolCaller) -> VmResult { - match (self, b) { - (Self::Bool(a), Self::Bool(b)) => return VmResult::Ok(a == b), - (Self::Byte(a), Self::Byte(b)) => return VmResult::Ok(a == b), - (Self::Char(a), Self::Char(b)) => return VmResult::Ok(a == b), - (Self::Float(a), Self::Float(b)) => { - if let Some(ordering) = a.partial_cmp(b) { - return VmResult::Ok(matches!(ordering, Ordering::Equal)); - } - - return VmResult::err(VmErrorKind::IllegalFloatComparison { lhs: *a, rhs: *b }); - } - (Self::Integer(a), Self::Integer(b)) => return VmResult::Ok(a == b), - (Self::Type(a), Self::Type(b)) => return VmResult::Ok(a == b), - (Self::Bytes(a), Self::Bytes(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); + match ( + &*vm_try!(self.borrow_kind_ref()), + &*vm_try!(b.borrow_kind_ref()), + ) { + (ValueKind::Bool(a), ValueKind::Bool(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Byte(a), ValueKind::Byte(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Char(a), ValueKind::Char(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Float(a), ValueKind::Float(b)) => { + let Some(ordering) = a.partial_cmp(b) else { + return VmResult::err(VmErrorKind::IllegalFloatComparison { lhs: *a, rhs: *b }); + }; + + return VmResult::Ok(matches!(ordering, Ordering::Equal)); + } + (ValueKind::Integer(a), ValueKind::Integer(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Type(a), ValueKind::Type(b)) => return VmResult::Ok(*a == *b), + (ValueKind::Bytes(a), ValueKind::Bytes(b)) => { return VmResult::Ok(*a == *b); } - (Self::Vec(a), Self::Vec(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Vec::eq_with(&a, &b, Value::eq_with, caller); - } - (Self::EmptyTuple, Self::EmptyTuple) => return VmResult::Ok(true), - (Self::Tuple(a), Self::Tuple(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Vec::eq_with(&a, &b, Value::eq_with, caller); - } - (Self::Object(a), Self::Object(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Object::eq_with(&a, &b, Value::eq_with, caller); - } - (Self::RangeFrom(a), Self::RangeFrom(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFrom::eq_with(&a, &b, caller); - } - (Self::RangeFull(a), Self::RangeFull(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFull::eq_with(&a, &b, caller); - } - (Self::RangeInclusive(a), Self::RangeInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeInclusive::eq_with(&a, &b, caller); - } - (Self::RangeToInclusive(a), Self::RangeToInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeToInclusive::eq_with(&a, &b, caller); - } - (Self::RangeTo(a), Self::RangeTo(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeTo::eq_with(&a, &b, caller); - } - (Self::Range(a), Self::Range(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Range::eq_with(&a, &b, caller); - } - (Self::ControlFlow(a), Self::ControlFlow(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return ControlFlow::eq_with(&a, &b, caller); - } - (Self::EmptyStruct(a), Self::EmptyStruct(b)) => { - if vm_try!(a.borrow_ref()).rtti.hash == vm_try!(b.borrow_ref()).rtti.hash { + (ValueKind::Vec(a), ValueKind::Vec(b)) => { + return Vec::eq_with(a, b, Value::eq_with, caller); + } + (ValueKind::EmptyTuple, ValueKind::EmptyTuple) => return VmResult::Ok(true), + (ValueKind::Tuple(a), ValueKind::Tuple(b)) => { + return Vec::eq_with(a, b, Value::eq_with, caller); + } + (ValueKind::Object(a), ValueKind::Object(b)) => { + return Object::eq_with(a, b, Value::eq_with, caller); + } + (ValueKind::RangeFrom(a), ValueKind::RangeFrom(b)) => { + return RangeFrom::eq_with(a, b, caller); + } + (ValueKind::RangeFull(a), ValueKind::RangeFull(b)) => { + return RangeFull::eq_with(a, b, caller); + } + (ValueKind::RangeInclusive(a), ValueKind::RangeInclusive(b)) => { + return RangeInclusive::eq_with(a, b, caller); + } + (ValueKind::RangeToInclusive(a), ValueKind::RangeToInclusive(b)) => { + return RangeToInclusive::eq_with(a, b, caller); + } + (ValueKind::RangeTo(a), ValueKind::RangeTo(b)) => { + return RangeTo::eq_with(a, b, caller); + } + (ValueKind::Range(a), ValueKind::Range(b)) => { + return Range::eq_with(a, b, caller); + } + (ValueKind::ControlFlow(a), ValueKind::ControlFlow(b)) => { + return ControlFlow::eq_with(a, b, caller); + } + (ValueKind::EmptyStruct(a), ValueKind::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. @@ -1527,54 +1686,41 @@ impl Value { return VmResult::Ok(true); } } - (Self::TupleStruct(a), Self::TupleStruct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::TupleStruct(a), ValueKind::TupleStruct(b)) => { if a.rtti.hash == b.rtti.hash { return Vec::eq_with(&a.data, &b.data, Value::eq_with, caller); } } - (Self::Struct(a), Self::Struct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::Struct(a), ValueKind::Struct(b)) => { if a.rtti.hash == b.rtti.hash { return Object::eq_with(&a.data, &b.data, Value::eq_with, caller); } } - (Self::Variant(a), Self::Variant(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::Variant(a), ValueKind::Variant(b)) => { if a.rtti().enum_hash == b.rtti().enum_hash { - return Variant::eq_with(&a, &b, caller); - } - } - (Self::String(a), Self::String(b)) => { - return VmResult::Ok(*vm_try!(a.borrow_ref()) == *vm_try!(b.borrow_ref())); - } - (Self::Option(a), Self::Option(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Some(a), Some(b)) => return Self::eq_with(a, b, caller), - (None, None) => return VmResult::Ok(true), - _ => return VmResult::Ok(false), - } - } - (Self::Result(a), Self::Result(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Ok(a), Ok(b)) => return Self::eq_with(a, b, caller), - (Err(a), Err(b)) => return Self::eq_with(a, b, caller), - _ => return VmResult::Ok(false), + return Variant::eq_with(a, b, caller); } } - _ => { - match vm_try!(caller.try_call_protocol_fn(Protocol::EQ, self.clone(), (b.clone(),))) - { - CallResult::Ok(value) => return bool::from_value(value), - CallResult::Unsupported(..) => {} - } + (ValueKind::String(a), ValueKind::String(b)) => { + return VmResult::Ok(*a == *b); } + (ValueKind::Option(a), ValueKind::Option(b)) => match (a, b) { + (Some(a), Some(b)) => return Value::eq_with(a, b, caller), + (None, None) => return VmResult::Ok(true), + _ => return VmResult::Ok(false), + }, + (ValueKind::Result(a), ValueKind::Result(b)) => match (a, b) { + (Ok(a), Ok(b)) => return Value::eq_with(a, b, caller), + (Err(a), Err(b)) => return Value::eq_with(a, b, caller), + _ => return VmResult::Ok(false), + }, + _ => {} + } + + if let CallResult::Ok(value) = + vm_try!(caller.try_call_protocol_fn(Protocol::EQ, self.clone(), (b.clone(),))) + { + return <_>::from_value(value); } err(VmErrorKind::UnsupportedBinaryOperation { @@ -1602,70 +1748,57 @@ impl Value { /// /// This is the basis for the comparison operation. pub(crate) fn partial_cmp_with( - a: &Value, + &self, b: &Value, caller: &mut impl ProtocolCaller, ) -> VmResult> { - match (a, b) { - (Self::Bool(a), Self::Bool(b)) => return VmResult::Ok(a.partial_cmp(b)), - (Self::Byte(a), Self::Byte(b)) => return VmResult::Ok(a.partial_cmp(b)), - (Self::Char(a), Self::Char(b)) => return VmResult::Ok(a.partial_cmp(b)), - (Self::Float(a), Self::Float(b)) => return VmResult::Ok(a.partial_cmp(b)), - (Self::Integer(a), Self::Integer(b)) => return VmResult::Ok(a.partial_cmp(b)), - (Self::Type(a), Self::Type(b)) => return VmResult::Ok(a.partial_cmp(b)), - (Self::Bytes(a), Self::Bytes(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return VmResult::Ok(a.partial_cmp(&b)); - } - (Self::Vec(a), Self::Vec(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Vec::partial_cmp_with(&a, &b, caller); - } - (Self::EmptyTuple, Self::EmptyTuple) => return VmResult::Ok(Some(Ordering::Equal)), - (Self::Tuple(a), Self::Tuple(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Vec::partial_cmp_with(&a, &b, caller); - } - (Self::Object(a), Self::Object(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Object::partial_cmp_with(&a, &b, caller); - } - (Self::RangeFrom(a), Self::RangeFrom(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFrom::partial_cmp_with(&a, &b, caller); - } - (Self::RangeFull(a), Self::RangeFull(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFull::partial_cmp_with(&a, &b, caller); - } - (Self::RangeInclusive(a), Self::RangeInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeInclusive::partial_cmp_with(&a, &b, caller); - } - (Self::RangeToInclusive(a), Self::RangeToInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeToInclusive::partial_cmp_with(&a, &b, caller); - } - (Self::RangeTo(a), Self::RangeTo(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeTo::partial_cmp_with(&a, &b, caller); - } - (Self::Range(a), Self::Range(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Range::partial_cmp_with(&a, &b, caller); - } - (Self::EmptyStruct(a), Self::EmptyStruct(b)) => { - if vm_try!(a.borrow_ref()).rtti.hash == vm_try!(b.borrow_ref()).rtti.hash { + match ( + &*vm_try!(self.borrow_kind_ref()), + &*vm_try!(b.borrow_kind_ref()), + ) { + (ValueKind::EmptyTuple, ValueKind::EmptyTuple) => { + return VmResult::Ok(Some(Ordering::Equal)) + } + (ValueKind::Bool(a), ValueKind::Bool(b)) => return VmResult::Ok(a.partial_cmp(b)), + (ValueKind::Byte(a), ValueKind::Byte(b)) => return VmResult::Ok(a.partial_cmp(b)), + (ValueKind::Char(a), ValueKind::Char(b)) => return VmResult::Ok(a.partial_cmp(b)), + (ValueKind::Float(a), ValueKind::Float(b)) => return VmResult::Ok(a.partial_cmp(b)), + (ValueKind::Integer(a), ValueKind::Integer(b)) => { + return VmResult::Ok(a.partial_cmp(b)); + } + (ValueKind::Type(a), ValueKind::Type(b)) => return VmResult::Ok(a.partial_cmp(b)), + (ValueKind::Bytes(a), ValueKind::Bytes(b)) => { + return VmResult::Ok(a.partial_cmp(b)); + } + (ValueKind::Vec(a), ValueKind::Vec(b)) => { + return Vec::partial_cmp_with(a, b, caller); + } + (ValueKind::Tuple(a), ValueKind::Tuple(b)) => { + return Vec::partial_cmp_with(a, b, caller); + } + (ValueKind::Object(a), ValueKind::Object(b)) => { + return Object::partial_cmp_with(a, b, caller); + } + (ValueKind::RangeFrom(a), ValueKind::RangeFrom(b)) => { + return RangeFrom::partial_cmp_with(a, b, caller); + } + (ValueKind::RangeFull(a), ValueKind::RangeFull(b)) => { + return RangeFull::partial_cmp_with(a, b, caller); + } + (ValueKind::RangeInclusive(a), ValueKind::RangeInclusive(b)) => { + return RangeInclusive::partial_cmp_with(a, b, caller); + } + (ValueKind::RangeToInclusive(a), ValueKind::RangeToInclusive(b)) => { + return RangeToInclusive::partial_cmp_with(a, b, caller); + } + (ValueKind::RangeTo(a), ValueKind::RangeTo(b)) => { + return RangeTo::partial_cmp_with(a, b, caller); + } + (ValueKind::Range(a), ValueKind::Range(b)) => { + return Range::partial_cmp_with(a, b, caller); + } + (ValueKind::EmptyStruct(a), ValueKind::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. @@ -1674,66 +1807,48 @@ impl Value { return VmResult::Ok(Some(Ordering::Equal)); } } - (Self::TupleStruct(a), Self::TupleStruct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::TupleStruct(a), ValueKind::TupleStruct(b)) => { if a.rtti.hash == b.rtti.hash { return Vec::partial_cmp_with(&a.data, &b.data, caller); } } - (Self::Struct(a), Self::Struct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::Struct(a), ValueKind::Struct(b)) => { if a.rtti.hash == b.rtti.hash { return Object::partial_cmp_with(&a.data, &b.data, caller); } } - (Self::Variant(a), Self::Variant(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::Variant(a), ValueKind::Variant(b)) => { if a.rtti().enum_hash == b.rtti().enum_hash { - return Variant::partial_cmp_with(&a, &b, caller); - } - } - (Self::String(a), Self::String(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return VmResult::Ok((*a).partial_cmp(&*b)); - } - (Self::Option(a), Self::Option(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Some(a), Some(b)) => return Self::partial_cmp_with(a, b, caller), - (None, None) => return VmResult::Ok(Some(Ordering::Equal)), - (Some(..), None) => return VmResult::Ok(Some(Ordering::Greater)), - (None, Some(..)) => return VmResult::Ok(Some(Ordering::Less)), - } - } - (Self::Result(a), Self::Result(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Ok(a), Ok(b)) => return Self::partial_cmp_with(a, b, caller), - (Err(a), Err(b)) => return Self::partial_cmp_with(a, b, caller), - (Ok(..), Err(..)) => return VmResult::Ok(Some(Ordering::Greater)), - (Err(..), Ok(..)) => return VmResult::Ok(Some(Ordering::Less)), - } - } - (a, b) => { - match vm_try!(caller.try_call_protocol_fn( - Protocol::PARTIAL_CMP, - a.clone(), - (b.clone(),) - )) { - CallResult::Ok(value) => return >::from_value(value), - CallResult::Unsupported(..) => {} + return Variant::partial_cmp_with(a, b, caller); } } + (ValueKind::String(a), ValueKind::String(b)) => { + return VmResult::Ok(a.partial_cmp(b)); + } + (ValueKind::Option(a), ValueKind::Option(b)) => match (a, b) { + (Some(a), Some(b)) => return Value::partial_cmp_with(a, b, caller), + (None, None) => return VmResult::Ok(Some(Ordering::Equal)), + (Some(..), None) => return VmResult::Ok(Some(Ordering::Greater)), + (None, Some(..)) => return VmResult::Ok(Some(Ordering::Less)), + }, + (ValueKind::Result(a), ValueKind::Result(b)) => match (a, b) { + (Ok(a), Ok(b)) => return Value::partial_cmp_with(a, b, caller), + (Err(a), Err(b)) => return Value::partial_cmp_with(a, b, caller), + (Ok(..), Err(..)) => return VmResult::Ok(Some(Ordering::Greater)), + (Err(..), Ok(..)) => return VmResult::Ok(Some(Ordering::Less)), + }, + _ => {} + } + + if let CallResult::Ok(value) = + vm_try!(caller.try_call_protocol_fn(Protocol::PARTIAL_CMP, self.clone(), (b.clone(),))) + { + return <_>::from_value(value); } err(VmErrorKind::UnsupportedBinaryOperation { op: "partial_cmp", - lhs: vm_try!(a.type_info()), + lhs: vm_try!(self.type_info()), rhs: vm_try!(b.type_info()), }) } @@ -1756,76 +1871,59 @@ impl Value { /// /// This is the basis for the comparison operation (`cmp`). pub(crate) fn cmp_with( - a: &Value, + &self, b: &Value, caller: &mut impl ProtocolCaller, ) -> VmResult { - match (a, b) { - (Self::Bool(a), Self::Bool(b)) => return VmResult::Ok(a.cmp(b)), - (Self::Byte(a), Self::Byte(b)) => return VmResult::Ok(a.cmp(b)), - (Self::Char(a), Self::Char(b)) => return VmResult::Ok(a.cmp(b)), - (Self::Float(a), Self::Float(b)) => { - if let Some(ordering) = a.partial_cmp(b) { - return VmResult::Ok(ordering); - } + match ( + &*vm_try!(self.borrow_kind_ref()), + &*vm_try!(b.borrow_kind_ref()), + ) { + (ValueKind::EmptyTuple, ValueKind::EmptyTuple) => return VmResult::Ok(Ordering::Equal), + (ValueKind::Bool(a), ValueKind::Bool(b)) => return VmResult::Ok(a.cmp(b)), + (ValueKind::Byte(a), ValueKind::Byte(b)) => return VmResult::Ok(a.cmp(b)), + (ValueKind::Char(a), ValueKind::Char(b)) => return VmResult::Ok(a.cmp(b)), + (ValueKind::Float(a), ValueKind::Float(b)) => { + let Some(ordering) = a.partial_cmp(b) else { + return VmResult::err(VmErrorKind::IllegalFloatComparison { lhs: *a, rhs: *b }); + }; - return VmResult::err(VmErrorKind::IllegalFloatComparison { lhs: *a, rhs: *b }); - } - (Self::Integer(a), Self::Integer(b)) => return VmResult::Ok(a.cmp(b)), - (Self::Type(a), Self::Type(b)) => return VmResult::Ok(a.cmp(b)), - (Self::Bytes(a), Self::Bytes(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return VmResult::Ok(a.cmp(&b)); - } - (Self::Vec(a), Self::Vec(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Vec::cmp_with(&a, &b, caller); - } - (Self::EmptyTuple, Self::EmptyTuple) => return VmResult::Ok(Ordering::Equal), - (Self::Tuple(a), Self::Tuple(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Vec::cmp_with(&a, &b, caller); - } - (Self::Object(a), Self::Object(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Object::cmp_with(&a, &b, caller); - } - (Self::RangeFrom(a), Self::RangeFrom(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFrom::cmp_with(&a, &b, caller); - } - (Self::RangeFull(a), Self::RangeFull(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeFull::cmp_with(&a, &b, caller); - } - (Self::RangeInclusive(a), Self::RangeInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeInclusive::cmp_with(&a, &b, caller); - } - (Self::RangeToInclusive(a), Self::RangeToInclusive(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeToInclusive::cmp_with(&a, &b, caller); - } - (Self::RangeTo(a), Self::RangeTo(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return RangeTo::cmp_with(&a, &b, caller); - } - (Self::Range(a), Self::Range(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return Range::cmp_with(&a, &b, caller); - } - (Self::EmptyStruct(a), Self::EmptyStruct(b)) => { - if vm_try!(a.borrow_ref()).rtti.hash == vm_try!(b.borrow_ref()).rtti.hash { + return VmResult::Ok(ordering); + } + (ValueKind::Integer(a), ValueKind::Integer(b)) => return VmResult::Ok(a.cmp(b)), + (ValueKind::Type(a), ValueKind::Type(b)) => return VmResult::Ok(a.cmp(b)), + (ValueKind::Bytes(a), ValueKind::Bytes(b)) => { + return VmResult::Ok(a.cmp(b)); + } + (ValueKind::Vec(a), ValueKind::Vec(b)) => { + return Vec::cmp_with(a, b, caller); + } + (ValueKind::Tuple(a), ValueKind::Tuple(b)) => { + return Vec::cmp_with(a, b, caller); + } + (ValueKind::Object(a), ValueKind::Object(b)) => { + return Object::cmp_with(a, b, caller); + } + (ValueKind::RangeFrom(a), ValueKind::RangeFrom(b)) => { + return RangeFrom::cmp_with(a, b, caller); + } + (ValueKind::RangeFull(a), ValueKind::RangeFull(b)) => { + return RangeFull::cmp_with(a, b, caller); + } + (ValueKind::RangeInclusive(a), ValueKind::RangeInclusive(b)) => { + return RangeInclusive::cmp_with(a, b, caller); + } + (ValueKind::RangeToInclusive(a), ValueKind::RangeToInclusive(b)) => { + return RangeToInclusive::cmp_with(a, b, caller); + } + (ValueKind::RangeTo(a), ValueKind::RangeTo(b)) => { + return RangeTo::cmp_with(a, b, caller); + } + (ValueKind::Range(a), ValueKind::Range(b)) => { + return Range::cmp_with(a, b, caller); + } + (ValueKind::EmptyStruct(a), ValueKind::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. @@ -1834,226 +1932,120 @@ impl Value { return VmResult::Ok(Ordering::Equal); } } - (Self::TupleStruct(a), Self::TupleStruct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::TupleStruct(a), ValueKind::TupleStruct(b)) => { if a.rtti.hash == b.rtti.hash { return Vec::cmp_with(&a.data, &b.data, caller); } } - (Self::Struct(a), Self::Struct(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::Struct(a), ValueKind::Struct(b)) => { if a.rtti.hash == b.rtti.hash { return Object::cmp_with(&a.data, &b.data, caller); } } - (Self::Variant(a), Self::Variant(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - + (ValueKind::Variant(a), ValueKind::Variant(b)) => { if a.rtti().enum_hash == b.rtti().enum_hash { - return Variant::cmp_with(&a, &b, caller); - } - } - (Self::String(a), Self::String(b)) => { - let a = vm_try!(a.borrow_ref()); - let b = vm_try!(b.borrow_ref()); - return VmResult::Ok(a.cmp(&b)); - } - (Self::Option(a), Self::Option(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Some(a), Some(b)) => return Self::cmp_with(a, b, caller), - (None, None) => return VmResult::Ok(Ordering::Equal), - (Some(..), None) => return VmResult::Ok(Ordering::Greater), - (None, Some(..)) => return VmResult::Ok(Ordering::Less), - } - } - (Self::Result(a), Self::Result(b)) => { - match (&*vm_try!(a.borrow_ref()), &*vm_try!(b.borrow_ref())) { - (Ok(a), Ok(b)) => return Self::cmp_with(a, b, caller), - (Err(a), Err(b)) => return Self::cmp_with(a, b, caller), - (Ok(..), Err(..)) => return VmResult::Ok(Ordering::Greater), - (Err(..), Ok(..)) => return VmResult::Ok(Ordering::Less), - } - } - (a, b) => { - match vm_try!(caller.try_call_protocol_fn(Protocol::CMP, a.clone(), (b.clone(),))) { - CallResult::Ok(value) => return Ordering::from_value(value), - CallResult::Unsupported(..) => {} + return Variant::cmp_with(a, b, caller); } } + (ValueKind::String(a), ValueKind::String(b)) => { + return VmResult::Ok(a.cmp(b)); + } + (ValueKind::Option(a), ValueKind::Option(b)) => match (a, b) { + (Some(a), Some(b)) => return Value::cmp_with(a, b, caller), + (None, None) => return VmResult::Ok(Ordering::Equal), + (Some(..), None) => return VmResult::Ok(Ordering::Greater), + (None, Some(..)) => return VmResult::Ok(Ordering::Less), + }, + (ValueKind::Result(a), ValueKind::Result(b)) => match (a, b) { + (Ok(a), Ok(b)) => return Value::cmp_with(a, b, caller), + (Err(a), Err(b)) => return Value::cmp_with(a, b, caller), + (Ok(..), Err(..)) => return VmResult::Ok(Ordering::Greater), + (Err(..), Ok(..)) => return VmResult::Ok(Ordering::Less), + }, + _ => {} + } + + if let CallResult::Ok(value) = + vm_try!(caller.try_call_protocol_fn(Protocol::CMP, self.clone(), (b.clone(),))) + { + return <_>::from_value(value); } err(VmErrorKind::UnsupportedBinaryOperation { op: "cmp", - lhs: vm_try!(a.type_info()), + lhs: vm_try!(self.type_info()), rhs: vm_try!(b.type_info()), }) } - pub(crate) fn try_into_integer(self) -> VmResult - where - T: TryFrom, - VmIntegerRepr: From, - { - let integer = vm_try!(self.into_integer()); - - match integer.try_into() { - Ok(number) => VmResult::Ok(number), - Err(..) => VmResult::err(VmErrorKind::ValueToIntegerCoercionError { - from: VmIntegerRepr::from(integer), - to: any::type_name::(), - }), - } - } - - pub(crate) fn try_as_integer(&self) -> VmResult + /// Try to coerce the current value as the specified integer `T`. + /// + /// # Examples + /// + /// ``` + /// use rune::runtime::{Value, VmResult}; + /// + /// let value = rune::to_value(u32::MAX)?; + /// + /// assert_eq!(value.try_as_integer::(), Ok(u32::MAX as u64)); + /// assert!(value.try_as_integer::().is_err()); + /// + /// # Ok::<(), rune::support::Error>(()) + /// ``` + pub fn try_as_integer(&self) -> Result where T: TryFrom, VmIntegerRepr: From, { - let integer = vm_try!(self.as_integer()); + let integer = self.as_integer()?; match integer.try_into() { - Ok(number) => VmResult::Ok(number), - Err(..) => VmResult::err(VmErrorKind::ValueToIntegerCoercionError { - from: VmIntegerRepr::from(integer), - to: any::type_name::(), - }), + Ok(number) => Ok(number), + Err(..) => Err(RuntimeError::new( + VmErrorKind::ValueToIntegerCoercionError { + from: VmIntegerRepr::from(integer), + to: any::type_name::(), + }, + )), } } } impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Value::Bool(value) => { - write!(f, "{:?}", value)?; - } - Value::Byte(value) => { - write!(f, "{:?}", value)?; - } - Value::Char(value) => { - write!(f, "{:?}", value)?; - } - Value::Integer(value) => { - write!(f, "{:?}", value)?; - } - Value::Float(value) => { - write!(f, "{:?}", value)?; - } - Value::Type(value) => { - write!(f, "{:?}", value)?; - } - Value::String(value) => { - write!(f, "{:?}", value)?; - } - Value::Bytes(value) => { - write!(f, "{:?}", value)?; - } - Value::Vec(value) => { - write!(f, "{:?}", value)?; - } - Value::EmptyTuple => { - write!(f, "()")?; - } - Value::Tuple(value) => { - write!(f, "{:?}", value)?; - } - Value::Object(value) => { - write!(f, "{:?}", value)?; - } - Value::RangeFrom(value) => { - write!(f, "{:?}", value)?; - } - Value::RangeFull(value) => { - write!(f, "{:?}", value)?; - } - Value::RangeInclusive(value) => { - write!(f, "{:?}", value)?; - } - Value::RangeToInclusive(value) => { - write!(f, "{:?}", value)?; - } - Value::RangeTo(value) => { - write!(f, "{:?}", value)?; - } - Value::Range(value) => { - write!(f, "{:?}", value)?; - } - Value::ControlFlow(value) => { - write!(f, "{:?}", value)?; - } - Value::Future(value) => { - write!(f, "{:?}", value)?; - } - Value::Stream(value) => { - write!(f, "{:?}", value)?; - } - Value::Generator(value) => { - write!(f, "{:?}", value)?; - } - Value::GeneratorState(value) => { - write!(f, "{:?}", value)?; - } - Value::Option(value) => { - write!(f, "{:?}", value)?; - } - Value::Result(value) => { - write!(f, "{:?}", value)?; - } - Value::EmptyStruct(value) => { - write!(f, "{:?}", value)?; - } - Value::TupleStruct(value) => { - write!(f, "{:?}", value)?; - } - Value::Struct(value) => { - write!(f, "{:?}", value)?; - } - Value::Variant(value) => { - write!(f, "{:?}", value)?; - } - Value::Function(value) => { - write!(f, "{:?}", value)?; - } - Value::Format(value) => { - write!(f, "{:?}", value)?; - } - Value::Iterator(value) => { - write!(f, "{:?}", value)?; - } - value => { - let mut o = Formatter::new(); - - if value.string_debug(&mut o).is_err() { - return Err(fmt::Error); - } + let mut o = Formatter::new(); - f.write_str(o.as_str())?; - } + if self.string_debug(&mut o).is_err() { + return Err(fmt::Error); } + f.write_str(o.as_str())?; Ok(()) } } -impl Default for Value { - fn default() -> Self { - Self::EmptyTuple +impl TryFrom<()> for Value { + type Error = rune_alloc::Error; + + #[inline] + fn try_from((): ()) -> Result { + Value::try_from(ValueKind::EmptyTuple) } } -impl From<()> for Value { - fn from((): ()) -> Self { - Self::EmptyTuple +impl TryFrom for Value { + type Error = rune_alloc::Error; + + #[inline] + fn try_from(kind: ValueKind) -> Result { + Ok(Self { + inner: Shared::new(kind)?, + }) } } impl ToValue for Value { + #[inline] fn to_value(self) -> VmResult { VmResult::Ok(self) } @@ -2062,41 +2054,34 @@ impl ToValue for Value { macro_rules! impl_from { ($($variant:ident => $ty:ty),* $(,)*) => { $( - impl From<$ty> for Value { + impl TryFrom<$ty> for Value { + type Error = rune_alloc::Error; + #[inline] - fn from(value: $ty) -> Self { - Self::$variant(value) + fn try_from(value: $ty) -> Result { + Value::try_from(ValueKind::$variant(value)) } } impl ToValue for $ty { #[inline] fn to_value(self) -> VmResult { - VmResult::Ok(Value::from(self)) + VmResult::Ok(vm_try!(Value::try_from(self))) } } )* }; } -macro_rules! impl_from_wrapper { - ($($variant:ident => $wrapper:ident<$ty:ty>),* $(,)?) => { - impl_from!($($variant => $wrapper<$ty>),*); - +macro_rules! impl_custom_from_wrapper { + ($($variant:ident => $ty:ty),* $(,)?) => { $( impl TryFrom<$ty> for Value { type Error = rune_alloc::Error; #[inline] fn try_from(value: $ty) -> Result { - Ok(Self::$variant($wrapper::new(value)?)) - } - } - - impl ToValue for $ty { - #[inline] - fn to_value(self) -> VmResult { - VmResult::Ok(vm_try!(Value::try_from(self))) + Value::try_from(ValueKind::$variant(value)) } } )* @@ -2110,35 +2095,36 @@ impl_from! { Integer => i64, Float => f64, Type => Type, - Option => Shared>, - Result => Shared>, + Ordering => Ordering, + String => String, + Bytes => Bytes, + ControlFlow => ControlFlow, + Function => Function, + Iterator => Iterator, + GeneratorState => GeneratorState, + Vec => Vec, + EmptyStruct => EmptyStruct, + TupleStruct => TupleStruct, + Struct => Struct, + Variant => Variant, + Object => Object, + Tuple => OwnedTuple, + Generator => Generator, + Format => Format, + RangeFrom => RangeFrom, + RangeFull => RangeFull, + RangeInclusive => RangeInclusive, + RangeToInclusive => RangeToInclusive, + RangeTo => RangeTo, + Range => Range, + Future => Future, + Stream => Stream, + Any => AnyObj, } -impl_from_wrapper! { - Format => Shared, - Iterator => Shared, - Bytes => Shared, - String => Shared, - Vec => Shared, - Tuple => Shared, - Object => Shared, - RangeFrom => Shared, - RangeFull => Shared, - RangeInclusive => Shared, - RangeToInclusive => Shared, - RangeTo => Shared, - Range => Shared, - ControlFlow => Shared, - Future => Shared, - Stream => Shared>, - Generator => Shared>, - GeneratorState => Shared, - EmptyStruct => Shared, - TupleStruct => Shared, - Struct => Shared, - Variant => Shared, - Function => Shared, - Any => Shared, +impl_custom_from_wrapper! { + Option => Option, + Result => Result, } impl MaybeTypeOf for Value { @@ -2155,16 +2141,242 @@ impl TryClone for Value { } } +/// Wrapper for a value kind. +#[doc(hidden)] +pub struct NotTypedValueKind(ValueKind); + +/// The coersion of a value into a typed value. +#[doc(hidden)] +#[non_exhaustive] +pub enum TypeValue { + /// The unit value. + EmptyTuple, + /// A tuple. + Tuple(OwnedTuple), + /// An object. + Object(Object), + /// An struct with a well-defined type. + EmptyStruct(EmptyStruct), + /// A tuple with a well-defined type. + TupleStruct(TupleStruct), + /// An struct with a well-defined type. + Struct(Struct), + /// The variant of an enum. + Variant(Variant), + /// Not a typed value. + #[doc(hidden)] + NotTyped(NotTypedValueKind), +} + +impl TypeValue { + /// Get the type info of the current value. + #[doc(hidden)] + pub fn type_info(&self) -> TypeInfo { + match self { + TypeValue::EmptyTuple => TypeInfo::StaticType(crate::runtime::static_type::TUPLE_TYPE), + TypeValue::Tuple(..) => TypeInfo::StaticType(crate::runtime::static_type::TUPLE_TYPE), + TypeValue::Object(..) => TypeInfo::StaticType(crate::runtime::static_type::OBJECT_TYPE), + TypeValue::EmptyStruct(empty) => empty.type_info(), + TypeValue::TupleStruct(tuple) => tuple.type_info(), + TypeValue::Struct(object) => object.type_info(), + TypeValue::Variant(empty) => empty.type_info(), + TypeValue::NotTyped(kind) => kind.0.type_info(), + } + } +} + +#[doc(hidden)] +#[non_exhaustive] +pub(crate) enum ValueKind { + /// The unit value. + EmptyTuple, + /// A boolean. + Bool(bool), + /// A single byte. + Byte(u8), + /// A character. + Char(char), + /// A number. + Integer(i64), + /// A float. + Float(f64), + /// A type hash. Describes a type in the virtual machine. + Type(Type), + /// Ordering. + Ordering(Ordering), + /// A UTF-8 string. + String(String), + /// A byte string. + Bytes(Bytes), + /// A vector containing any values. + Vec(Vec), + /// A tuple. + Tuple(OwnedTuple), + /// An object. + Object(Object), + /// A range `start..` + RangeFrom(RangeFrom), + /// A full range `..` + RangeFull(RangeFull), + /// A full range `start..=end` + RangeInclusive(RangeInclusive), + /// A full range `..=end` + RangeToInclusive(RangeToInclusive), + /// A full range `..end` + RangeTo(RangeTo), + /// A range `start..end`. + Range(Range), + /// A control flow indicator. + ControlFlow(ControlFlow), + /// A stored future. + Future(Future), + /// A Stream. + Stream(Stream), + /// A stored generator. + Generator(Generator), + /// Generator state. + GeneratorState(GeneratorState), + /// An empty value indicating nothing. + Option(Option), + /// A stored result in a slot. + Result(Result), + /// An struct with a well-defined type. + EmptyStruct(EmptyStruct), + /// A tuple with a well-defined type. + TupleStruct(TupleStruct), + /// An struct with a well-defined type. + Struct(Struct), + /// The variant of an enum. + Variant(Variant), + /// A stored function pointer. + Function(Function), + /// A value being formatted. + Format(Format), + /// An iterator. + Iterator(Iterator), + /// An opaque value that can be downcasted. + Any(AnyObj), +} + +impl ValueKind { + pub(crate) fn type_info(&self) -> TypeInfo { + match self { + ValueKind::Bool(..) => TypeInfo::StaticType(crate::runtime::static_type::BOOL_TYPE), + ValueKind::Byte(..) => TypeInfo::StaticType(crate::runtime::static_type::BYTE_TYPE), + ValueKind::Char(..) => TypeInfo::StaticType(crate::runtime::static_type::CHAR_TYPE), + ValueKind::Integer(..) => { + TypeInfo::StaticType(crate::runtime::static_type::INTEGER_TYPE) + } + ValueKind::Float(..) => TypeInfo::StaticType(crate::runtime::static_type::FLOAT_TYPE), + ValueKind::Type(..) => TypeInfo::StaticType(crate::runtime::static_type::TYPE), + ValueKind::Ordering(..) => { + TypeInfo::StaticType(crate::runtime::static_type::ORDERING_TYPE) + } + ValueKind::String(..) => TypeInfo::StaticType(crate::runtime::static_type::STRING_TYPE), + ValueKind::Bytes(..) => TypeInfo::StaticType(crate::runtime::static_type::BYTES_TYPE), + ValueKind::Vec(..) => TypeInfo::StaticType(crate::runtime::static_type::VEC_TYPE), + ValueKind::EmptyTuple => TypeInfo::StaticType(crate::runtime::static_type::TUPLE_TYPE), + ValueKind::Tuple(..) => TypeInfo::StaticType(crate::runtime::static_type::TUPLE_TYPE), + ValueKind::Object(..) => TypeInfo::StaticType(crate::runtime::static_type::OBJECT_TYPE), + ValueKind::RangeFrom(..) => { + TypeInfo::StaticType(crate::runtime::static_type::RANGE_FROM_TYPE) + } + ValueKind::RangeFull(..) => { + TypeInfo::StaticType(crate::runtime::static_type::RANGE_FULL_TYPE) + } + ValueKind::RangeInclusive(..) => { + TypeInfo::StaticType(crate::runtime::static_type::RANGE_INCLUSIVE_TYPE) + } + ValueKind::RangeToInclusive(..) => { + TypeInfo::StaticType(crate::runtime::static_type::RANGE_TO_INCLUSIVE_TYPE) + } + ValueKind::RangeTo(..) => { + TypeInfo::StaticType(crate::runtime::static_type::RANGE_TO_TYPE) + } + ValueKind::Range(..) => TypeInfo::StaticType(crate::runtime::static_type::RANGE_TYPE), + ValueKind::ControlFlow(..) => { + TypeInfo::StaticType(crate::runtime::static_type::CONTROL_FLOW_TYPE) + } + ValueKind::Future(..) => TypeInfo::StaticType(crate::runtime::static_type::FUTURE_TYPE), + ValueKind::Stream(..) => TypeInfo::StaticType(crate::runtime::static_type::STREAM_TYPE), + ValueKind::Generator(..) => { + TypeInfo::StaticType(crate::runtime::static_type::GENERATOR_TYPE) + } + ValueKind::GeneratorState(..) => { + TypeInfo::StaticType(crate::runtime::static_type::GENERATOR_STATE_TYPE) + } + ValueKind::Option(..) => TypeInfo::StaticType(crate::runtime::static_type::OPTION_TYPE), + ValueKind::Result(..) => TypeInfo::StaticType(crate::runtime::static_type::RESULT_TYPE), + ValueKind::Function(..) => { + TypeInfo::StaticType(crate::runtime::static_type::FUNCTION_TYPE) + } + ValueKind::Format(..) => TypeInfo::StaticType(crate::runtime::static_type::FORMAT_TYPE), + ValueKind::Iterator(..) => { + TypeInfo::StaticType(crate::runtime::static_type::ITERATOR_TYPE) + } + ValueKind::EmptyStruct(empty) => empty.type_info(), + ValueKind::TupleStruct(tuple) => tuple.type_info(), + ValueKind::Struct(object) => object.type_info(), + ValueKind::Variant(empty) => empty.type_info(), + ValueKind::Any(any) => any.type_info(), + } + } + + /// Get the type hash for the current value. + /// + /// One notable feature is that the type of a variant is its container + /// *enum*, and not the type hash of the variant itself. + pub(crate) fn type_hash(&self) -> Hash { + match self { + ValueKind::Bool(..) => crate::runtime::static_type::BOOL_TYPE.hash, + ValueKind::Byte(..) => crate::runtime::static_type::BYTE_TYPE.hash, + ValueKind::Char(..) => crate::runtime::static_type::CHAR_TYPE.hash, + ValueKind::Integer(..) => crate::runtime::static_type::INTEGER_TYPE.hash, + ValueKind::Float(..) => crate::runtime::static_type::FLOAT_TYPE.hash, + ValueKind::Type(..) => crate::runtime::static_type::TYPE.hash, + ValueKind::Ordering(..) => crate::runtime::static_type::ORDERING_TYPE.hash, + ValueKind::String(..) => crate::runtime::static_type::STRING_TYPE.hash, + ValueKind::Bytes(..) => crate::runtime::static_type::BYTES_TYPE.hash, + ValueKind::Vec(..) => crate::runtime::static_type::VEC_TYPE.hash, + ValueKind::EmptyTuple => crate::runtime::static_type::TUPLE_TYPE.hash, + ValueKind::Tuple(..) => crate::runtime::static_type::TUPLE_TYPE.hash, + ValueKind::Object(..) => crate::runtime::static_type::OBJECT_TYPE.hash, + ValueKind::RangeFrom(..) => crate::runtime::static_type::RANGE_FROM_TYPE.hash, + ValueKind::RangeFull(..) => crate::runtime::static_type::RANGE_FULL_TYPE.hash, + ValueKind::RangeInclusive(..) => crate::runtime::static_type::RANGE_INCLUSIVE_TYPE.hash, + ValueKind::RangeToInclusive(..) => { + crate::runtime::static_type::RANGE_TO_INCLUSIVE_TYPE.hash + } + ValueKind::RangeTo(..) => crate::runtime::static_type::RANGE_TO_TYPE.hash, + ValueKind::Range(..) => crate::runtime::static_type::RANGE_TYPE.hash, + ValueKind::ControlFlow(..) => crate::runtime::static_type::CONTROL_FLOW_TYPE.hash, + ValueKind::Future(..) => crate::runtime::static_type::FUTURE_TYPE.hash, + ValueKind::Stream(..) => crate::runtime::static_type::STREAM_TYPE.hash, + ValueKind::Generator(..) => crate::runtime::static_type::GENERATOR_TYPE.hash, + ValueKind::GeneratorState(..) => crate::runtime::static_type::GENERATOR_STATE_TYPE.hash, + ValueKind::Result(..) => crate::runtime::static_type::RESULT_TYPE.hash, + ValueKind::Option(..) => crate::runtime::static_type::OPTION_TYPE.hash, + ValueKind::Function(..) => crate::runtime::static_type::FUNCTION_TYPE.hash, + ValueKind::Format(..) => crate::runtime::static_type::FORMAT_TYPE.hash, + ValueKind::Iterator(..) => crate::runtime::static_type::ITERATOR_TYPE.hash, + ValueKind::EmptyStruct(empty) => empty.rtti.hash, + ValueKind::TupleStruct(tuple) => tuple.rtti.hash, + ValueKind::Struct(object) => object.rtti.hash, + ValueKind::Variant(variant) => variant.rtti().enum_hash, + ValueKind::Any(any) => any.type_hash(), + } + } +} + #[cfg(test)] mod tests { use super::Value; #[test] fn test_size() { - // :( - make this 16 bytes again by reducing the size of the Rc. assert_eq! { std::mem::size_of::(), - 16, + std::mem::size_of::(), }; } } diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index 9f2f3f551..08377c9e2 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -2,10 +2,10 @@ use core::fmt; use crate::alloc; use crate::alloc::prelude::*; -use crate::runtime::{Bytes, Object, Shared, Vec}; +use crate::runtime::{Bytes, Object, ValueKind, Vec}; -use serde::de::{self, Deserialize as _, Error}; -use serde::ser::{self, SerializeMap as _, SerializeSeq as _}; +use serde::de::{self, Deserialize as _, Error as _}; +use serde::ser::{self, Error as _, SerializeMap as _, SerializeSeq as _}; use super::Value; @@ -25,35 +25,27 @@ impl ser::Serialize for Value { where S: ser::Serializer, { - match self { - Value::Bool(b) => serializer.serialize_bool(*b), - Value::Char(c) => serializer.serialize_char(*c), - Value::Byte(c) => serializer.serialize_u8(*c), - Value::Integer(integer) => serializer.serialize_i64(*integer), - Value::Float(float) => serializer.serialize_f64(*float), - Value::Type(..) => Err(ser::Error::custom("cannot serialize types")), - Value::Ordering(..) => Err(ser::Error::custom("cannot serialize orderings")), - Value::String(string) => { - let string = string.borrow_ref().map_err(ser::Error::custom)?; - serializer.serialize_str(&string) - } - Value::Bytes(bytes) => { - let bytes = bytes.borrow_ref().map_err(ser::Error::custom)?; - serializer.serialize_bytes(&bytes) - } - Value::Vec(vec) => { - let vec = vec.borrow_ref().map_err(ser::Error::custom)?; + match &*self.borrow_kind_ref().map_err(S::Error::custom)? { + ValueKind::EmptyTuple => serializer.serialize_unit(), + ValueKind::Bool(b) => serializer.serialize_bool(*b), + ValueKind::Char(c) => serializer.serialize_char(*c), + ValueKind::Byte(c) => serializer.serialize_u8(*c), + ValueKind::Integer(integer) => serializer.serialize_i64(*integer), + ValueKind::Float(float) => serializer.serialize_f64(*float), + ValueKind::Type(..) => Err(ser::Error::custom("cannot serialize types")), + ValueKind::Ordering(..) => Err(ser::Error::custom("cannot serialize orderings")), + ValueKind::String(string) => serializer.serialize_str(string), + ValueKind::Bytes(bytes) => serializer.serialize_bytes(bytes), + ValueKind::Vec(vec) => { let mut serializer = serializer.serialize_seq(Some(vec.len()))?; - for value in &*vec { + for value in vec { serializer.serialize_element(value)?; } serializer.end() } - Value::EmptyTuple => serializer.serialize_unit(), - Value::Tuple(tuple) => { - let tuple = tuple.borrow_ref().map_err(ser::Error::custom)?; + ValueKind::Tuple(tuple) => { let mut serializer = serializer.serialize_seq(Some(tuple.len()))?; for value in tuple.iter() { @@ -62,48 +54,50 @@ impl ser::Serialize for Value { serializer.end() } - Value::Object(object) => { - let object = object.borrow_ref().map_err(ser::Error::custom)?; + ValueKind::Object(object) => { let mut serializer = serializer.serialize_map(Some(object.len()))?; - for (key, value) in &*object { + for (key, value) in object { serializer.serialize_entry(key, value)?; } serializer.end() } - Value::Option(option) => { - let option = option.borrow_ref().map_err(ser::Error::custom)?; - >::serialize(&*option, serializer) - } - Value::EmptyStruct(..) => serializer.serialize_unit(), - Value::TupleStruct(..) => Err(ser::Error::custom("cannot serialize tuple structs")), - Value::Struct(..) => Err(ser::Error::custom("cannot serialize objects structs")), - Value::Variant(..) => Err(ser::Error::custom("cannot serialize variants")), - Value::Result(..) => Err(ser::Error::custom("cannot serialize results")), - Value::Future(..) => Err(ser::Error::custom("cannot serialize futures")), - Value::Stream(..) => Err(ser::Error::custom("cannot serialize streams")), - Value::Generator(..) => Err(ser::Error::custom("cannot serialize generators")), - Value::GeneratorState(..) => { + ValueKind::Option(option) => >::serialize(option, serializer), + ValueKind::EmptyStruct(..) => Err(ser::Error::custom("cannot serialize empty structs")), + ValueKind::TupleStruct(..) => Err(ser::Error::custom("cannot serialize tuple structs")), + ValueKind::Struct(..) => Err(ser::Error::custom("cannot serialize objects structs")), + ValueKind::Variant(..) => Err(ser::Error::custom("cannot serialize variants")), + ValueKind::Result(..) => Err(ser::Error::custom("cannot serialize results")), + ValueKind::Future(..) => Err(ser::Error::custom("cannot serialize futures")), + ValueKind::Stream(..) => Err(ser::Error::custom("cannot serialize streams")), + ValueKind::Generator(..) => Err(ser::Error::custom("cannot serialize generators")), + ValueKind::GeneratorState(..) => { Err(ser::Error::custom("cannot serialize generator states")) } - Value::Function(..) => Err(ser::Error::custom("cannot serialize function pointers")), - Value::Format(..) => Err(ser::Error::custom("cannot serialize format specifications")), - Value::Iterator(..) => Err(ser::Error::custom("cannot serialize iterators")), - Value::RangeFrom(..) => Err(ser::Error::custom("cannot serialize `start..` ranges")), - Value::RangeFull(..) => Err(ser::Error::custom("cannot serialize `..` ranges")), - Value::RangeInclusive(..) => { + ValueKind::Function(..) => { + Err(ser::Error::custom("cannot serialize function pointers")) + } + ValueKind::Format(..) => { + Err(ser::Error::custom("cannot serialize format specifications")) + } + ValueKind::Iterator(..) => Err(ser::Error::custom("cannot serialize iterators")), + ValueKind::RangeFrom(..) => { + Err(ser::Error::custom("cannot serialize `start..` ranges")) + } + ValueKind::RangeFull(..) => Err(ser::Error::custom("cannot serialize `..` ranges")), + ValueKind::RangeInclusive(..) => { Err(ser::Error::custom("cannot serialize `start..=end` ranges")) } - Value::RangeToInclusive(..) => { + ValueKind::RangeToInclusive(..) => { Err(ser::Error::custom("cannot serialize `..=end` ranges")) } - Value::RangeTo(..) => Err(ser::Error::custom("cannot serialize `..end` ranges")), - Value::Range(..) => Err(ser::Error::custom("cannot serialize `start..end` ranges")), - Value::ControlFlow(..) => { + ValueKind::RangeTo(..) => Err(ser::Error::custom("cannot serialize `..end` ranges")), + ValueKind::Range(..) => Err(ser::Error::custom("cannot serialize `start..end` ranges")), + ValueKind::ControlFlow(..) => { Err(ser::Error::custom("cannot serialize `start..end` ranges")) } - Value::Any(..) => Err(ser::Error::custom("cannot serialize external objects")), + ValueKind::Any(..) => Err(ser::Error::custom("cannot serialize external objects")), } } } @@ -119,21 +113,21 @@ impl<'de> de::Visitor<'de> for VmVisitor { } #[inline] - fn visit_str(self, value: &str) -> Result + fn visit_str(self, v: &str) -> Result where E: de::Error, { - let value = value.try_to_owned().map_err(E::custom)?; - Ok(Value::String(Shared::new(value).map_err(E::custom)?)) + let v = v.try_to_owned().map_err(E::custom)?; + Value::try_from(v).map_err(E::custom) } #[inline] - fn visit_string(self, value: ::rust_alloc::string::String) -> Result + fn visit_string(self, v: ::rust_alloc::string::String) -> Result where E: de::Error, { - let value = alloc::String::try_from(value).map_err(E::custom)?; - Ok(Value::String(Shared::new(value).map_err(E::custom)?)) + let v = alloc::String::try_from(v).map_err(E::custom)?; + Value::try_from(v).map_err(E::custom) } #[inline] @@ -142,9 +136,8 @@ impl<'de> de::Visitor<'de> for VmVisitor { E: de::Error, { let v = alloc::Vec::try_from(v).map_err(E::custom)?; - Ok(Value::Bytes( - Shared::new(Bytes::from_vec(v)).map_err(E::custom)?, - )) + let v = Bytes::from_vec(v); + Value::try_from(v).map_err(E::custom) } #[inline] @@ -153,9 +146,8 @@ impl<'de> de::Visitor<'de> for VmVisitor { E: de::Error, { let v = alloc::Vec::try_from(v).map_err(E::custom)?; - Ok(Value::Bytes( - Shared::new(Bytes::from_vec(v)).map_err(E::custom)?, - )) + let v = Bytes::from_vec(v); + Value::try_from(v).map_err(E::custom) } #[inline] @@ -163,7 +155,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -171,7 +163,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -179,7 +171,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -187,7 +179,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v)) + Value::try_from(v).map_err(E::custom) } #[inline] @@ -195,7 +187,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -203,7 +195,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -211,7 +203,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -219,7 +211,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -227,7 +219,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -235,7 +227,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Integer(v as i64)) + Value::try_from(v as i64).map_err(E::custom) } #[inline] @@ -243,7 +235,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Float(v as f64)) + Value::try_from(v as f64).map_err(E::custom) } #[inline] @@ -251,7 +243,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Float(v)) + Value::try_from(v).map_err(E::custom) } #[inline] @@ -259,7 +251,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Bool(v)) + Value::try_from(v).map_err(E::custom) } #[inline] @@ -267,9 +259,8 @@ impl<'de> de::Visitor<'de> for VmVisitor { where D: serde::Deserializer<'de>, { - let option = - Shared::new(Some(Value::deserialize(deserializer)?)).map_err(D::Error::custom)?; - Ok(Value::Option(option)) + let some = Some(Value::deserialize(deserializer)?); + Value::try_from(some).map_err(D::Error::custom) } #[inline] @@ -277,7 +268,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::Option(Shared::new(None).map_err(E::custom)?)) + Value::try_from(None).map_err(E::custom) } #[inline] @@ -285,7 +276,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { - Ok(Value::EmptyTuple) + Value::empty().map_err(E::custom) } #[inline] @@ -303,9 +294,8 @@ impl<'de> de::Visitor<'de> for VmVisitor { vec.try_push(elem).map_err(V::Error::custom)?; } - Ok(Value::Vec( - Shared::new(Vec::from(vec)).map_err(V::Error::custom)?, - )) + let vec = Vec::from(vec); + Value::try_from(vec).map_err(V::Error::custom) } #[inline] @@ -319,8 +309,6 @@ impl<'de> de::Visitor<'de> for VmVisitor { object.insert(key, value).map_err(V::Error::custom)?; } - Ok(Value::Object( - Shared::new(object).map_err(V::Error::custom)?, - )) + Value::try_from(object).map_err(V::Error::custom) } } diff --git a/crates/rune/src/runtime/variant.rs b/crates/rune/src/runtime/variant.rs index 749e27152..19ddecd19 100644 --- a/crates/rune/src/runtime/variant.rs +++ b/crates/rune/src/runtime/variant.rs @@ -1,12 +1,16 @@ use core::cmp::Ordering; use core::fmt; +use ::rust_alloc::sync::Arc; + +use crate as rune; +use crate::alloc::clone::TryClone; use crate::runtime::{ Object, OwnedTuple, ProtocolCaller, TypeInfo, Value, VariantRtti, Vec, VmResult, }; -use ::rust_alloc::sync::Arc; /// The variant of a type. +#[derive(TryClone)] pub struct Variant { pub(crate) rtti: Arc, pub(crate) data: VariantData, @@ -155,6 +159,7 @@ impl Variant { } /// The data of the variant. +#[derive(TryClone)] pub enum VariantData { /// A unit variant. Empty, diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs index 36578ac9d..f831d2244 100644 --- a/crates/rune/src/runtime/vec.rs +++ b/crates/rune/src/runtime/vec.rs @@ -14,8 +14,8 @@ use crate::alloc::prelude::*; #[cfg(feature = "alloc")] use crate::runtime::Hasher; use crate::runtime::{ - Formatter, FromValue, Iterator, ProtocolCaller, RawRef, Ref, Shared, ToValue, UnsafeToRef, - Value, VmErrorKind, VmResult, + Formatter, FromValue, Iterator, ProtocolCaller, RawRef, Ref, ToValue, UnsafeToRef, Value, + ValueKind, VmErrorKind, VmResult, }; use crate::Any; @@ -40,7 +40,8 @@ use self::iter::Iter; /// ``` #[derive(Any)] #[repr(transparent)] -#[rune(builtin, static_type = VEC_TYPE, from_value = Value::into_vec)] +#[rune(builtin, static_type = VEC_TYPE)] +#[rune(from_value = Value::into_vec, from_value_ref = Value::into_vec_ref, from_value_mut = Value::into_vec_mut)] pub struct Vec { inner: alloc::Vec, } @@ -94,8 +95,9 @@ impl Vec { /// let mut v = Vec::new(); /// assert!(v.is_empty()); /// - /// v.push(Value::Integer(1)); + /// v.push(rune::to_value(1u32)?); /// assert!(!v.is_empty()); + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn is_empty(&self) -> bool { self.inner.is_empty() @@ -334,44 +336,41 @@ impl Vec { /// This is a common get implementation that can be used across linear /// types, such as vectors and tuples. pub(crate) fn index_get(this: &[Value], index: Value) -> VmResult> { - let slice = match index { - Value::RangeFrom(range) => { - let range = vm_try!(range.borrow_ref()); - let start = vm_try!(range.start.as_usize()); - this.get(start..) - } - Value::RangeFull(..) => this.get(..), - Value::RangeInclusive(range) => { - let range = vm_try!(range.borrow_ref()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); - this.get(start..=end) - } - Value::RangeToInclusive(range) => { - let range = vm_try!(range.borrow_ref()); - let end = vm_try!(range.end.as_usize()); - this.get(..=end) - } - Value::RangeTo(range) => { - let range = vm_try!(range.borrow_ref()); - let end = vm_try!(range.end.as_usize()); - this.get(..end) - } - Value::Range(range) => { - let range = vm_try!(range.borrow_ref()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); - this.get(start..end) - } - value => { - let index = vm_try!(usize::from_value(value)); + let slice: Option<&[Value]> = 'out: { + match &*vm_try!(index.borrow_kind_ref()) { + ValueKind::RangeFrom(range) => { + let start = vm_try!(range.start.as_usize()); + break 'out this.get(start..); + } + ValueKind::RangeFull(..) => break 'out this.get(..), + ValueKind::RangeInclusive(range) => { + let start = vm_try!(range.start.as_usize()); + let end = vm_try!(range.end.as_usize()); + break 'out this.get(start..=end); + } + ValueKind::RangeToInclusive(range) => { + let end = vm_try!(range.end.as_usize()); + break 'out this.get(..=end); + } + ValueKind::RangeTo(range) => { + let end = vm_try!(range.end.as_usize()); + break 'out this.get(..end); + } + ValueKind::Range(range) => { + let start = vm_try!(range.start.as_usize()); + let end = vm_try!(range.end.as_usize()); + break 'out this.get(start..end); + } + _ => {} + }; - let Some(value) = this.get(index) else { - return VmResult::Ok(None); - }; + let index = vm_try!(usize::from_value(index)); - return VmResult::Ok(Some(value.clone())); - } + let Some(value) = this.get(index) else { + return VmResult::Ok(None); + }; + + return VmResult::Ok(Some(value.clone())); }; let Some(values) = slice else { @@ -496,7 +495,6 @@ where { fn from_value(value: Value) -> VmResult { let vec = vm_try!(value.into_vec()); - let vec = vm_try!(vec.take()); let mut output = ::rust_alloc::vec::Vec::with_capacity(vec.len()); @@ -514,7 +512,6 @@ where { fn from_value(value: Value) -> VmResult { let vec = vm_try!(value.into_vec()); - let vec = vm_try!(vec.take()); let mut output = vm_try!(alloc::Vec::try_with_capacity(vec.len())); @@ -530,8 +527,8 @@ impl UnsafeToRef for [Value] { type Guard = RawRef; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let vec = vm_try!(value.into_vec()); - let (vec, guard) = Ref::into_raw(vm_try!(vec.into_ref())); + let vec = vm_try!(value.into_vec_ref()); + let (vec, guard) = Ref::into_raw(vec); // SAFETY: we're holding onto the guard for the vector here, so it is // live. VmResult::Ok((vec.as_ref().as_slice(), guard)) @@ -549,7 +546,7 @@ where vm_try!(inner.try_push(vm_try!(value.to_value()))); } - VmResult::Ok(Value::from(vm_try!(Shared::new(Vec { inner })))) + VmResult::Ok(vm_try!(Value::try_from(Vec { inner }))) } } @@ -565,6 +562,6 @@ where vm_try!(inner.try_push(vm_try!(value.to_value()))); } - VmResult::Ok(Value::from(vm_try!(Shared::new(Vec { inner })))) + VmResult::Ok(vm_try!(Value::try_from(Vec { inner }))) } } diff --git a/crates/rune/src/runtime/vec_tuple.rs b/crates/rune/src/runtime/vec_tuple.rs index 04f6c01df..bb8787952 100644 --- a/crates/rune/src/runtime/vec_tuple.rs +++ b/crates/rune/src/runtime/vec_tuple.rs @@ -27,7 +27,7 @@ macro_rules! impl_from_value_tuple_vec { $($ty: FromValue,)* { fn from_value(value: Value) -> VmResult { - let vec = vm_try!(vm_try!(value.into_vec()).into_ref()); + let vec = vm_try!(value.into_vec_ref()); let [$($var,)*] = vec.as_slice() else { return VmResult::err(VmErrorKind::ExpectedTupleLength { diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index 3572ced2c..64bf0b5b8 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -17,7 +17,7 @@ use crate::runtime::{ Formatter, FromValue, Function, Future, Generator, GuardedArgs, Inst, InstAddress, InstAssignOp, InstOp, InstRange, InstTarget, InstValue, InstVariant, Object, OwnedTuple, Panic, Protocol, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, - RuntimeContext, Select, Shared, Stack, Stream, Struct, Type, TypeCheck, TypeOf, Unit, Value, + RuntimeContext, Select, Stack, Stream, Struct, Type, TypeCheck, TypeOf, Unit, Value, ValueKind, Variant, VariantData, Vec, VmError, VmErrorKind, VmExecution, VmHalt, VmIntegerRepr, VmResult, VmSendExecution, }; @@ -244,7 +244,7 @@ impl Vm { /// // Looking up an item from the source. /// let dynamic_max = vm.lookup_function(["max"])?; /// - /// let value: i64 = rune::from_value(dynamic_max.call((10, 20)).into_result()?)?; + /// let value: i64 = dynamic_max.call::((10, 20)).into_result()?; /// assert_eq!(value, 20); /// /// // Building an item buffer to lookup an `::std` item. @@ -254,7 +254,7 @@ impl Vm { /// /// let max = vm.lookup_function(&item)?; /// - /// let value: i64 = rune::from_value(max.call((10, 20)).into_result()?)?; + /// let value: i64 = max.call::((10, 20)).into_result()?; /// assert_eq!(value, 20); /// # Ok::<_, rune::support::Error>(()) /// ``` @@ -348,7 +348,7 @@ impl Vm { { self.set_entrypoint(name, args.count())?; args.into_stack(&mut self.stack).into_result()?; - Result::Ok(VmExecution::new(self)) + Ok(VmExecution::new(self)) } /// An `execute` variant that returns an execution which implements @@ -368,7 +368,7 @@ impl Vm { self.set_entrypoint(name, args.count())?; args.into_stack(&mut self.stack).into_result()?; - Result::Ok(VmSendExecution(VmExecution::new(self))) + Ok(VmSendExecution(VmExecution::new(self))) } /// Call the given function immediately, returning the produced value. @@ -385,11 +385,11 @@ impl Vm { /// /// [`Mut`]: crate::runtime::Mut /// [`Ref`]: crate::runtime::Ref - pub fn call(&mut self, name: N, args: A) -> Result - where - N: ToTypeHash, - A: GuardedArgs, - { + pub fn call( + &mut self, + name: impl ToTypeHash, + args: impl GuardedArgs, + ) -> Result { self.set_entrypoint(name, args.count())?; // Safety: We hold onto the guard until the vm has completed and @@ -408,7 +408,7 @@ impl Vm { // reference of the value. We should prevent it from being possible to // take any owned references to values held by this. drop(guard); - Result::Ok(value) + Ok(value) } /// Call the given function immediately asynchronously, returning the @@ -452,7 +452,7 @@ impl Vm { // reference of the value. We should prevent it from being possible to // take any owned references to values held by this. drop(guard); - Result::Ok(value) + Ok(value) } /// Update the instruction pointer to match the function matching the given @@ -587,8 +587,6 @@ impl Vm { fn internal_boolean_ops( &mut self, - int_op: fn(i64, i64) -> bool, - float_op: fn(f64, f64) -> bool, match_ordering: fn(Ordering) -> bool, lhs: InstAddress, rhs: InstAddress, @@ -596,20 +594,12 @@ impl Vm { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); - let out = match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => int_op(lhs, rhs), - (Value::Float(lhs), Value::Float(rhs)) => float_op(lhs, rhs), - (lhs, rhs) => { - let ordering = vm_try!(Value::partial_cmp_with(&lhs, &rhs, self)); - - match ordering { - Some(ordering) => match_ordering(ordering), - None => false, - } - } + let out = match vm_try!(Value::partial_cmp_with(&lhs, &rhs, self)) { + Some(ordering) => match_ordering(ordering), + None => false, }; - vm_try!(self.stack.push(Value::from(out))); + vm_try!(self.stack.push(out)); VmResult::Ok(()) } @@ -673,85 +663,68 @@ impl Vm { /// Implementation of getting a string index on an object-like type. fn try_object_like_index_get(target: &Value, field: &str) -> VmResult> { - let value = match &target { - Value::Object(target) => vm_try!(target.borrow_ref()).get(field).cloned(), - Value::Struct(target) => vm_try!(target.borrow_ref()).get(field).cloned(), - Value::Variant(variant) => match vm_try!(variant.borrow_ref()).data() { - VariantData::Struct(target) => target.get(field).cloned(), + let target = vm_try!(target.borrow_kind_ref()); + + let value = match &*target { + ValueKind::Object(ref target) => target.get(field), + ValueKind::Struct(ref target) => target.get(field), + ValueKind::Variant(ref variant) => match variant.data() { + VariantData::Struct(target) => target.get(field), _ => return VmResult::Ok(None), }, _ => return VmResult::Ok(None), }; - let value = match value { - Some(value) => value, - None => { - return err(VmErrorKind::MissingField { - target: vm_try!(target.type_info()), - field: vm_try!(field.try_to_owned()), - }); - } + let Some(value) = value else { + return err(VmErrorKind::MissingField { + target: target.type_info(), + field: vm_try!(field.try_to_owned()), + }); }; - VmResult::Ok(Some(value)) + VmResult::Ok(Some(value.clone())) } /// Implementation of getting a string index on an object-like type. fn try_tuple_like_index_get(target: &Value, index: usize) -> VmResult> { - let value = match target { - Value::EmptyTuple => None, - Value::Tuple(tuple) => vm_try!(tuple.borrow_ref()).get(index).cloned(), - Value::Vec(vec) => vm_try!(vec.borrow_ref()).get(index).cloned(), - Value::Result(result) => { - let result = vm_try!(result.borrow_ref()); - - match &*result { - Result::Ok(value) if index == 0 => Some(value.clone()), - Result::Err(value) if index == 0 => Some(value.clone()), - _ => None, - } - } - Value::Option(option) => { - let option = vm_try!(option.borrow_ref()); - - match &*option { - Some(value) if index == 0 => Some(value.clone()), - _ => None, - } - } - Value::GeneratorState(state) => { - use crate::runtime::GeneratorState::*; - let state = vm_try!(state.borrow_ref()); - - match &*state { - Yielded(value) if index == 0 => Some(value.clone()), - Complete(value) if index == 0 => Some(value.clone()), - _ => None, - } - } - Value::TupleStruct(tuple_struct) => { - let tuple_struct = vm_try!(tuple_struct.borrow_ref()); - tuple_struct.data().get(index).cloned() - } - Value::Variant(variant) => { - let variant = vm_try!(variant.borrow_ref()); - - match variant.data() { - VariantData::Tuple(tuple) => tuple.get(index).cloned(), - _ => return VmResult::Ok(None), - } - } + use crate::runtime::GeneratorState::*; + + let target = vm_try!(target.borrow_kind_ref()); + + let value = match &*target { + ValueKind::EmptyTuple => None, + ValueKind::Tuple(tuple) => tuple.get(index), + ValueKind::Vec(vec) => vec.get(index), + ValueKind::Result(result) => match (index, result) { + (0, Ok(value)) => Some(value), + (0, Err(value)) => Some(value), + _ => None, + }, + ValueKind::Option(option) => match (index, option) { + (0, Some(value)) => Some(value), + _ => None, + }, + ValueKind::GeneratorState(state) => match (index, state) { + (0, Yielded(value)) => Some(value), + (0, Complete(value)) => Some(value), + _ => None, + }, + ValueKind::TupleStruct(tuple_struct) => tuple_struct.data().get(index), + ValueKind::Variant(variant) => match variant.data() { + VariantData::Tuple(tuple) => tuple.get(index), + _ => return VmResult::Ok(None), + }, _ => return VmResult::Ok(None), }; let Some(value) = value else { return err(VmErrorKind::MissingIndexInteger { - target: vm_try!(target.type_info()), + target: target.type_info(), index: VmIntegerRepr::from(index), }); }; - VmResult::Ok(Some(value)) + VmResult::Ok(Some(value.clone())) } /// Implementation of getting a mutable value out of a tuple-like value. @@ -759,69 +732,54 @@ impl Vm { target: &Value, index: usize, ) -> VmResult>> { - let value = match target { - Value::EmptyTuple => None, - Value::Tuple(tuple) => { - let tuple = vm_try!(tuple.borrow_mut()); - - BorrowMut::try_map(tuple, |tuple| tuple.get_mut(index)) - } - Value::Vec(vec) => { - let vec = vm_try!(vec.borrow_mut()); - - BorrowMut::try_map(vec, |vec| vec.get_mut(index)) - } - Value::Result(result) => { - let result = vm_try!(result.borrow_mut()); - - BorrowMut::try_map(result, |result| match result { - Result::Ok(value) if index == 0 => Some(value), - Result::Err(value) if index == 0 => Some(value), - _ => None, - }) - } - Value::Option(option) => { - let option = vm_try!(option.borrow_mut()); - - BorrowMut::try_map(option, |option| match option { - Some(value) if index == 0 => Some(value), - _ => None, - }) - } - Value::GeneratorState(state) => { - use crate::runtime::GeneratorState::*; - let state = vm_try!(state.borrow_mut()); - - BorrowMut::try_map(state, |state| match state { - Yielded(value) if index == 0 => Some(value), - Complete(value) if index == 0 => Some(value), - _ => None, - }) + use crate::runtime::GeneratorState::*; + + let mut unsupported = false; + + let result = BorrowMut::try_map(vm_try!(target.borrow_kind_mut()), |kind| { + match kind { + ValueKind::Tuple(tuple) => return tuple.get_mut(index), + ValueKind::Vec(vec) => return vec.get_mut(index), + ValueKind::Result(result) => match (index, result) { + (0, Ok(value)) => return Some(value), + (0, Err(value)) => return Some(value), + _ => {} + }, + ValueKind::Option(option) => { + if let (0, Some(value)) = (index, option) { + return Some(value); + } + } + ValueKind::GeneratorState(state) => match (index, state) { + (0, Yielded(value)) => return Some(value), + (0, Complete(value)) => return Some(value), + _ => {} + }, + ValueKind::TupleStruct(tuple_struct) => return tuple_struct.get_mut(index), + ValueKind::Variant(Variant { + data: VariantData::Tuple(tuple), + .. + }) => { + return tuple.get_mut(index); + } + _ => {} } - Value::TupleStruct(tuple_struct) => { - let tuple_struct = vm_try!(tuple_struct.borrow_mut()); - BorrowMut::try_map(tuple_struct, |tuple_struct| tuple_struct.get_mut(index)) - } - Value::Variant(variant) => { - let variant = vm_try!(variant.borrow_mut()); + unsupported = true; + None + }); - BorrowMut::try_map(variant, |variant| match variant.data_mut() { - VariantData::Tuple(tuple) => tuple.get_mut(index), - _ => None, - }) - } - _ => return VmResult::Ok(None), - }; + if unsupported { + return VmResult::Ok(None); + } - let Some(value) = value else { - return err(VmErrorKind::MissingIndexInteger { - target: vm_try!(target.type_info()), + match result { + Ok(value) => VmResult::Ok(Some(value)), + Err(actual) => err(VmErrorKind::MissingIndexInteger { + target: actual.type_info(), index: VmIntegerRepr::from(index), - }); - }; - - VmResult::Ok(Some(value)) + }), + } } /// Implementation of getting a mutable string index on an object-like type. @@ -829,44 +787,47 @@ impl Vm { target: &'a Value, field: &str, ) -> VmResult>> { - let value = match &target { - Value::Object(target) => { - let target = vm_try!(target.borrow_mut()); - BorrowMut::try_map(target, |target| target.get_mut(field)) - } - Value::Struct(target) => { - let target = vm_try!(target.borrow_mut()); - BorrowMut::try_map(target, |target| target.get_mut(field)) - } - Value::Variant(target) => BorrowMut::try_map(vm_try!(target.borrow_mut()), |target| { - match target.data_mut() { - VariantData::Struct(st) => st.get_mut(field), - _ => None, - } - }), - _ => return VmResult::Ok(None), - }; + let mut unsupported = false; - let value = match value { - Some(value) => value, - None => { - return err(VmErrorKind::MissingField { - target: vm_try!(target.type_info()), - field: vm_try!(field.try_to_owned()), - }); + let result = BorrowMut::try_map(vm_try!(target.borrow_kind_mut()), |kind| { + match kind { + ValueKind::Object(target) => { + return target.get_mut(field); + } + ValueKind::Struct(target) => { + return target.get_mut(field); + } + ValueKind::Variant(Variant { + data: VariantData::Struct(st), + .. + }) => { + return st.get_mut(field); + } + _ => {} } - }; - VmResult::Ok(Some(value)) + unsupported = true; + None + }); + + if unsupported { + return VmResult::Ok(None); + } + + match result { + Ok(value) => VmResult::Ok(Some(value)), + Err(actual) => err(VmErrorKind::MissingField { + target: actual.type_info(), + field: vm_try!(field.try_to_owned()), + }), + } } /// Implementation of getting a string index on an object-like type. fn try_tuple_like_index_set(target: &Value, index: usize, value: Value) -> VmResult { - match target { - Value::EmptyTuple => VmResult::Ok(false), - Value::Tuple(tuple) => { - let mut tuple = vm_try!(tuple.borrow_mut()); - + match &mut *vm_try!(target.borrow_kind_mut()) { + ValueKind::EmptyTuple => VmResult::Ok(false), + ValueKind::Tuple(tuple) => { if let Some(target) = tuple.get_mut(index) { *target = value; return VmResult::Ok(true); @@ -874,9 +835,7 @@ impl Vm { VmResult::Ok(false) } - Value::Vec(vec) => { - let mut vec = vm_try!(vec.borrow_mut()); - + ValueKind::Vec(vec) => { if let Some(target) = vec.get_mut(index) { *target = value; return VmResult::Ok(true); @@ -884,22 +843,18 @@ impl Vm { VmResult::Ok(false) } - Value::Result(result) => { - let mut result = vm_try!(result.borrow_mut()); - - let target = match &mut *result { - Result::Ok(ok) if index == 0 => ok, - Result::Err(err) if index == 1 => err, + ValueKind::Result(result) => { + let target = match result { + Ok(ok) if index == 0 => ok, + Err(err) if index == 1 => err, _ => return VmResult::Ok(false), }; *target = value; VmResult::Ok(true) } - Value::Option(option) => { - let mut option = vm_try!(option.borrow_mut()); - - let target = match &mut *option { + ValueKind::Option(option) => { + let target = match option { Some(some) if index == 0 => some, _ => return VmResult::Ok(false), }; @@ -907,9 +862,7 @@ impl Vm { *target = value; VmResult::Ok(true) } - Value::TupleStruct(tuple_struct) => { - let mut tuple_struct = vm_try!(tuple_struct.borrow_mut()); - + ValueKind::TupleStruct(tuple_struct) => { if let Some(target) = tuple_struct.get_mut(index) { *target = value; return VmResult::Ok(true); @@ -917,9 +870,7 @@ impl Vm { VmResult::Ok(false) } - Value::Variant(variant) => { - let mut variant = vm_try!(variant.borrow_mut()); - + ValueKind::Variant(variant) => { if let VariantData::Tuple(data) = variant.data_mut() { if let Some(target) = data.get_mut(index) { *target = value; @@ -941,43 +892,42 @@ impl Vm { ) -> VmResult> { let index = vm_try!(self.unit.lookup_string(string_slot)); - match target { - Value::Object(object) => { - let object = vm_try!(object.borrow_ref()); - - if let Some(value) = object.get(index.as_str()) { - return VmResult::Ok(CallResult::Ok(value.clone())); + 'out: { + match &*vm_try!(target.borrow_kind_ref()) { + ValueKind::Object(object) => { + if let Some(value) = object.get(index.as_str()) { + return VmResult::Ok(CallResult::Ok(value.clone())); + } } - } - Value::Struct(typed_object) => { - let typed_object = vm_try!(typed_object.borrow_ref()); - - if let Some(value) = typed_object.get(index.as_str()) { - return VmResult::Ok(CallResult::Ok(value.clone())); + ValueKind::Struct(typed_object) => { + if let Some(value) = typed_object.get(index.as_str()) { + return VmResult::Ok(CallResult::Ok(value.clone())); + } } - } - Value::Variant(variant) => { - let variant = vm_try!(variant.borrow_ref()); - - if let VariantData::Struct(data) = variant.data() { + ValueKind::Variant(Variant { + data: VariantData::Struct(data), + .. + }) => { if let Some(value) = data.get(index.as_str()) { return VmResult::Ok(CallResult::Ok(value.clone())); } } + _ => { + break 'out; + } } - target => { - let hash = index.hash(); - return VmResult::Ok( - match vm_try!(self.call_field_fn(Protocol::GET, target, hash, ())) { - CallResult::Ok(()) => CallResult::Ok(vm_try!(self.stack.pop())), - CallResult::Unsupported(target) => CallResult::Unsupported(target), - }, - ); - } - } + return err(VmErrorKind::ObjectIndexMissing { slot: string_slot }); + }; - err(VmErrorKind::ObjectIndexMissing { slot: string_slot }) + let hash = index.hash(); + + VmResult::Ok( + match vm_try!(self.call_field_fn(Protocol::GET, target, hash, ())) { + CallResult::Ok(()) => CallResult::Ok(vm_try!(self.stack.pop())), + CallResult::Unsupported(target) => CallResult::Unsupported(target), + }, + ) } fn try_object_slot_index_set( @@ -988,16 +938,13 @@ impl Vm { ) -> VmResult> { let field = vm_try!(self.unit.lookup_string(string_slot)); - VmResult::Ok(match target { - Value::Object(object) => { - let mut object = vm_try!(object.borrow_mut()); + match &mut *vm_try!(target.borrow_kind_mut()) { + ValueKind::Object(object) => { let key = vm_try!(field.as_str().try_to_owned()); vm_try!(object.insert(key, value)); return VmResult::Ok(CallResult::Ok(())); } - Value::Struct(typed_object) => { - let mut typed_object = vm_try!(typed_object.borrow_mut()); - + ValueKind::Struct(typed_object) => { if let Some(v) = typed_object.get_mut(field.as_str()) { *v = value; return VmResult::Ok(CallResult::Ok(())); @@ -1008,9 +955,7 @@ impl Vm { field: vm_try!(field.as_str().try_to_owned()), }); } - Value::Variant(variant) => { - let mut variant = vm_try!(variant.borrow_mut()); - + ValueKind::Variant(variant) => { if let VariantData::Struct(data) = variant.data_mut() { if let Some(v) = data.get_mut(field.as_str()) { *v = value; @@ -1023,51 +968,44 @@ impl Vm { field: vm_try!(field.as_str().try_to_owned()), }); } - target => { - let hash = field.hash(); + _ => {} + } - match vm_try!(self.call_field_fn(Protocol::SET, target, hash, (value,))) { - CallResult::Ok(()) => { - vm_try!(<()>::from_value(vm_try!(self.stack.pop()))); - CallResult::Ok(()) - } - result => result, - } + let hash = field.hash(); + + let value = match vm_try!(self.call_field_fn(Protocol::SET, target, hash, (value,))) { + CallResult::Ok(()) => { + vm_try!(<()>::from_value(vm_try!(self.stack.pop()))); + CallResult::Ok(()) } - }) + result => result, + }; + + VmResult::Ok(value) } fn on_tuple(&mut self, ty: TypeCheck, value: &Value, f: F) -> VmResult> where F: FnOnce(&[Value]) -> O, { - VmResult::Ok(match (ty, value) { - (TypeCheck::EmptyTuple, Value::EmptyTuple) => Some(f(&[])), - (TypeCheck::Tuple, Value::Tuple(tuple)) => Some(f(&vm_try!(tuple.borrow_ref()))), - (TypeCheck::Vec, Value::Vec(vec)) => Some(f(&vm_try!(vec.borrow_ref()))), - (TypeCheck::Result(v), Value::Result(result)) => { - let result = vm_try!(result.borrow_ref()); - - Some(match (v, &*result) { - (0, Result::Ok(ok)) => f(slice::from_ref(ok)), - (1, Result::Err(err)) => f(slice::from_ref(err)), - _ => return VmResult::Ok(None), - }) - } - (TypeCheck::Option(v), Value::Option(option)) => { - let option = vm_try!(option.borrow_ref()); - - Some(match (v, &*option) { - (0, Some(some)) => f(slice::from_ref(some)), - (1, None) => f(&[]), - _ => return VmResult::Ok(None), - }) - } - (TypeCheck::GeneratorState(v), Value::GeneratorState(state)) => { - use crate::runtime::GeneratorState::*; - let state = vm_try!(state.borrow_ref()); - - Some(match (v, &*state) { + use crate::runtime::GeneratorState::*; + + VmResult::Ok(match (ty, &*vm_try!(value.borrow_kind_ref())) { + (TypeCheck::EmptyTuple, ValueKind::EmptyTuple) => Some(f(&[])), + (TypeCheck::Tuple, ValueKind::Tuple(tuple)) => Some(f(tuple)), + (TypeCheck::Vec, ValueKind::Vec(vec)) => Some(f(vec)), + (TypeCheck::Result(v), ValueKind::Result(result)) => Some(match (v, result) { + (0, Ok(ok)) => f(slice::from_ref(ok)), + (1, Err(err)) => f(slice::from_ref(err)), + _ => return VmResult::Ok(None), + }), + (TypeCheck::Option(v), ValueKind::Option(option)) => Some(match (v, option) { + (0, Some(some)) => f(slice::from_ref(some)), + (1, None) => f(&[]), + _ => return VmResult::Ok(None), + }), + (TypeCheck::GeneratorState(v), ValueKind::GeneratorState(state)) => { + Some(match (v, state) { (0, Complete(complete)) => f(slice::from_ref(complete)), (1, Yielded(yielded)) => f(slice::from_ref(yielded)), _ => return VmResult::Ok(None), @@ -1082,22 +1020,23 @@ impl Vm { let b = vm_try!(self.stack.address(rhs)); let a = vm_try!(self.stack.address(lhs)); - let ty = match b { - Value::Type(ty) => ty, - _ => { - return err(VmErrorKind::UnsupportedIs { - value: vm_try!(a.type_info()), - test_type: vm_try!(b.type_info()), - }); - } + let ValueKind::Type(ty) = *vm_try!(b.borrow_kind_ref()) else { + return err(VmErrorKind::UnsupportedIs { + value: vm_try!(a.type_info()), + test_type: vm_try!(b.type_info()), + }); }; macro_rules! convert { - ($from:ty, $value:ident, $ty:expr) => { + ($from:ty, $value:expr, $ty:expr) => { match $ty.into_hash() { - runtime::static_type::FLOAT_TYPE_HASH => Value::Float($value as f64), - runtime::static_type::BYTE_TYPE_HASH => Value::Byte($value as u8), - runtime::static_type::INTEGER_TYPE_HASH => Value::Integer($value as i64), + runtime::static_type::FLOAT_TYPE_HASH => { + vm_try!(Value::try_from($value as f64)) + } + runtime::static_type::BYTE_TYPE_HASH => vm_try!(Value::try_from($value as u8)), + runtime::static_type::INTEGER_TYPE_HASH => { + vm_try!(Value::try_from($value as i64)) + } ty => { return err(VmErrorKind::UnsupportedAs { value: <$from as TypeOf>::type_info(), @@ -1108,17 +1047,19 @@ impl Vm { }; } - VmResult::Ok(match a { - Value::Integer(a) => convert!(i64, a, ty), - Value::Float(a) => convert!(f64, a, ty), - Value::Byte(a) => convert!(u8, a, ty), - value => { + let value = match &*vm_try!(a.borrow_kind_ref()) { + ValueKind::Integer(a) => convert!(i64, *a, ty), + ValueKind::Float(a) => convert!(f64, *a, ty), + ValueKind::Byte(a) => convert!(u8, *a, ty), + kind => { return err(VmErrorKind::UnsupportedAs { - value: vm_try!(value.type_info()), + value: kind.type_info(), type_hash: ty.into_hash(), }); } - }) + }; + + VmResult::Ok(value) } /// Internal implementation of the instance check. @@ -1126,14 +1067,11 @@ impl Vm { let b = vm_try!(self.stack.address(rhs)); let a = vm_try!(self.stack.address(lhs)); - let ty = match b { - Value::Type(ty) => ty, - _ => { - return err(VmErrorKind::UnsupportedIs { - value: vm_try!(a.type_info()), - test_type: vm_try!(b.type_info()), - }); - } + let ValueKind::Type(ty) = *vm_try!(b.borrow_kind_ref()) else { + return err(VmErrorKind::UnsupportedIs { + value: vm_try!(a.type_info()), + test_type: vm_try!(b.type_info()), + }); }; VmResult::Ok(vm_try!(a.type_hash()) == ty.into_hash()) @@ -1149,18 +1087,21 @@ impl Vm { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); - let out = match (lhs, rhs) { - (Value::Bool(lhs), Value::Bool(rhs)) => bool_op(lhs, rhs), + let out = match ( + &*vm_try!(lhs.borrow_kind_ref()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Bool(lhs), ValueKind::Bool(rhs)) => bool_op(*lhs, *rhs), (lhs, rhs) => { return err(VmErrorKind::UnsupportedBinaryOperation { op, - lhs: vm_try!(lhs.type_info()), - rhs: vm_try!(rhs.type_info()), + lhs: lhs.type_info(), + rhs: rhs.type_info(), }); } }; - vm_try!(self.stack.push(Value::from(out))); + vm_try!(self.stack.push(out)); VmResult::Ok(()) } @@ -1169,7 +1110,7 @@ impl Vm { let stack = self.stack.drain(args)?.try_collect::()?; let mut vm = Self::with_stack(self.context.clone(), self.unit.clone(), stack); vm.ip = offset; - self.stack.push(Value::try_from(Generator::new(vm))?)?; + self.stack.push(Generator::new(vm))?; Ok(()) } @@ -1178,7 +1119,7 @@ impl Vm { let stack = self.stack.drain(args)?.try_collect::()?; let mut vm = Self::with_stack(self.context.clone(), self.unit.clone(), stack); vm.ip = offset; - self.stack.push(Value::try_from(Stream::new(vm))?)?; + self.stack.push(Stream::new(vm))?; Ok(()) } @@ -1189,7 +1130,7 @@ impl Vm { vm.ip = offset; let mut execution = vm.into_execution(); let future = Future::new(async move { execution.async_complete().await })?; - self.stack.push(Value::try_from(future)?)?; + self.stack.push(future)?; Ok(()) } @@ -1234,19 +1175,26 @@ impl Vm { let mut guard; let fallback = match target_value!(self, target, guard, lhs) { - TargetValue::Value(lhs, rhs) => match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => { - let out = vm_try!(integer_op(*lhs, rhs).ok_or_else(error)); - *lhs = out; - return VmResult::Ok(()); - } - (Value::Float(lhs), Value::Float(rhs)) => { - let out = float_op(*lhs, rhs); - *lhs = out; - return VmResult::Ok(()); + TargetValue::Value(lhs, rhs) => { + match ( + &mut *vm_try!(lhs.borrow_kind_mut()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Integer(lhs), ValueKind::Integer(rhs)) => { + let out = vm_try!(integer_op(*lhs, *rhs).ok_or_else(error)); + *lhs = out; + return VmResult::Ok(()); + } + (ValueKind::Float(lhs), ValueKind::Float(rhs)) => { + let out = float_op(*lhs, *rhs); + *lhs = out; + return VmResult::Ok(()); + } + _ => {} } - (lhs, rhs) => TargetFallback::Value(lhs.clone(), rhs), - }, + + TargetFallback::Value(lhs.clone(), rhs) + } TargetValue::Fallback(fallback) => fallback, }; @@ -1316,18 +1264,21 @@ impl Vm { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); - let (lhs, rhs) = match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => { + match ( + &*vm_try!(lhs.borrow_kind_ref()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Integer(lhs), ValueKind::Integer(rhs)) => { vm_try!(self .stack - .push(Value::from(vm_try!(integer_op(lhs, rhs).ok_or_else(error))))); + .push(vm_try!(integer_op(*lhs, *rhs).ok_or_else(error)))); return VmResult::Ok(()); } - (Value::Float(lhs), Value::Float(rhs)) => { - vm_try!(self.stack.push(Value::from(float_op(lhs, rhs)))); + (ValueKind::Float(lhs), ValueKind::Float(rhs)) => { + vm_try!(self.stack.push(float_op(*lhs, *rhs))); return VmResult::Ok(()); } - (lhs, rhs) => (lhs, rhs), + _ => {} }; if let CallResult::Unsupported(lhs) = vm_try!(self.call_instance_fn(lhs, protocol, (&rhs,))) @@ -1355,20 +1306,23 @@ impl Vm { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); - let (lhs, rhs) = match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => { - vm_try!(self.stack.push(Value::from(integer_op(lhs, rhs)))); + match ( + &*vm_try!(lhs.borrow_kind_ref()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Integer(lhs), ValueKind::Integer(rhs)) => { + vm_try!(self.stack.push(integer_op(*lhs, *rhs))); return VmResult::Ok(()); } - (Value::Byte(lhs), Value::Byte(rhs)) => { - vm_try!(self.stack.push(Value::from(byte_op(lhs, rhs)))); + (ValueKind::Byte(lhs), ValueKind::Byte(rhs)) => { + vm_try!(self.stack.push(byte_op(*lhs, *rhs))); return VmResult::Ok(()); } - (Value::Bool(lhs), Value::Bool(rhs)) => { - vm_try!(self.stack.push(Value::from(bool_op(lhs, rhs)))); + (ValueKind::Bool(lhs), ValueKind::Bool(rhs)) => { + vm_try!(self.stack.push(bool_op(*lhs, *rhs))); return VmResult::Ok(()); } - (lhs, rhs) => (lhs, rhs), + _ => {} }; if let CallResult::Unsupported(lhs) = vm_try!(self.call_instance_fn(lhs, protocol, (&rhs,))) @@ -1395,21 +1349,28 @@ impl Vm { let mut guard; let fallback = match target_value!(self, target, guard, lhs) { - TargetValue::Value(lhs, rhs) => match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => { - integer_op(lhs, rhs); - return VmResult::Ok(()); - } - (Value::Byte(lhs), Value::Byte(rhs)) => { - byte_op(lhs, rhs); - return VmResult::Ok(()); - } - (Value::Bool(lhs), Value::Bool(rhs)) => { - bool_op(lhs, rhs); - return VmResult::Ok(()); + TargetValue::Value(lhs, rhs) => { + match ( + &mut *vm_try!(lhs.borrow_kind_mut()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Integer(lhs), ValueKind::Integer(rhs)) => { + integer_op(lhs, *rhs); + return VmResult::Ok(()); + } + (ValueKind::Byte(lhs), ValueKind::Byte(rhs)) => { + byte_op(lhs, *rhs); + return VmResult::Ok(()); + } + (ValueKind::Bool(lhs), ValueKind::Bool(rhs)) => { + bool_op(lhs, *rhs); + return VmResult::Ok(()); + } + _ => {} } - (lhs, rhs) => TargetFallback::Value(lhs.clone(), rhs), - }, + + TargetFallback::Value(lhs.clone(), rhs) + } TargetValue::Fallback(fallback) => fallback, }; @@ -1428,19 +1389,22 @@ impl Vm { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); - let (lhs, rhs) = match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => { - let integer = vm_try!(integer_op(lhs, rhs).ok_or_else(error)); - vm_try!(self.stack.push(Value::from(integer))); + match ( + &*vm_try!(lhs.borrow_kind_ref()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Integer(lhs), ValueKind::Integer(rhs)) => { + let integer = vm_try!(integer_op(*lhs, *rhs).ok_or_else(error)); + vm_try!(self.stack.push(integer)); return VmResult::Ok(()); } - (Value::Byte(lhs), Value::Integer(rhs)) => { - let byte = vm_try!(byte_op(lhs, rhs).ok_or_else(error)); - vm_try!(self.stack.push(Value::from(byte))); + (ValueKind::Byte(lhs), ValueKind::Integer(rhs)) => { + let byte = vm_try!(byte_op(*lhs, *rhs).ok_or_else(error)); + vm_try!(self.stack.push(byte)); return VmResult::Ok(()); } - (lhs, rhs) => (lhs, rhs), - }; + _ => {} + } if let CallResult::Unsupported(lhs) = vm_try!(self.call_instance_fn(lhs, protocol, (&rhs,))) { @@ -1466,19 +1430,26 @@ impl Vm { let mut guard; let fallback = match target_value!(self, target, guard, lhs) { - TargetValue::Value(lhs, rhs) => match (lhs, rhs) { - (Value::Integer(lhs), Value::Integer(rhs)) => { - let out = vm_try!(integer_op(*lhs, rhs).ok_or_else(error)); - *lhs = out; - return VmResult::Ok(()); - } - (Value::Byte(lhs), Value::Integer(rhs)) => { - let out = vm_try!(byte_op(*lhs, rhs).ok_or_else(error)); - *lhs = out; - return VmResult::Ok(()); + TargetValue::Value(lhs, rhs) => { + match ( + &mut *vm_try!(lhs.borrow_kind_mut()), + &*vm_try!(rhs.borrow_kind_ref()), + ) { + (ValueKind::Integer(lhs), ValueKind::Integer(rhs)) => { + let out = vm_try!(integer_op(*lhs, *rhs).ok_or_else(error)); + *lhs = out; + return VmResult::Ok(()); + } + (ValueKind::Byte(lhs), ValueKind::Integer(rhs)) => { + let out = vm_try!(byte_op(*lhs, *rhs).ok_or_else(error)); + *lhs = out; + return VmResult::Ok(()); + } + _ => {} } - (lhs, rhs) => TargetFallback::Value(lhs.clone(), rhs), - }, + + TargetFallback::Value(lhs.clone(), rhs) + } TargetValue::Fallback(fallback) => fallback, }; @@ -1486,7 +1457,7 @@ impl Vm { } #[cfg_attr(feature = "bench", inline(never))] - fn op_await(&mut self) -> VmResult> { + fn op_await(&mut self) -> VmResult { vm_try!(self.stack.pop()).into_future() } @@ -1495,7 +1466,7 @@ impl Vm { let futures = futures_util::stream::FuturesUnordered::new(); for (branch, value) in vm_try!(self.stack.drain(len)).enumerate() { - let future = vm_try!(vm_try!(value.into_future()).into_mut()); + let future = vm_try!(value.into_future_mut()); if !future.is_completed() { futures.push(SelectFuture::new(branch, future)); @@ -1504,7 +1475,7 @@ impl Vm { // NB: nothing to poll. if futures.is_empty() { - vm_try!(self.stack.push(Value::from(()))); + vm_try!(self.stack.push(())); return VmResult::Ok(None); } @@ -1520,7 +1491,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_push(&mut self, value: InstValue) -> VmResult<()> { - vm_try!(self.stack.push(value.into_value())); + vm_try!(self.stack.push(vm_try!(value.into_value()))); VmResult::Ok(()) } @@ -1533,7 +1504,7 @@ impl Vm { /// pop-and-jump-if-not instruction. #[cfg_attr(feature = "bench", inline(never))] fn op_pop_and_jump_if_not(&mut self, count: usize, jump: usize) -> VmResult<()> { - if vm_try!(vm_try!(self.stack.pop()).into_bool()) { + if vm_try!(vm_try!(self.stack.pop()).as_bool()) { return VmResult::Ok(()); } @@ -1566,7 +1537,8 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_move(&mut self, offset: usize) -> VmResult<()> { let value = vm_try!(self.stack.at_offset(offset)).clone(); - vm_try!(self.stack.push(vm_try!(value.take()))); + let value = vm_try!(value.move_()); + vm_try!(self.stack.push(value)); VmResult::Ok(()) } @@ -1603,7 +1575,7 @@ impl Vm { /// Perform a conditional jump operation. #[cfg_attr(feature = "bench", inline(never))] fn op_jump_if(&mut self, jump: usize) -> VmResult<()> { - if vm_try!(vm_try!(self.stack.pop()).into_bool()) { + if vm_try!(vm_try!(self.stack.pop()).as_bool()) { self.ip = vm_try!(self.unit.translate(jump)); } @@ -1639,8 +1611,9 @@ impl Vm { /// Perform a branch-conditional jump operation. #[cfg_attr(feature = "bench", inline(never))] fn op_jump_if_branch(&mut self, branch: i64, jump: usize) -> VmResult<()> { - if let Some(Value::Integer(current)) = self.stack.peek() { - if *current == branch { + if let Some(current) = self.stack.peek() { + if matches!(*vm_try!(current.borrow_kind_ref()), ValueKind::Integer(current) if current == branch) + { self.ip = vm_try!(self.unit.translate(jump)); vm_try!(self.stack.pop()); } @@ -1652,12 +1625,8 @@ impl Vm { /// Construct a new vec. #[cfg_attr(feature = "bench", inline(never))] fn op_vec(&mut self, count: usize) -> VmResult<()> { - let vec = vm_try!(Vec::try_from(vm_try!(vm_try!(self - .stack - .pop_sequence(count))))); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(vm_try!(Shared::new(vec)))))); + let vec = vm_try!(vm_try!(self.stack.pop_sequence(count))); + vm_try!(self.stack.push(Vec::from(vec))); VmResult::Ok(()) } @@ -1665,29 +1634,31 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_tuple(&mut self, count: usize) -> VmResult<()> { let tuple = vm_try!(vm_try!(self.stack.pop_sequence(count))); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(vm_try!(OwnedTuple::try_from( - tuple - )))))); + let tuple = vm_try!(OwnedTuple::try_from(tuple)); + vm_try!(self.stack.push(tuple)); VmResult::Ok(()) } /// Construct a new tuple with a fixed number of arguments. #[cfg_attr(feature = "bench", inline(never))] fn op_tuple_n(&mut self, args: &[InstAddress]) -> VmResult<()> { - let mut tuple = vec![Value::EmptyTuple; args.len()]; + let mut tuple = vm_try!(alloc::Vec::::try_with_capacity(args.len())); - for (n, arg) in args.iter().enumerate().rev() { - tuple[n] = vm_try!(self.stack.address(*arg)); - } - - vm_try!(self - .stack - .push(vm_try!(Value::try_from(vm_try!(OwnedTuple::try_from( + // SAFETY: We've ensured that the allocated vector is in-bound with args. + unsafe { + // NB: Consumption order of args matter, since it might modify the + // stack. + for (n, &arg) in args.iter().enumerate().rev() { tuple - )))))); + .as_mut_ptr() + .add(n) + .write(vm_try!(self.stack.address(arg))); + } + tuple.set_len(args.len()); + } + + vm_try!(self.stack.push(vm_try!(OwnedTuple::try_from(tuple)))); VmResult::Ok(()) } @@ -1695,9 +1666,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_push_tuple(&mut self) -> VmResult<()> { let tuple = vm_try!(vm_try!(self.stack.pop()).into_tuple()); - vm_try!(self - .stack - .extend(vm_try!(tuple.borrow_ref()).iter().cloned())); + vm_try!(self.stack.extend(tuple.iter().cloned())); VmResult::Ok(()) } @@ -1705,12 +1674,12 @@ impl Vm { fn op_not(&mut self) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - let value = match value { - Value::Bool(value) => Value::from(!value), - Value::Integer(value) => Value::from(!value), - Value::Byte(value) => Value::from(!value), - other => { - let operand = vm_try!(other.type_info()); + let value = match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Bool(value) => vm_try!(Value::try_from(!value)), + ValueKind::Integer(value) => vm_try!(Value::try_from(!value)), + ValueKind::Byte(value) => vm_try!(Value::try_from(!value)), + ref other => { + let operand = other.type_info(); return err(VmErrorKind::UnsupportedUnaryOperation { op: "!", operand }); } }; @@ -1723,11 +1692,11 @@ impl Vm { fn op_neg(&mut self) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - let value = match value { - Value::Float(value) => Value::from(-value), - Value::Integer(value) => Value::from(-value), - other => { - let operand = vm_try!(other.type_info()); + let value = match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Float(value) => vm_try!(Value::try_from(-value)), + ValueKind::Integer(value) => vm_try!(Value::try_from(-value)), + ref other => { + let operand = other.type_info(); return err(VmErrorKind::UnsupportedUnaryOperation { op: "-", operand }); } }; @@ -1843,36 +1812,20 @@ impl Vm { )); } InstOp::Gt => { - vm_try!(self.internal_boolean_ops( - |a, b| a > b, - |a, b| a > b, - |o| matches!(o, Ordering::Greater), - lhs, - rhs - )); + vm_try!(self.internal_boolean_ops(|o| matches!(o, Ordering::Greater), lhs, rhs)); } InstOp::Gte => { vm_try!(self.internal_boolean_ops( - |a, b| a >= b, - |a, b| a >= b, |o| matches!(o, Ordering::Greater | Ordering::Equal), lhs, rhs )); } InstOp::Lt => { - vm_try!(self.internal_boolean_ops( - |a, b| a < b, - |a, b| a < b, - |o| matches!(o, Ordering::Less), - lhs, - rhs - )); + vm_try!(self.internal_boolean_ops(|o| matches!(o, Ordering::Less), lhs, rhs)); } InstOp::Lte => { vm_try!(self.internal_boolean_ops( - |a, b| a <= b, - |a, b| a <= b, |o| matches!(o, Ordering::Less | Ordering::Equal), lhs, rhs @@ -1882,13 +1835,13 @@ impl Vm { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); let test = vm_try!(Value::partial_eq_with(&lhs, &rhs, self)); - vm_try!(self.stack.push(Value::from(test))); + vm_try!(self.stack.push(test)); } InstOp::Neq => { let rhs = vm_try!(self.stack.address(rhs)); let lhs = vm_try!(self.stack.address(lhs)); let test = vm_try!(Value::partial_eq_with(&lhs, &rhs, self)); - vm_try!(self.stack.push(Value::from(!test))); + vm_try!(self.stack.push(!test)); } InstOp::And => { vm_try!(self.internal_boolean_op(|a, b| a && b, "&&", lhs, rhs)); @@ -1902,11 +1855,11 @@ impl Vm { } InstOp::Is => { let is_instance = vm_try!(self.test_is_instance(lhs, rhs)); - vm_try!(self.stack.push(Value::from(is_instance))); + vm_try!(self.stack.push(is_instance)); } InstOp::IsNot => { let is_instance = vm_try!(self.test_is_instance(lhs, rhs)); - vm_try!(self.stack.push(Value::from(!is_instance))); + vm_try!(self.stack.push(!is_instance)); } } @@ -2019,22 +1972,19 @@ impl Vm { let value = vm_try!(self.stack.pop()); 'out: { - let field = match &index { - Value::String(string) => vm_try!(string.borrow_ref()), + let kind = vm_try!(index.borrow_kind_ref()); + + let field = match *kind { + ValueKind::String(ref string) => string.as_str(), _ => break 'out, }; - let field = field.as_str(); - - match &target { - Value::Object(object) => { - let mut object = vm_try!(object.borrow_mut()); + match &mut *vm_try!(target.borrow_kind_mut()) { + ValueKind::Object(object) => { vm_try!(object.insert(vm_try!(field.try_to_owned()), value)); return VmResult::Ok(()); } - Value::Struct(typed_object) => { - let mut typed_object = vm_try!(typed_object.borrow_mut()); - + ValueKind::Struct(typed_object) => { if let Some(v) = typed_object.get_mut(field) { *v = value; return VmResult::Ok(()); @@ -2045,9 +1995,7 @@ impl Vm { field: vm_try!(field.try_to_owned()), }); } - Value::Variant(variant) => { - let mut variant = vm_try!(variant.borrow_mut()); - + ValueKind::Variant(variant) => { if let VariantData::Struct(st) = variant.data_mut() { if let Some(v) = st.get_mut(field) { *v = value; @@ -2159,7 +2107,7 @@ impl Vm { #[tracing::instrument(skip(self))] fn op_return_unit(&mut self) -> Result { let exit = self.pop_call_frame()?; - self.stack.push(Value::from(()))?; + self.stack.push(())?; Ok(exit) } @@ -2168,7 +2116,7 @@ impl Vm { let instance = self.stack.pop()?; let ty = instance.type_hash()?; let hash = Hash::associated_function(ty, hash); - self.stack.push(Value::Type(Type::new(hash)))?; + self.stack.push(ValueKind::Type(Type::new(hash)))?; Ok(()) } @@ -2178,20 +2126,17 @@ impl Vm { let index = vm_try!(self.stack.address(index)); let target = vm_try!(self.stack.address_ref(target)); - match &index { - Value::String(string) => { - let string_ref = vm_try!(string.borrow_ref()); - - if let Some(value) = vm_try!(Self::try_object_like_index_get( - &target, - string_ref.as_str() - )) { + match &*vm_try!(index.borrow_kind_ref()) { + ValueKind::String(index) => { + if let Some(value) = + vm_try!(Self::try_object_like_index_get(&target, index.as_str())) + { vm_try!(self.stack.push(value)); return VmResult::Ok(()); } } - Value::Integer(index) => { - let Ok(index) = (*index).try_into() else { + ValueKind::Integer(index) => { + let Ok(index) = usize::try_from(*index) else { return err(VmErrorKind::MissingIndexInteger { target: vm_try!(target.type_info()), index: VmIntegerRepr::from(*index), @@ -2288,10 +2233,10 @@ impl Vm { fn op_eq_bool(&mut self, boolean: bool) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - vm_try!(self.stack.push(Value::from(match value { - Value::Bool(actual) => actual == boolean, + vm_try!(self.stack.push(match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Bool(actual) => actual == boolean, _ => false, - }))); + })); VmResult::Ok(()) } @@ -2361,9 +2306,7 @@ impl Vm { vm_try!(object.insert(key, value)); } - vm_try!(self - .stack - .push(vm_try!(Value::try_from(vm_try!(Shared::new(object)))))); + vm_try!(self.stack.push(object)); VmResult::Ok(()) } @@ -2410,9 +2353,7 @@ impl Vm { .lookup_rtti(hash) .ok_or(VmErrorKind::MissingRtti { hash })); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(EmptyStruct { rtti: rtti.clone() })))); + vm_try!(self.stack.push(EmptyStruct { rtti: rtti.clone() })); VmResult::Ok(()) } @@ -2437,10 +2378,10 @@ impl Vm { vm_try!(data.insert(key, value)); } - vm_try!(self.stack.push(vm_try!(Value::try_from(Struct { + vm_try!(self.stack.push(Struct { rtti: rtti.clone(), data, - })))); + })); VmResult::Ok(()) } @@ -2453,9 +2394,7 @@ impl Vm { .lookup_variant_rtti(hash) .ok_or(VmErrorKind::MissingVariantRtti { hash })); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(Variant::unit(rtti.clone()))))); + vm_try!(self.stack.push(Variant::unit(rtti.clone()))); VmResult::Ok(()) } @@ -2480,21 +2419,14 @@ impl Vm { vm_try!(data.insert(key, value)); } - vm_try!(self.stack.push(vm_try!(Value::try_from(Variant::struct_( - rtti.clone(), - data - ))))); + vm_try!(self.stack.push(Variant::struct_(rtti.clone(), data))); VmResult::Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_string(&mut self, slot: usize) -> VmResult<()> { let string = vm_try!(self.unit.lookup_string(slot)); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(vm_try!(String::try_from( - string.as_str() - )))))); + vm_try!(self.stack.push(vm_try!(String::try_from(string.as_str())))); VmResult::Ok(()) } @@ -2503,9 +2435,7 @@ impl Vm { let bytes = vm_try!(alloc::Vec::::try_from(vm_try!(self .unit .lookup_bytes(slot)))); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(Bytes::from_vec(bytes))))); + vm_try!(self.stack.push(Bytes::from_vec(bytes))); VmResult::Ok(()) } @@ -2520,7 +2450,7 @@ impl Vm { vm_try!(value.string_display_with(&mut f, &mut *self)); } - vm_try!(self.stack.push(vm_try!(Value::try_from(f.string)))); + vm_try!(self.stack.push(f.string)); VmResult::Ok(()) } @@ -2528,18 +2458,14 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_format(&mut self, spec: FormatSpec) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - vm_try!(self - .stack - .push(vm_try!(Value::try_from(Format { value, spec })))); + vm_try!(self.stack.push(Format { value, spec })); VmResult::Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_is_unit(&mut self) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - vm_try!(self - .stack - .push(Value::from(matches!(value, Value::EmptyTuple)))); + vm_try!(self.stack.push(vm_try!(value.is_empty()))); VmResult::Ok(()) } @@ -2548,21 +2474,23 @@ impl Vm { fn op_try(&mut self, address: InstAddress, clean: usize, preserve: bool) -> VmResult { let value = vm_try!(self.stack.address(address)); - let result = match value { - Value::Result(result) => vm_try!(result::result_try(vm_try!(result.take()))), - Value::Option(option) => vm_try!(option::option_try(vm_try!(option.take()))), - value => { - if let CallResult::Unsupported(target) = - vm_try!(self.call_instance_fn(value, Protocol::TRY, ())) - { - return err(VmErrorKind::UnsupportedTryOperand { - actual: vm_try!(target.type_info()), - }); - } + let result = 'out: { + match &*vm_try!(value.borrow_kind_ref()) { + ValueKind::Result(result) => break 'out vm_try!(result::result_try(result)), + ValueKind::Option(option) => break 'out vm_try!(option::option_try(option)), + _ => {} + } - let value = vm_try!(self.stack.pop()); - vm_try!(ControlFlow::from_value(value)) + if let CallResult::Unsupported(target) = + vm_try!(self.call_instance_fn(value, Protocol::TRY, ())) + { + return err(VmErrorKind::UnsupportedTryOperand { + actual: vm_try!(target.type_info()), + }); } + + let value = vm_try!(self.stack.pop()); + vm_try!(ControlFlow::from_value(value)) }; match result { @@ -2583,10 +2511,10 @@ impl Vm { fn op_eq_byte(&mut self, byte: u8) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - vm_try!(self.stack.push(Value::from(match value { - Value::Byte(actual) => actual == byte, + vm_try!(self.stack.push(match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Byte(actual) => actual == byte, _ => false, - }))); + })); VmResult::Ok(()) } @@ -2595,10 +2523,10 @@ impl Vm { fn op_eq_character(&mut self, character: char) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - vm_try!(self.stack.push(Value::from(match value { - Value::Char(actual) => actual == character, + vm_try!(self.stack.push(match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Char(actual) => actual == character, _ => false, - }))); + })); VmResult::Ok(()) } @@ -2607,10 +2535,10 @@ impl Vm { fn op_eq_integer(&mut self, integer: i64) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - vm_try!(self.stack.push(Value::from(match value { - Value::Integer(actual) => actual == integer, + vm_try!(self.stack.push(match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Integer(actual) => actual == integer, _ => false, - }))); + })); VmResult::Ok(()) } @@ -2621,16 +2549,15 @@ impl Vm { fn op_eq_string(&mut self, slot: usize) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - let equal = match value { - Value::String(actual) => { + let equal = match *vm_try!(value.borrow_kind_ref()) { + ValueKind::String(ref actual) => { let string = vm_try!(self.unit.lookup_string(slot)); - let actual = vm_try!(actual.borrow_ref()); actual.as_str() == string.as_str() } _ => false, }; - vm_try!(self.stack.push(Value::Bool(equal))); + vm_try!(self.stack.push(equal)); VmResult::Ok(()) } @@ -2640,16 +2567,15 @@ impl Vm { fn op_eq_bytes(&mut self, slot: usize) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - let equal = match value { - Value::Bytes(actual) => { + let equal = match *vm_try!(value.borrow_kind_ref()) { + ValueKind::Bytes(ref actual) => { let bytes = vm_try!(self.unit.lookup_bytes(slot)); - let actual = vm_try!(actual.borrow_ref()); *actual == *bytes } _ => false, }; - vm_try!(self.stack.push(Value::Bool(equal))); + vm_try!(self.stack.push(equal)); VmResult::Ok(()) } @@ -2665,7 +2591,7 @@ impl Vm { } })); - vm_try!(self.stack.push(Value::Bool(result.unwrap_or_default()))); + vm_try!(self.stack.push(result.unwrap_or_default())); VmResult::Ok(()) } @@ -2673,7 +2599,7 @@ impl Vm { fn op_match_type(&mut self, hash: Hash) -> VmResult<()> { let value = vm_try!(self.stack.pop()); let is_match = vm_try!(value.type_hash()) == hash; - vm_try!(self.stack.push(Value::from(is_match))); + vm_try!(self.stack.push(is_match)); VmResult::Ok(()) } @@ -2686,67 +2612,58 @@ impl Vm { ) -> VmResult<()> { let value = vm_try!(self.stack.pop()); - let is_match = match &value { - Value::Variant(variant) => vm_try!(variant.borrow_ref()).rtti().hash == variant_hash, - Value::Any(any) => { - let hash = vm_try!(any.borrow_ref()).type_hash(); - - if hash == enum_hash { - match vm_try!(self.call_instance_fn(value, Protocol::IS_VARIANT, (index,))) { - CallResult::Ok(()) => vm_try!(vm_try!(self.stack.pop()).as_bool()), - CallResult::Unsupported(..) => false, + let is_match = 'out: { + match &*vm_try!(value.borrow_kind_ref()) { + ValueKind::Variant(variant) => { + break 'out variant.rtti().hash == variant_hash; + } + ValueKind::Any(any) => { + if any.type_hash() != enum_hash { + break 'out false; } - } else { - false } + _ => break 'out false, + } + + match vm_try!(self.call_instance_fn(value, Protocol::IS_VARIANT, (index,))) { + CallResult::Ok(()) => vm_try!(vm_try!(self.stack.pop()).as_bool()), + CallResult::Unsupported(..) => false, } - _ => false, }; - vm_try!(self.stack.push(Value::from(is_match))); + vm_try!(self.stack.push(is_match)); VmResult::Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_match_builtin(&mut self, type_check: TypeCheck) -> VmResult<()> { - let value = vm_try!(self.stack.pop()); - - let is_match = match (type_check, value) { - (TypeCheck::Tuple, Value::Tuple(..)) => true, - (TypeCheck::Vec, Value::Vec(..)) => true, - (TypeCheck::Result(v), Value::Result(result)) => { - let result = vm_try!(result.borrow_ref()); - - match (v, &*result) { - (0, Result::Ok(..)) => true, - (1, Result::Err(..)) => true, - _ => false, - } - } - (TypeCheck::Option(v), Value::Option(option)) => { - let option = vm_try!(option.borrow_ref()); + use crate::runtime::GeneratorState::*; - match (v, &*option) { - (0, Some(..)) => true, - (1, None) => true, - _ => false, - } - } - (TypeCheck::GeneratorState(v), Value::GeneratorState(state)) => { - use crate::runtime::GeneratorState::*; - let state = vm_try!(state.borrow_ref()); + let value = vm_try!(self.stack.pop()); - match (v, &*state) { - (0, Complete(..)) => true, - (1, Yielded(..)) => true, - _ => false, - } - } - (TypeCheck::EmptyTuple, Value::EmptyTuple) => true, + let is_match = match (type_check, &*vm_try!(value.borrow_kind_ref())) { + (TypeCheck::EmptyTuple, ValueKind::EmptyTuple) => true, + (TypeCheck::Tuple, ValueKind::Tuple(..)) => true, + (TypeCheck::Vec, ValueKind::Vec(..)) => true, + (TypeCheck::Result(v), ValueKind::Result(result)) => match (v, result) { + (0, Ok(..)) => true, + (1, Err(..)) => true, + _ => false, + }, + (TypeCheck::Option(v), ValueKind::Option(option)) => match (v, option) { + (0, Some(..)) => true, + (1, None) => true, + _ => false, + }, + (TypeCheck::GeneratorState(v), ValueKind::GeneratorState(state)) => match (v, state) { + (0, Complete(..)) => true, + (1, Yielded(..)) => true, + _ => false, + }, _ => false, }; - vm_try!(self.stack.push(Value::from(is_match))); + vm_try!(self.stack.push(is_match)); VmResult::Ok(()) } @@ -2772,20 +2689,19 @@ impl Vm { let value = vm_try!(self.stack.pop()); - let is_match = match value { - Value::Object(object) => { + let is_match = match &*vm_try!(value.borrow_kind_ref()) { + ValueKind::Object(object) => { let keys = vm_try!(self .unit .lookup_object_keys(slot) .ok_or(VmErrorKind::MissingStaticObjectKeys { slot })); - let object = vm_try!(object.borrow_ref()); - test(&object, keys, exact) + test(object, keys, exact) } _ => false, }; - vm_try!(self.stack.push(Value::from(is_match))); + vm_try!(self.stack.push(is_match)); VmResult::Ok(()) } @@ -2795,24 +2711,18 @@ impl Vm { match variant { InstVariant::Some => { let some = vm_try!(self.stack.pop()); - vm_try!(self - .stack - .push(Value::Option(vm_try!(Shared::new(Some(some)))))); + vm_try!(self.stack.push(Some(some))); } InstVariant::None => { - vm_try!(self.stack.push(Value::Option(vm_try!(Shared::new(None))))); + vm_try!(self.stack.push(None)); } InstVariant::Ok => { let some = vm_try!(self.stack.pop()); - vm_try!(self - .stack - .push(Value::Result(vm_try!(Shared::new(Result::Ok(some)))))); + vm_try!(self.stack.push(Ok(some))); } InstVariant::Err => { let some = vm_try!(self.stack.pop()); - vm_try!(self - .stack - .push(Value::Result(vm_try!(Shared::new(Result::Err(some)))))); + vm_try!(self.stack.push(Err(some))); } } @@ -2823,9 +2733,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_load_fn(&mut self, hash: Hash) -> VmResult<()> { let function = vm_try!(self.lookup_function_by_hash(hash)); - vm_try!(self - .stack - .push(Value::Function(vm_try!(Shared::new(function))))); + vm_try!(self.stack.push(function)); VmResult::Ok(()) } @@ -2855,9 +2763,7 @@ impl Vm { hash, ); - vm_try!(self - .stack - .push(Value::Function(vm_try!(Shared::new(function))))); + vm_try!(self.stack.push(function)); VmResult::Ok(()) } @@ -2982,14 +2888,13 @@ impl Vm { fn op_call_fn(&mut self, args: usize) -> VmResult> { let function = vm_try!(self.stack.pop()); - let ty = match function { - Value::Type(ty) => ty, - Value::Function(function) => { - let function = vm_try!(function.into_ref()); + let ty = match *vm_try!(function.borrow_kind_ref()) { + ValueKind::Type(ty) => ty, + ValueKind::Function(ref function) => { return function.call_with_vm(self, args); } - actual => { - let actual = vm_try!(actual.type_info()); + ref actual => { + let actual = actual.type_info(); return err(VmErrorKind::UnsupportedCallFn { actual }); } }; @@ -3002,21 +2907,17 @@ impl Vm { fn op_iter_next(&mut self, offset: usize, jump: usize) -> VmResult<()> { let value = vm_try!(self.stack.at_offset_mut(offset)); - let some = match value { - Value::Option(option) => { - let option = vm_try!(option.borrow_ref()).clone(); - - match option { - Some(some) => some, - None => { - self.ip = vm_try!(self.unit.translate(jump)); - return VmResult::Ok(()); - } + let some = match &*vm_try!(value.borrow_kind_ref()) { + ValueKind::Option(option) => match option { + Some(some) => some.clone(), + None => { + self.ip = vm_try!(self.unit.translate(jump)); + return VmResult::Ok(()); } - } - other => { + }, + actual => { return err(VmErrorKind::UnsupportedIterNextOperand { - actual: vm_try!(other.type_info()), + actual: actual.type_info(), }); } }; @@ -3030,7 +2931,7 @@ impl Vm { /// This allows for calling protocol function helpers like /// [Value::string_display] which requires access to a virtual machine. /// - /// ```,no_run + /// ```no_run /// use rune::{Context, Unit}; /// use rune::runtime::Formatter; /// use std::sync::Arc; @@ -3056,7 +2957,7 @@ impl Vm { /// vm.with(|| output.string_display(&mut f)).into_result()?; /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn with(&mut self, f: F) -> T + pub fn with(&self, f: F) -> T where F: FnOnce() -> T, { @@ -3313,7 +3214,7 @@ impl Vm { return VmResult::Ok(VmHalt::Yielded); } Inst::YieldUnit => { - vm_try!(self.stack.push(Value::EmptyTuple)); + vm_try!(self.stack.push(vm_try!(Value::empty()))); return VmResult::Ok(VmHalt::Yielded); } Inst::Variant { variant } => { @@ -3409,5 +3310,5 @@ fn check_args(args: usize, expected: usize) -> Result<(), VmErrorKind> { }); } - Result::Ok(()) + Ok(()) } diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index 48376acc3..f52d6dd85 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -11,8 +11,8 @@ use crate::compile::ItemBuf; use crate::hash::Hash; use crate::runtime::unit::{BadInstruction, BadJump}; use crate::runtime::{ - AccessError, BoxedPanic, CallFrame, ExecutionState, FullTypeOf, MaybeTypeOf, Panic, StackError, - TypeInfo, TypeOf, Unit, Vm, VmHaltInfo, + AccessError, AccessErrorKind, BoxedPanic, CallFrame, ExecutionState, FullTypeOf, MaybeTypeOf, + Panic, Protocol, StackError, TypeInfo, TypeOf, Unit, Vm, VmHaltInfo, }; /// Trait used to convert result types to [`VmResult`]. @@ -446,11 +446,103 @@ impl From for VmErrorKind { } } +/// An opaque simple runtime error. +#[derive(Debug, PartialEq)] +pub struct RuntimeError { + error: VmErrorKind, +} + +impl RuntimeError { + pub(crate) fn new(error: VmErrorKind) -> Self { + Self { error } + } + + pub(crate) fn into_vm_error_kind(self) -> VmErrorKind { + self.error + } + + /// Construct an expected error. + pub(crate) fn expected(actual: TypeInfo) -> Self + where + T: ?Sized + TypeOf, + { + Self::new(VmErrorKind::Expected { + expected: T::type_info(), + actual, + }) + } + + /// Construct an expected any error. + pub(crate) fn expected_any(actual: TypeInfo) -> Self { + Self::new(VmErrorKind::ExpectedAny { actual }) + } +} + +impl From for RuntimeError { + #[inline] + fn from(error: AccessError) -> Self { + Self { + error: VmErrorKind::from(error), + } + } +} + +impl From for RuntimeError { + #[inline] + fn from(error: AccessErrorKind) -> Self { + Self { + error: VmErrorKind::from(AccessError::from(error)), + } + } +} + +impl From for RuntimeError { + #[inline] + fn from(error: VmErrorKind) -> Self { + Self { error } + } +} + +impl fmt::Display for RuntimeError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.error.fmt(f) + } +} + +cfg_std! { + impl std::error::Error for RuntimeError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self.error { + VmErrorKind::AllocError { + error, + } => Some(error), + VmErrorKind::AccessError { + error, + } => Some(error), + VmErrorKind::StackError { + error, + } => Some(error), + VmErrorKind::BadInstruction { + error, + } => Some(error), + VmErrorKind::BadJump { + error, + } => Some(error), + _ => None, + } + } + } +} + /// The kind of error encountered. -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[non_exhaustive] #[doc(hidden)] pub(crate) enum VmErrorKind { + AllocError { + error: alloc::Error, + }, AccessError { error: AccessError, }, @@ -486,6 +578,10 @@ pub(crate) enum VmErrorKind { MissingContextFunction { hash: Hash, }, + MissingProtocolFunction { + protocol: Protocol, + instance: TypeInfo, + }, MissingInstanceFunction { hash: Hash, instance: TypeInfo, @@ -652,27 +748,25 @@ pub(crate) enum VmErrorKind { }, MissingCallFrame, IllegalFormat, - AllocError { - error: alloc::Error, - }, } impl fmt::Display for VmErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + VmErrorKind::AllocError { error } => error.fmt(f), VmErrorKind::AccessError { error } => { write!(f, "{error}") } - VmErrorKind::StackError { error } => write!(f, "Stack error: {error}",), + VmErrorKind::StackError { error } => write!(f, "{error}"), VmErrorKind::BadInstruction { error } => { write!(f, "{error}") } VmErrorKind::BadJump { error } => { write!(f, "{error}") } - VmErrorKind::Panic { reason } => write!(f, "Panicked: {reason}",), + VmErrorKind::Panic { reason } => write!(f, "Panicked: {reason}"), VmErrorKind::NoRunningVm {} => write!(f, "No running virtual machines"), - VmErrorKind::Halted { halt } => write!(f, "Halted for unexpected reason `{halt}`",), + VmErrorKind::Halted { halt } => write!(f, "Halted for unexpected reason `{halt}`"), VmErrorKind::Overflow {} => write!(f, "Numerical overflow"), VmErrorKind::Underflow {} => write!(f, "Numerical underflow"), VmErrorKind::DivideByZero {} => write!(f, "Division by zero"), @@ -688,6 +782,9 @@ impl fmt::Display for VmErrorKind { VmErrorKind::MissingContextFunction { hash } => { write!(f, "Missing context function with hash `{hash}`",) } + VmErrorKind::MissingProtocolFunction { protocol, instance } => { + write!(f, "Missing protocol function `{protocol}` for `{instance}`",) + } VmErrorKind::MissingInstanceFunction { hash, instance } => { write!(f, "Missing instance function `{hash}` for `{instance}`",) } @@ -819,7 +916,7 @@ impl fmt::Display for VmErrorKind { write!(f, "Cannot resume a generator that has completed") } VmErrorKind::FutureCompleted {} => write!(f, "Future already completed"), - VmErrorKind::MissingVariant { name } => write!(f, "No variant matching `{name}`",), + VmErrorKind::MissingVariant { name } => write!(f, "No variant matching `{name}`"), VmErrorKind::MissingField { target, field } => { write!(f, "Missing field `{field}` on `{target}`",) } @@ -857,11 +954,17 @@ impl fmt::Display for VmErrorKind { VmErrorKind::IllegalFormat => { write!(f, "Value cannot be formatted") } - VmErrorKind::AllocError { error } => error.fmt(f), } } } +impl From for VmErrorKind { + #[inline(always)] + fn from(value: RuntimeError) -> Self { + value.into_vm_error_kind() + } +} + impl From for VmErrorKind { #[inline(always)] fn from(error: Infallible) -> Self { @@ -915,12 +1018,12 @@ impl From for VmErrorKind { impl VmErrorKind { /// Bad argument. - pub fn bad_argument(arg: usize) -> Self { + pub(crate) fn bad_argument(arg: usize) -> Self { Self::BadArgument { arg } } /// Construct an expected error. - pub fn expected(actual: TypeInfo) -> Self + pub(crate) fn expected(actual: TypeInfo) -> Self where T: ?Sized + TypeOf, { @@ -929,15 +1032,10 @@ impl VmErrorKind { actual, } } - - /// Construct an expected any error. - pub fn expected_any(actual: TypeInfo) -> Self { - Self::ExpectedAny { actual } - } } /// A type-erased rust number. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct VmIntegerRepr(num::BigInt); impl From for VmIntegerRepr diff --git a/crates/rune/src/runtime/vm_execution.rs b/crates/rune/src/runtime/vm_execution.rs index 2f6f9ee28..1bda34f8f 100644 --- a/crates/rune/src/runtime/vm_execution.rs +++ b/crates/rune/src/runtime/vm_execution.rs @@ -4,6 +4,7 @@ use core::mem::{replace, take}; use ::rust_alloc::sync::Arc; +use crate::alloc::clone::TryClone; use crate::alloc::Vec; use crate::runtime::budget; use crate::runtime::{ @@ -16,9 +17,9 @@ use crate::shared::AssertSend; /// correctly interact with functions that yield (like generators and streams) /// by initially just calling the function, then by providing a value pushed /// onto the stack. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] #[non_exhaustive] -pub enum ExecutionState { +pub(crate) enum ExecutionState { /// The initial state of an execution. Initial, /// The resumed state of an execution. This expects a value to be pushed @@ -35,6 +36,8 @@ impl fmt::Display for ExecutionState { } } +#[derive(TryClone)] +#[try_clone(crate)] pub(crate) struct VmExecutionState { pub(crate) context: Option>, pub(crate) unit: Option>, @@ -198,7 +201,7 @@ where /// it while returning a unit from the current `yield`. pub async fn async_resume(&mut self) -> VmResult { if matches!(self.state, ExecutionState::Resumed) { - vm_try!(self.head.as_mut().stack_mut().push(Value::EmptyTuple)); + vm_try!(self.head.as_mut().stack_mut().push(vm_try!(Value::empty()))); } else { self.state = ExecutionState::Resumed; } @@ -264,7 +267,7 @@ where #[tracing::instrument(skip_all)] pub fn resume(&mut self) -> VmResult { if matches!(self.state, ExecutionState::Resumed) { - vm_try!(self.head.as_mut().stack_mut().push(Value::EmptyTuple)); + vm_try!(self.head.as_mut().stack_mut().push(vm_try!(Value::empty()))); } else { self.state = ExecutionState::Resumed; } @@ -457,3 +460,17 @@ impl VmSendExecution { unsafe { AssertSend::new(future) } } } + +impl TryClone for VmExecution +where + T: AsRef + AsMut + TryClone, +{ + #[inline] + fn try_clone(&self) -> Result { + Ok(Self { + head: self.head.try_clone()?, + state: self.state, + states: self.states.try_clone()?, + }) + } +} diff --git a/crates/rune/src/runtime/vm_halt.rs b/crates/rune/src/runtime/vm_halt.rs index b869d715f..05c8bf792 100644 --- a/crates/rune/src/runtime/vm_halt.rs +++ b/crates/rune/src/runtime/vm_halt.rs @@ -31,8 +31,8 @@ impl VmHalt { } /// The reason why the virtual machine execution stopped. -#[derive(Debug, Clone, Copy)] -pub enum VmHaltInfo { +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum VmHaltInfo { /// The virtual machine exited by running out of call frames. Exited, /// The virtual machine exited because it ran out of execution quota. diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index 5bb341ee7..24d7db9d9 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -14,9 +14,9 @@ pub(crate) mod prelude { pub(crate) use crate::module::InstallWith; pub(crate) use crate::parse; pub(crate) use crate::runtime::{ - self, AnyObj, AnyTypeInfo, Bytes, FullTypeOf, Function, MaybeTypeOf, Mut, Object, - OwnedTuple, Protocol, RawRef, RawStr, Ref, Shared, Stack, Tuple, TypeInfo, TypeOf, - UnsafeToRef, VecTuple, VmErrorKind, VmResult, + self, AnyTypeInfo, Bytes, FullTypeOf, Function, MaybeTypeOf, Mut, Object, OwnedTuple, + Protocol, RawRef, RawStr, Ref, Stack, Tuple, TypeInfo, TypeOf, UnsafeToRef, ValueKind, + VecTuple, VmErrorKind, VmResult, }; pub(crate) use crate::support::Result; pub(crate) use crate::tests::run; @@ -31,6 +31,8 @@ pub(crate) mod prelude { pub(crate) use ::rust_alloc::string::{String, ToString}; pub(crate) use ::rust_alloc::sync::Arc; pub(crate) use ::rust_alloc::vec::Vec; + + pub(crate) use anyhow::Context as AnyhowContext; } use core::fmt; diff --git a/crates/rune/src/tests/bug_344.rs b/crates/rune/src/tests/bug_344.rs index aa8406019..491f6a797 100644 --- a/crates/rune/src/tests/bug_344.rs +++ b/crates/rune/src/tests/bug_344.rs @@ -29,7 +29,7 @@ fn bug_344_function() -> Result<()> { let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; function(&mut stack, 1).into_result()?; - assert_eq!(stack.pop()?.into_integer().into_result()?, 42); + assert_eq!(stack.pop()?.as_integer()?, 42); return Ok(()); fn function(check: &GuardCheck) -> i64 { @@ -65,7 +65,7 @@ fn bug_344_inst_fn() -> Result<()> { stack.push(rune::to_value(GuardCheck::new())?)?; function(&mut stack, 2).into_result()?; - assert_eq!(stack.pop()?.into_integer().into_result()?, 42); + assert_eq!(stack.pop()?.as_integer()?, 42); Ok(()) } @@ -86,21 +86,12 @@ fn bug_344_async_function() -> Result<()> { let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; function(&mut stack, 1).into_result()?; - let future = stack.pop()?.into_future().into_result()?.take()?; - assert_eq!( - block_on(future) - .into_result()? - .into_integer() - .into_result()?, - 42 - ); + let future = stack.pop()?.into_future().into_result()?; + assert_eq!(block_on(future).into_result()?.as_integer()?, 42); return Ok(()); - async fn function(check: Shared) -> i64 { - check - .downcast_borrow_ref::() - .unwrap() - .ensure_not_dropped("async argument"); + async fn function(check: Ref) -> i64 { + check.ensure_not_dropped("async argument"); 42 } } @@ -132,14 +123,8 @@ fn bug_344_async_inst_fn() -> Result<()> { stack.push(rune::to_value(GuardCheck::new())?)?; function(&mut stack, 2).into_result()?; - let future = stack.pop()?.into_future().into_result()?.take()?; - assert_eq!( - block_on(future) - .into_result()? - .into_integer() - .into_result()?, - 42 - ); + let future = stack.pop()?.into_future().into_result()?; + assert_eq!(block_on(future).into_result()?.as_integer()?, 42); Ok(()) } @@ -213,7 +198,7 @@ impl UnsafeToRef for GuardCheck { type Guard = Guard; unsafe fn unsafe_to_ref<'a>(value: Value) -> VmResult<(&'a Self, Self::Guard)> { - let (output, guard) = vm_try!(value.into_any_ptr::()); + let (output, guard) = Ref::into_raw(vm_try!(value.into_any_ref::())); let guard = Guard { _guard: guard, diff --git a/crates/rune/src/tests/external_constructor.rs b/crates/rune/src/tests/external_constructor.rs index af10fcee9..1daff9c60 100644 --- a/crates/rune/src/tests/external_constructor.rs +++ b/crates/rune/src/tests/external_constructor.rs @@ -97,7 +97,7 @@ fn construct_struct() -> rune::support::Result<()> { headers: Headers, } - #[derive(Debug, Any, Clone, PartialEq, Eq)] + #[derive(Debug, Any, TryClone, PartialEq, Eq)] #[rune(constructor)] struct Headers { #[rune(get, set)] diff --git a/crates/rune/src/tests/external_generic.rs b/crates/rune/src/tests/external_generic.rs index 6b02291cc..a68f6b072 100644 --- a/crates/rune/src/tests/external_generic.rs +++ b/crates/rune/src/tests/external_generic.rs @@ -15,7 +15,7 @@ use rune::{Any, Context, ContextError, Diagnostics, Module, Sources, Vm}; #[rune(item = ::native_crate)] struct Generic where - T: 'static + Clone + Named + FromValue + ToValue + MaybeTypeOf + TypeOf, + T: 'static + TryClone + Named + FromValue + ToValue + MaybeTypeOf + TypeOf, { #[rune(get, set)] data: T, @@ -23,7 +23,7 @@ where impl Generic where - T: 'static + Clone + Copy + Named + FromValue + ToValue + MaybeTypeOf + TypeOf, + T: 'static + TryClone + Copy + Named + FromValue + ToValue + MaybeTypeOf + TypeOf, { fn get_value(&self) -> T { self.data diff --git a/crates/rune/src/tests/external_ops.rs b/crates/rune/src/tests/external_ops.rs index cba364987..4d9bb6e2f 100644 --- a/crates/rune/src/tests/external_ops.rs +++ b/crates/rune/src/tests/external_ops.rs @@ -74,7 +74,7 @@ fn assign_ops_struct() -> Result<()> { assert_eq!(foo.field, $expected, "{} != {} (field)", foo.field, $expected); assert_eq!(foo.derived, $expected, "{} != {} (derived)", foo.derived, $expected); assert_eq!(foo.custom, $expected, "{} != {} (custom)", foo.custom, $expected); - assert!(matches!(output, Value::EmptyTuple)); + assert!(matches!(output.take_kind().unwrap(), ValueKind::EmptyTuple)); } }}; } @@ -156,7 +156,7 @@ fn assign_ops_tuple() -> Result<()> { assert_eq!(foo.1, $expected, "{} != {} (field .1)", foo.1, $expected); assert_eq!(foo.2, $expected, "{} != {} (derived .2)", foo.2, $expected); assert_eq!(foo.3, $expected, "{} != {} (custom .3)", foo.3, $expected); - assert!(matches!(output, Value::EmptyTuple)); + assert!(matches!(output.take_kind().unwrap(), ValueKind::EmptyTuple)); } }}; } diff --git a/crates/rune/src/tests/getter_setter.rs b/crates/rune/src/tests/getter_setter.rs index 97fe2bf51..b2311c21b 100644 --- a/crates/rune/src/tests/getter_setter.rs +++ b/crates/rune/src/tests/getter_setter.rs @@ -41,6 +41,6 @@ fn test_getter_setter() -> Result<()> { assert_eq!(foo.number, 43); assert_eq!(foo.string, "Hello World"); - assert!(matches!(output, Value::EmptyTuple)); + assert!(matches!(output.take_kind().unwrap(), ValueKind::EmptyTuple)); Ok(()) } diff --git a/crates/rune/src/tests/reference_error.rs b/crates/rune/src/tests/reference_error.rs index 70ac9173d..c6f09e1c4 100644 --- a/crates/rune/src/tests/reference_error.rs +++ b/crates/rune/src/tests/reference_error.rs @@ -9,9 +9,8 @@ fn test_reference_error() -> Result<()> { value: i64, } - fn take_it(this: Shared) -> VmResult<()> { - // NB: this will error, since this is a reference. - let _ = vm_try!(this.into_ref()); + // NB: Calling this should error, since it's a mutable reference. + fn take_it(_: Ref) -> VmResult<()> { VmResult::Ok(()) } diff --git a/crates/rune/src/tests/unit_constants.rs b/crates/rune/src/tests/unit_constants.rs index b7b4fdbf9..7e018d9c6 100644 --- a/crates/rune/src/tests/unit_constants.rs +++ b/crates/rune/src/tests/unit_constants.rs @@ -14,12 +14,9 @@ fn test_get_const() -> Result<()> { assert_eq!( unit.constant(Hash::type_hash(["LEET"])) - .expect("successful lookup") - .try_clone()? - .into_value() - .expect("could not allocate value") - .into_integer() - .expect("the inner value"), + .context("missing constant")? + .as_value()? + .as_integer()?, 1337 ); Ok(()) @@ -43,12 +40,9 @@ fn test_get_const_re_export() -> Result<()> { assert_eq!( unit.constant(Hash::type_hash(["LEET"])) - .expect("successful lookup") - .try_clone()? - .into_value() - .expect("could not allocate value") - .into_integer() - .expect("the inner value"), + .context("missing constant")? + .as_value()? + .as_integer()?, 1337 ); Ok(()) @@ -71,10 +65,9 @@ fn test_get_const_nested() -> Result<()> { assert_eq!( unit.constant(Hash::type_hash(["inner", "LEET"])) .expect("successful lookup") - .try_clone()? - .into_value() + .as_value() .expect("could not allocate value") - .into_integer() + .as_integer() .expect("the inner value"), 1337 ); diff --git a/crates/rune/src/tests/vm_closures.rs b/crates/rune/src/tests/vm_closures.rs index f896f2070..90bd5f965 100644 --- a/crates/rune/src/tests/vm_closures.rs +++ b/crates/rune/src/tests/vm_closures.rs @@ -187,8 +187,8 @@ fn test_closure_in_lit_vec() -> VmResult<()> { let (start, first, second, end) = ret.0; assert_eq!(0, start); - assert_eq!(2, vm_try!(first.call::<_, i64>(()))); - assert_eq!(4, vm_try!(second.call::<_, i64>(()))); + assert_eq!(2, vm_try!(first.call::(()))); + assert_eq!(4, vm_try!(second.call::(()))); assert_eq!(3, end); VmResult::Ok(()) } @@ -201,8 +201,8 @@ fn test_closure_in_lit_tuple() -> VmResult<()> { let (start, first, second, end) = ret; assert_eq!(0, start); - assert_eq!(2, vm_try!(first.call::<_, i64>(()))); - assert_eq!(4, vm_try!(second.call::<_, i64>(()))); + assert_eq!(2, vm_try!(first.call::(()))); + assert_eq!(4, vm_try!(second.call::(()))); assert_eq!(3, end); VmResult::Ok(()) } @@ -222,8 +222,8 @@ fn test_closure_in_lit_object() -> Result<()> { }; assert_eq!(0, proxy.a); - assert_eq!(2, proxy.b.call::<_, i64>(()).into_result()?); - assert_eq!(4, proxy.c.call::<_, i64>(()).into_result()?); + assert_eq!(2, proxy.b.call::(()).into_result()?); + assert_eq!(4, proxy.c.call::(()).into_result()?); assert_eq!(3, proxy.d); Ok(()) } diff --git a/crates/rune/src/tests/vm_function.rs b/crates/rune/src/tests/vm_function.rs index fd75f3037..26a046536 100644 --- a/crates/rune/src/tests/vm_function.rs +++ b/crates/rune/src/tests/vm_function.rs @@ -13,8 +13,8 @@ fn test_function() { pub fn main() { foo } }; - assert_eq!(function.call::<_, i64>((1i64, 3i64)).unwrap(), 4i64); - assert!(function.call::<_, i64>((1i64,)).is_err()); + assert_eq!(function.call::((1i64, 3i64)).unwrap(), 4i64); + assert!(function.call::((1i64,)).is_err()); // ptr to native function let function: Function = rune!( @@ -32,9 +32,9 @@ fn test_function() { pub fn main() { Custom::A } }; - assert!(function.call::<_, Value>(()).into_result().is_err()); + assert!(function.call::(()).into_result().is_err()); let value: Value = function.call((1i64,)).unwrap(); - assert!(matches!(value, Value::Variant(..))); + assert!(matches!(value.take_kind().unwrap(), ValueKind::Variant(..))); // ptr to dynamic function. let function: Function = rune! { @@ -42,18 +42,21 @@ fn test_function() { pub fn main() { Custom } }; - assert!(function.call::<_, Value>(()).into_result().is_err()); + assert!(function.call::(()).into_result().is_err()); let value: Value = function.call((1i64,)).unwrap(); - assert!(matches!(value, Value::TupleStruct(..))); + assert!(matches!( + value.take_kind().unwrap(), + ValueKind::TupleStruct(..) + )); // non-capturing closure == free function let function: Function = rune! { pub fn main() { |a, b| a + b } }; - assert!(function.call::<_, Value>((1i64,)).into_result().is_err()); + assert!(function.call::((1i64,)).into_result().is_err()); let value: Value = function.call((1i64, 2i64)).unwrap(); - assert!(matches!(value, Value::Integer(3))); + assert!(matches!(value.take_kind().unwrap(), ValueKind::Integer(3))); // closure with captures let function: Function = run( @@ -64,7 +67,7 @@ fn test_function() { ) .unwrap(); - assert!(function.call::<_, Value>((1i64,)).into_result().is_err()); + assert!(function.call::((1i64,)).into_result().is_err()); let value: Value = function.call(()).unwrap(); - assert!(matches!(value, Value::Integer(3))); + assert!(matches!(value.take_kind().unwrap(), ValueKind::Integer(3))); } diff --git a/examples/examples/object.rs b/examples/examples/object.rs index 1df4e1dbd..098ca72ec 100644 --- a/examples/examples/object.rs +++ b/examples/examples/object.rs @@ -1,7 +1,7 @@ use rune::alloc; use rune::runtime::Object; use rune::termcolor::{ColorChoice, StandardStream}; -use rune::{Diagnostics, Value, Vm}; +use rune::{Diagnostics, Vm}; use std::sync::Arc; @@ -36,7 +36,7 @@ fn main() -> rune::support::Result<()> { let mut vm = Vm::new(runtime, Arc::new(unit)); let mut object = Object::new(); - object.insert(alloc::String::try_from("key")?, Value::from(42i64))?; + object.insert(alloc::String::try_from("key")?, rune::to_value(42i64)?)?; let output = vm.call(["calc"], (object,))?; let output: Object = rune::from_value(output)?; diff --git a/examples/examples/rune_function.rs b/examples/examples/rune_function.rs index 6d9b720e6..6e333969f 100644 --- a/examples/examples/rune_function.rs +++ b/examples/examples/rune_function.rs @@ -38,7 +38,7 @@ fn main() -> rune::support::Result<()> { let output = vm.call(["main"], ())?; let output: Function = rune::from_value(output)?; - println!("{}", output.call::<(i64, i64), i64>((1, 3)).into_result()?); - println!("{}", output.call::<(i64, i64), i64>((2, 6)).into_result()?); + println!("{}", output.call::((1, 3)).into_result()?); + println!("{}", output.call::((2, 6)).into_result()?); Ok(()) }