diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7e527e30..161ff7fa8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,18 +132,18 @@ jobs: strategy: fail-fast: false matrix: - include: - - crate: rune - target: > - runtime:: hir::arena:: --skip runtime::vm:: --skip runtime::vm_execution:: - - crate: rune-alloc + crate: + - rune + - rune-core + - rune-alloc steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly with: components: miri - uses: Swatinem/rust-cache@v2 - - run: cargo miri test -p ${{matrix.crate}} --all-features -- ${{matrix.target}} + - run: cargo miri test -p ${{matrix.crate}} --all-features --all-targets + - run: cargo miri test -p ${{matrix.crate}} --all-features --doc test_lib: runs-on: ubuntu-latest diff --git a/crates/rune/src/build.rs b/crates/rune/src/build.rs index 290fc2721..6825314be 100644 --- a/crates/rune/src/build.rs +++ b/crates/rune/src/build.rs @@ -91,7 +91,7 @@ impl core::error::Error for BuildError { /// Note: these must be built with the `emit` feature enabled (default) to give /// access to `rune::termcolor`. /// -/// ``` +/// ```no_run /// use rune::termcolor::{ColorChoice, StandardStream}; /// use rune::{Context, Source, Vm}; /// use std::sync::Arc; @@ -101,9 +101,9 @@ impl core::error::Error for BuildError { /// /// let mut sources = rune::Sources::new(); /// -/// sources.insert(Source::new("entry", r#" +/// sources.insert(Source::memory(r#" /// pub fn main() { -/// println("Hello World"); +/// println!("Hello World"); /// } /// "#)?)?; /// @@ -237,12 +237,14 @@ impl<'a> compile::CompileVisitor for CompileVisitorGroup<'a> { } impl<'a, S> Build<'a, S> { - /// Modify the current [Build] to use the given [Context] while building. + /// Modify the current [`Build`] to use the given [`Context`] while + /// building. + /// + /// If unspecified the empty context constructed with [`Context::new`] will + /// be used. Since this counts as building without a context, + /// [`Vm::without_runtime`] can be used when running the produced [`Unit`]. /// - /// If unspecified the empty context constructed with [Context::new] will be - /// used. Since this counts as building without a context, - /// [Vm::without_context][crate::runtime::Vm] can be used when running the - /// produced [Unit]. + /// [`Vm::without_runtime`]: crate::Vm::without_runtime #[inline] pub fn with_context(mut self, context: &'a Context) -> Self { self.context = Some(context); diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index 4af44234d..2cf49c6bf 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -390,7 +390,7 @@ impl Context { /// This is not a cheap operation, since it requires cloning things out of /// the build-time [Context] which are necessary at runtime. /// - /// ``` + /// ```no_run /// use rune::{Context, Vm, Unit}; /// use std::sync::Arc; /// diff --git a/crates/rune/src/lib.rs b/crates/rune/src/lib.rs index 0861c9fb2..16de01307 100644 --- a/crates/rune/src/lib.rs +++ b/crates/rune/src/lib.rs @@ -73,7 +73,7 @@ //! //! [`termcolor`]: https://docs.rs/termcolor //! -//! ```rust +//! ```no_run //! use rune::{Context, Diagnostics, Source, Sources, Vm}; //! use rune::termcolor::{ColorChoice, StandardStream}; //! use std::sync::Arc; diff --git a/crates/rune/src/modules/capture_io.rs b/crates/rune/src/modules/capture_io.rs index ebc464f8d..48e710fed 100644 --- a/crates/rune/src/modules/capture_io.rs +++ b/crates/rune/src/modules/capture_io.rs @@ -2,15 +2,15 @@ //! //! # Examples //! -//! ``` -//! use rune::{Context, ContextError}; +//! ```no_run +//! use rune::Context; //! use rune::modules::capture_io::{self, CaptureIo}; //! //! let io = CaptureIo::new(); //! //! let mut context = rune::Context::with_config(false)?; //! context.install(capture_io::module(&io)?)?; -//! # Ok::<_, ContextError>(()) +//! # Ok::<_, rune::ContextError>(()) //! ``` use core::mem::take; diff --git a/crates/rune/src/modules/disable_io.rs b/crates/rune/src/modules/disable_io.rs index 16a37b742..c0a4cc075 100644 --- a/crates/rune/src/modules/disable_io.rs +++ b/crates/rune/src/modules/disable_io.rs @@ -2,13 +2,13 @@ //! //! # Examples //! -//! ``` -//! use rune::{Context, ContextError}; +//! ```no_run +//! use rune::Context; //! use rune::modules::disable_io; //! //! let mut context = rune::Context::with_config(false)?; //! context.install(disable_io::module()?)?; -//! # Ok::<_, ContextError>(()) +//! # Ok::<_, rune::ContextError>(()) //! ``` use crate as rune; diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index d7dba9293..72ef0884a 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -165,13 +165,11 @@ pub(crate) use self::unit::UnitFn; pub use self::unit::{Unit, UnitStorage}; mod value; -#[cfg(any(test, feature = "cli"))] -pub(crate) use self::value::OwnedRepr; pub use self::value::{ Accessor, EmptyStruct, Inline, RawValueGuard, Rtti, Struct, TupleStruct, TypeValue, Value, ValueMutGuard, ValueRefGuard, VariantRtti, }; -pub(crate) use self::value::{BorrowRefRepr, MutRepr, Mutable, RefRepr}; +pub(crate) use self::value::{BorrowRefRepr, MutRepr, Mutable, OwnedRepr, RefRepr}; mod variant; pub use self::variant::{Variant, VariantData}; diff --git a/crates/rune/src/runtime/value/data.rs b/crates/rune/src/runtime/value/data.rs index ad719ceb2..8eefcce1f 100644 --- a/crates/rune/src/runtime/value/data.rs +++ b/crates/rune/src/runtime/value/data.rs @@ -9,7 +9,7 @@ use crate as rune; use crate::alloc::prelude::*; use crate::runtime::{OwnedTuple, TypeInfo}; -use super::{Rtti, Value}; +use super::{FromValue, Mutable, OwnedRepr, Rtti, RuntimeError, Value}; /// A empty with a well-defined type. #[derive(TryClone)] @@ -31,6 +31,17 @@ impl EmptyStruct { } } +impl FromValue for EmptyStruct { + fn from_value(value: Value) -> Result { + match value.take_repr()? { + OwnedRepr::Inline(value) => Err(RuntimeError::expected_unit_struct(value.type_info())), + OwnedRepr::Mutable(Mutable::EmptyStruct(value)) => Ok(value), + OwnedRepr::Mutable(value) => Err(RuntimeError::expected_unit_struct(value.type_info())), + OwnedRepr::Any(value) => Err(RuntimeError::expected_unit_struct(value.type_info())), + } + } +} + impl fmt::Debug for EmptyStruct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.rtti.item) @@ -78,6 +89,19 @@ impl TupleStruct { } } +impl FromValue for TupleStruct { + fn from_value(value: Value) -> Result { + match value.take_repr()? { + OwnedRepr::Inline(value) => Err(RuntimeError::expected_tuple_struct(value.type_info())), + OwnedRepr::Mutable(Mutable::TupleStruct(value)) => Ok(value), + OwnedRepr::Mutable(value) => { + Err(RuntimeError::expected_tuple_struct(value.type_info())) + } + OwnedRepr::Any(value) => Err(RuntimeError::expected_tuple_struct(value.type_info())), + } + } +} + impl fmt::Debug for TupleStruct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}{:?}", self.rtti.item, self.data) @@ -133,6 +157,17 @@ impl Struct { } } +impl FromValue for Struct { + fn from_value(value: Value) -> Result { + match value.take_repr()? { + OwnedRepr::Inline(value) => Err(RuntimeError::expected_struct(value.type_info())), + OwnedRepr::Mutable(Mutable::Struct(value)) => Ok(value), + OwnedRepr::Mutable(value) => Err(RuntimeError::expected_struct(value.type_info())), + OwnedRepr::Any(value) => Err(RuntimeError::expected_struct(value.type_info())), + } + } +} + impl fmt::Debug for Struct { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} {{", self.rtti.item)?; diff --git a/crates/rune/src/runtime/variant.rs b/crates/rune/src/runtime/variant.rs index 7f77520cf..3b0c96b1b 100644 --- a/crates/rune/src/runtime/variant.rs +++ b/crates/rune/src/runtime/variant.rs @@ -7,7 +7,10 @@ use crate as rune; use crate::alloc::clone::TryClone; use crate::alloc::Box; -use super::{Accessor, OwnedTuple, ProtocolCaller, TypeInfo, Value, VariantRtti, Vec, VmResult}; +use super::{ + Accessor, FromValue, Mutable, OwnedRepr, OwnedTuple, ProtocolCaller, RuntimeError, Tuple, + TypeInfo, Value, VariantRtti, Vec, VmResult, +}; /// The variant of a type. #[derive(TryClone)] @@ -26,6 +29,14 @@ impl Variant { } } + /// Try to access variant data as a tuple. + pub fn as_tuple(&self) -> Option<&Tuple> { + match &self.data { + VariantData::Tuple(tuple) => Some(tuple), + _ => None, + } + } + /// Construct a unit variant. pub(crate) fn unit(rtti: Arc) -> Self { Self { @@ -61,7 +72,7 @@ impl Variant { } /// Access the underlying variant data mutably. - pub fn data_mut(&mut self) -> &mut VariantData { + pub(crate) fn data_mut(&mut self) -> &mut VariantData { &mut self.data } @@ -165,6 +176,17 @@ impl Variant { } } +impl FromValue for Variant { + fn from_value(value: Value) -> Result { + match value.take_repr()? { + OwnedRepr::Inline(value) => Err(RuntimeError::expected_variant(value.type_info())), + OwnedRepr::Mutable(Mutable::Variant(value)) => Ok(value), + OwnedRepr::Mutable(value) => Err(RuntimeError::expected_variant(value.type_info())), + OwnedRepr::Any(value) => Err(RuntimeError::expected_variant(value.type_info())), + } + } +} + /// The data of the variant. #[derive(TryClone)] pub enum VariantData { diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index dd1d63486..43c36e769 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -318,14 +318,11 @@ impl Vm { /// /// # Examples /// - /// ``` + /// ```no_run /// use rune::{Context, Unit, Vm}; /// /// use std::sync::Arc; /// - /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()?); - /// /// let mut sources = rune::sources! { /// entry => { /// pub fn max(a, b) { @@ -338,10 +335,13 @@ impl Vm { /// } /// }; /// + /// let context = Context::with_default_modules()?; + /// let runtime = Arc::new(context.runtime()?); + /// /// let unit = rune::prepare(&mut sources).build()?; /// let unit = Arc::new(unit); /// - /// let vm = Vm::new(context, unit); + /// let vm = Vm::new(runtime, unit); /// /// // Looking up an item from the source. /// let dynamic_max = vm.lookup_function(["max"])?; @@ -394,18 +394,12 @@ impl Vm { /// /// # Examples /// - /// ```,no_run + /// ```no_run /// use rune::{Context, Unit}; /// use std::sync::Arc; /// - /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()?); - /// - /// // Normally the unit would be created by compiling some source, - /// // and since this one is empty it won't do anything. /// let unit = Arc::new(Unit::default()); - /// - /// let mut vm = rune::Vm::new(context, unit); + /// let mut vm = rune::Vm::without_runtime(unit); /// /// let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; /// let output: i64 = rune::from_value(output)?; @@ -417,18 +411,14 @@ impl Vm { /// You can use a `Vec` to provide a variadic collection of /// arguments. /// - /// ```,no_run + /// ```no_run /// use rune::{Context, Unit}; /// use std::sync::Arc; /// - /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()?); - /// /// // Normally the unit would be created by compiling some source, /// // and since this one is empty it won't do anything. /// let unit = Arc::new(Unit::default()); - /// - /// let mut vm = rune::Vm::new(context, unit); + /// let mut vm = rune::Vm::without_runtime(unit); /// /// let mut args = Vec::new(); /// args.push(rune::to_value(1u32)?); diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index b7b3120b3..464acf74c 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -79,11 +79,6 @@ impl VmError { pub(crate) fn into_kind(self) -> VmErrorKind { self.inner.error.kind } - - #[cfg(test)] - pub(crate) fn as_kind(&self) -> &VmErrorKind { - &self.inner.error.kind - } } impl fmt::Display for VmError { @@ -446,6 +441,26 @@ impl RuntimeError { }) } + /// Construct an expected error for a variant. + pub(crate) fn expected_variant(actual: TypeInfo) -> Self { + Self::new(VmErrorKind::ExpectedVariant { actual }) + } + + /// Construct an expected expecting a unit struct. + pub(crate) fn expected_unit_struct(actual: TypeInfo) -> Self { + Self::new(VmErrorKind::ExpectedUnitStruct { actual }) + } + + /// Construct an expected expecting a tuple struct. + pub(crate) fn expected_tuple_struct(actual: TypeInfo) -> Self { + Self::new(VmErrorKind::ExpectedTupleStruct { actual }) + } + + /// Construct an expected expecting a struct. + pub(crate) fn expected_struct(actual: TypeInfo) -> Self { + Self::new(VmErrorKind::ExpectedStruct { actual }) + } + /// Construct an expected error from any. pub(crate) fn expected_any(actual: TypeInfo) -> Self where @@ -819,6 +834,15 @@ pub(crate) enum VmErrorKind { ExpectedVariant { actual: TypeInfo, }, + ExpectedUnitStruct { + actual: TypeInfo, + }, + ExpectedTupleStruct { + actual: TypeInfo, + }, + ExpectedStruct { + actual: TypeInfo, + }, UnsupportedObjectFieldGet { target: TypeInfo, }, @@ -1026,6 +1050,15 @@ impl fmt::Display for VmErrorKind { VmErrorKind::ExpectedVariant { actual } => { write!(f, "Expected an enum variant, but got `{actual}`") } + VmErrorKind::ExpectedUnitStruct { actual } => { + write!(f, "Expected a unit struct, but got `{actual}`") + } + VmErrorKind::ExpectedTupleStruct { actual } => { + write!(f, "Expected a tuple struct, but got `{actual}`") + } + VmErrorKind::ExpectedStruct { actual } => { + write!(f, "Expected a struct, but got `{actual}`") + } VmErrorKind::UnsupportedObjectFieldGet { target } => write!( f, "The object field get operation is not supported on `{target}`", diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index a14be11e9..734065fd1 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -2,6 +2,7 @@ #![allow(clippy::bool_assert_comparison)] #![allow(clippy::approx_constant)] +#![cfg_attr(miri, allow(unused))] pub(crate) mod prelude { pub(crate) use crate as rune; @@ -16,8 +17,8 @@ pub(crate) mod prelude { pub(crate) use crate::parse; pub(crate) use crate::runtime::{ self, Bytes, Formatter, Function, InstAddress, MaybeTypeOf, Mutable, Object, Output, - OwnedRepr, OwnedTuple, Protocol, RawAnyGuard, Ref, Stack, Tuple, TypeHash, TypeInfo, - TypeOf, UnsafeToRef, VecTuple, VmErrorKind, VmResult, + OwnedRepr, OwnedTuple, Protocol, RawAnyGuard, Ref, Stack, Tuple, TupleStruct, TypeHash, + TypeInfo, TypeOf, UnsafeToRef, Variant, VecTuple, VmErrorKind, VmResult, }; pub(crate) use crate::support::Result; pub(crate) use crate::tests::{eval, run}; @@ -403,75 +404,146 @@ macro_rules! prelude { }; } +#[cfg(not(miri))] mod attribute; +#[cfg(not(miri))] mod binary; +#[cfg(not(miri))] mod bug_326; +#[cfg(not(miri))] mod bug_344; +#[cfg(not(miri))] mod bug_417; +#[cfg(not(miri))] mod bug_422; +#[cfg(not(miri))] mod bug_428; +#[cfg(not(miri))] mod bug_454; +#[cfg(not(miri))] mod bug_700; +#[cfg(not(miri))] mod bugfixes; +#[cfg(not(miri))] mod builtin_macros; +#[cfg(not(miri))] mod capture; +#[cfg(not(miri))] mod collections; +#[cfg(not(miri))] mod comments; +#[cfg(not(miri))] mod compiler_docs; +#[cfg(not(miri))] mod compiler_expr_assign; +#[cfg(not(miri))] mod compiler_fn; +#[cfg(not(miri))] mod compiler_general; +#[cfg(not(miri))] mod compiler_literals; +#[cfg(not(miri))] mod compiler_paths; +#[cfg(not(miri))] mod compiler_patterns; +#[cfg(not(miri))] mod compiler_use; +#[cfg(not(miri))] mod compiler_visibility; +#[cfg(not(miri))] mod compiler_warnings; +#[cfg(not(miri))] mod continue_; +#[cfg(not(miri))] mod core_macros; +#[cfg(not(miri))] mod custom_macros; +#[cfg(not(miri))] mod debug_fmt; +#[cfg(not(miri))] mod deprecation; +#[cfg(not(miri))] mod destructuring; +#[cfg(not(miri))] mod esoteric_impls; +#[cfg(not(miri))] mod external_constructor; +#[cfg(not(miri))] mod external_generic; +#[cfg(not(miri))] mod external_match; +#[cfg(not(miri))] mod external_ops; mod function_guardedargs; +#[cfg(not(miri))] mod getter_setter; +#[cfg(not(miri))] mod iterator; +#[cfg(not(miri))] mod macros; +#[cfg(not(miri))] mod moved; +#[cfg(not(miri))] mod option; +#[cfg(not(miri))] mod patterns; +#[cfg(not(miri))] mod quote; +#[cfg(not(miri))] mod range; +#[cfg(not(miri))] mod reference_error; +#[cfg(not(miri))] mod rename_type; +#[cfg(not(miri))] mod result; +#[cfg(not(miri))] mod tuple; +#[cfg(not(miri))] mod type_name_native; +#[cfg(not(miri))] mod unit_constants; +#[cfg(not(miri))] mod unreachable; +#[cfg(not(miri))] mod variants; +#[cfg(not(miri))] mod vm_arithmetic; +#[cfg(not(miri))] mod vm_assign_exprs; +#[cfg(not(miri))] mod vm_async_block; +#[cfg(not(miri))] mod vm_blocks; +#[cfg(not(miri))] mod vm_closures; +#[cfg(not(miri))] mod vm_const_exprs; +#[cfg(not(miri))] mod vm_early_termination; +#[cfg(not(miri))] mod vm_function; +#[cfg(not(miri))] mod vm_function_pointers; +#[cfg(not(miri))] mod vm_general; +#[cfg(not(miri))] mod vm_literals; +#[cfg(not(miri))] mod vm_not_used; +#[cfg(not(miri))] mod vm_result; +#[cfg(not(miri))] mod vm_test_from_value_derive; +#[cfg(not(miri))] mod vm_test_imports; +#[cfg(not(miri))] mod vm_test_instance_fns; +#[cfg(not(miri))] mod vm_test_linked_list; +#[cfg(not(miri))] mod vm_test_mod; +#[cfg(not(miri))] mod vm_try; +#[cfg(not(miri))] mod wildcard_imports; diff --git a/crates/rune/src/tests/function_guardedargs.rs b/crates/rune/src/tests/function_guardedargs.rs index 2b2a6506c..929bf28c2 100644 --- a/crates/rune/src/tests/function_guardedargs.rs +++ b/crates/rune/src/tests/function_guardedargs.rs @@ -12,15 +12,14 @@ fn get_vm() -> crate::support::Result { Variant(internal) } - struct Struct(internal); + struct Tuple(internal); pub fn function(argument) {} } }; - let context = crate::Context::with_default_modules()?; let unit = crate::prepare(&mut sources).build()?; - Ok(crate::Vm::new(Arc::new(context.runtime()?), Arc::new(unit))) + Ok(crate::Vm::without_runtime(Arc::new(unit))) } #[test] @@ -45,8 +44,6 @@ fn references_allowed_for_function_calls() { #[test] fn references_disallowed_for_tuple_variant() { - use crate::runtime::{VmErrorKind, VmResult}; - let vm = get_vm().unwrap(); let constructor = vm.lookup_function(["Enum", "Variant"]).unwrap(); @@ -55,54 +52,35 @@ fn references_disallowed_for_tuple_variant() { let mut mine = MyAny; - let VmResult::Err(err) = constructor.call::((&mine,)) else { - panic!("expected ref call to return an error") - }; - assert!( - matches!(err.as_kind(), VmErrorKind::AccessError { .. }), - "{err:?}" - ); + let tuple = constructor.call::((&mine,)).unwrap(); + let tuple = tuple.as_tuple().unwrap(); + assert!(tuple.first().unwrap().borrow_ref::().is_err()); - let VmResult::Err(err) = constructor.call::((&mut mine,)) else { - panic!("expected mut call to return an error") - }; - assert!( - matches!(err.as_kind(), VmErrorKind::AccessError { .. }), - "{err:?}" - ); + let tuple = constructor.call::((&mut mine,)).unwrap(); + let tuple = tuple.as_tuple().unwrap(); + assert!(tuple.first().unwrap().borrow_ref::().is_err()); - let any_result = constructor.call::((mine,)); - assert!(any_result.is_ok()); + let tuple = constructor.call::((mine,)).unwrap(); + let tuple = tuple.as_tuple().unwrap(); + assert!(tuple.first().unwrap().borrow_ref::().is_ok()); } #[test] fn references_disallowed_for_tuple_struct() { - use crate::runtime::{VmErrorKind, VmResult}; - let vm = get_vm().unwrap(); - let constructor = vm.lookup_function(["Struct"]).unwrap(); + let constructor = vm.lookup_function(["Tuple"]).unwrap(); let value_result = constructor.call::((crate::Value::unit(),)); assert!(value_result.is_ok()); let mut mine = MyAny; - let VmResult::Err(err) = constructor.call::((&mine,)) else { - panic!("expected ref call to return an error") - }; - assert!( - matches!(err.as_kind(), VmErrorKind::AccessError { .. }), - "{err:?}" - ); + let st: TupleStruct = constructor.call::((&mine,)).unwrap(); + assert!(st.data().first().unwrap().borrow_ref::().is_err()); - let VmResult::Err(err) = constructor.call::((&mut mine,)) else { - panic!("expected mut call to return an error") - }; - assert!( - matches!(err.as_kind(), VmErrorKind::AccessError { .. }), - "{err:?}" - ); + let st: TupleStruct = constructor.call::((&mut mine,)).unwrap(); + assert!(st.data().first().unwrap().borrow_ref::().is_err()); - let any_result = constructor.call::((mine,)); - assert!(any_result.is_ok()); + let st: TupleStruct = constructor.call::((mine,)).unwrap(); + assert!(st.data().first().unwrap().borrow_ref::().is_ok()); }