diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 608487a85..40f305b9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.81 + - uses: dtolnay/rust-toolchain@1.87 - uses: Swatinem/rust-cache@v2 - run: cargo build --workspace --lib @@ -91,7 +91,7 @@ jobs: steps: - run: exit 0 - build_feature: + rune_feature: runs-on: ubuntu-latest needs: basics strategy: @@ -99,6 +99,7 @@ jobs: matrix: feature: - alloc + - alloc,anyhow - cli - cli,doc - cli,fmt @@ -106,6 +107,9 @@ jobs: - workspace - languageserver - byte-code + - alloc,serde + - alloc,musli + - alloc,serde,musli - capture-io - emit env: @@ -117,8 +121,33 @@ jobs: components: clippy - uses: Swatinem/rust-cache@v2 - run: cargo check -p rune --no-default-features --features ${{matrix.feature}} - - run: cargo check --release -p rune --no-default-features --features ${{matrix.feature}} - - run: cargo clippy --all-targets --no-default-features --features ${{matrix.feature}} + - run: cargo clippy -p rune --no-default-features --features ${{matrix.feature}} + + rune_modules_feature: + runs-on: ubuntu-latest + needs: basics + strategy: + fail-fast: false + matrix: + feature: + - rand + - rand,os_rng + - rand,small_rng + - rand,small_rng,os_rng + - rand,std_rng + - rand,std_rng,os_rng + - rand,thread_rng + - rand,thread_rng,os_rng + env: + RUSTFLAGS: -D warnings + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo check -p rune-modules --no-default-features --features ${{matrix.feature}} + - run: cargo clippy -p rune-modules --no-default-features --features ${{matrix.feature}} wasm: runs-on: ubuntu-latest diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 3b6bffa95..8b35c1a1f 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -5,7 +5,7 @@ publish = false [dependencies] rune = { path = "../crates/rune", features = ["bench", "capture-io"] } -rhai = "1.19.0" +rhai = "1.21.0" tokio = { version = "1.28.1", features = ["macros"] } criterion = "0.4.0" diff --git a/book/src/field_functions.md b/book/src/field_functions.md index 301f34b68..26f7a4e89 100644 --- a/book/src/field_functions.md +++ b/book/src/field_functions.md @@ -78,6 +78,60 @@ pub fn main(external) { } ``` +## Customizing how fields are cloned with `#[rune(get)]` + +In order to return a value through `#[rune(get)]`, the value has to be cloned. + +By default, this is done through the [`TryClone` trait], but its behavior can be +customized through the following attributes: + +#### `#[rune(copy)]` + +This indicates that the field is `Copy`. + +#### `#[rune(clone)]` + +This indicates that the field should use `std::clone::Clone` to clone the value. +Note that this effecitvely means that the memory the value uses during cloning +is *not* tracked and should be avoided in favor of using [`rune::alloc`] and the +[`TryClone` trait] without good reason. + +#### `#[rune(clone_with = )]` + +This specified a custom method that should be used to clone the value. + +```rust,noplaypen +use rune::Any; + +use std::sync::Arc; + +#[derive(Any)] +struct External { + #[rune(get, clone_with = Thing::clone)] + field: Thing, +} + +#[derive(Any, Clone)] +struct Thing { + name: Arc, +} +``` + +#### `#[rune(try_clone_with = )]` + +This specified a custom method that should be used to clone the value. + +```rust,noplaypen +use rune::Any; +use rune::prelude::*; + +#[derive(Any)] +struct External { + #[rune(get, try_clone_with = String::try_clone)] + field: String, +} +``` + ## Custom field function Using the `Any` derive, you can specify a custom field function by using an @@ -95,15 +149,17 @@ $> cargo run --example checked_add_assign Error: numerical overflow (at inst 2) ``` -[`Protocol::GET`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.GET -[`Protocol::SET`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.SET [`Protocol::ADD_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.ADD_ASSIGN -[`Protocol::SUB_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.SUB_ASSIGN -[`Protocol::MUL_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.MUL_ASSIGN -[`Protocol::DIV_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.DIV_ASSIGN [`Protocol::BIT_AND_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.BIT_AND_ASSIGN [`Protocol::BIT_OR_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.BIT_OR_ASSIGN [`Protocol::BIT_XOR_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.BIT_XOR_ASSIGN +[`Protocol::DIV_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.DIV_ASSIGN +[`Protocol::GET`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.GET +[`Protocol::MUL_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.MUL_ASSIGN +[`Protocol::REM_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.REM_ASSIGN +[`Protocol::SET`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.SET [`Protocol::SHL_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.SHL_ASSIGN [`Protocol::SHR_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.SHR_ASSIGN -[`Protocol::REM_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.REM_ASSIGN +[`Protocol::SUB_ASSIGN`]: https://docs.rs/rune/0/rune/runtime/struct.Protocol.html#associatedconstant.SUB_ASSIGN +[`rune::alloc`]: https://docs.rs/rune/0/rune/alloc/ +[`TryClone` trait]: https://docs.rs/rune/0/rune/alloc/clone/trait.TryClone.html diff --git a/crates/rune-alloc-macros/Cargo.toml b/crates/rune-alloc-macros/Cargo.toml index bd785997a..e904a67fe 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.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "Macros for alloc crate of the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -18,5 +18,8 @@ syn = { version = "2.0.16", features = ["full"] } quote = "1.0.27" proc-macro2 = "1.0.56" +[dev-dependencies] +rune = { path = "../rune" } + [lib] proc-macro = true diff --git a/crates/rune-alloc-macros/src/lib.rs b/crates/rune-alloc-macros/src/lib.rs index c5db5bd86..e267ac301 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-alloc/Cargo.toml b/crates/rune-alloc/Cargo.toml index cbc6841de..efc87c970 100644 --- a/crates/rune-alloc/Cargo.toml +++ b/crates/rune-alloc/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-alloc" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "The Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -27,11 +27,12 @@ raw = [] rune-alloc-macros = { version = "=0.14.0", path = "../rune-alloc-macros" } serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } +musli = { version = "0.0.131", default-features = false, features = ["alloc"], optional = true } ahash = { version = "0.8.8", default-features = false } pin-project = "1.1.0" [dev-dependencies] -rune = { package = "rune-shim", path = "../rune-shim", features = ["alloc"] } +rune = { path = "../rune", features = ["alloc"] } rand = { version = "0.8.5", features = ["small_rng"] } tokio = { version = "1.28.1", default-features = false, features = ["rt", "macros"] } diff --git a/crates/rune-alloc/src/alloc/global.rs b/crates/rune-alloc/src/alloc/global.rs index a06a56925..dda31b8c9 100644 --- a/crates/rune-alloc/src/alloc/global.rs +++ b/crates/rune-alloc/src/alloc/global.rs @@ -4,7 +4,7 @@ use crate::alloc::{AllocError, Allocator}; use crate::ptr::{invalid_mut, NonNull}; #[cfg(feature = "alloc")] -use ::rust_alloc::alloc::{alloc, alloc_zeroed, dealloc}; +use rust_alloc::alloc::{alloc, alloc_zeroed, dealloc}; /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. /// diff --git a/crates/rune-alloc/src/borrow/mod.rs b/crates/rune-alloc/src/borrow/mod.rs index b73427d54..46fb591e2 100644 --- a/crates/rune-alloc/src/borrow/mod.rs +++ b/crates/rune-alloc/src/borrow/mod.rs @@ -7,7 +7,7 @@ use core::hash::{Hash, Hasher}; use core::ops::Deref; #[cfg(feature = "alloc")] -use ::rust_alloc::borrow::ToOwned; +use rust_alloc::borrow::ToOwned; use crate::clone::TryClone; use crate::error::Error; diff --git a/crates/rune-alloc/src/boxed.rs b/crates/rune-alloc/src/boxed.rs index 1ec791abd..aeb2a7385 100644 --- a/crates/rune-alloc/src/boxed.rs +++ b/crates/rune-alloc/src/boxed.rs @@ -251,7 +251,7 @@ impl Box { /// # Ok::<_, rune::alloc::Error>(()) /// ``` #[cfg(feature = "alloc")] - pub fn from_std(b: ::rust_alloc::boxed::Box) -> Result { + pub fn from_std(b: rust_alloc::boxed::Box) -> Result { // SAFETY: We've ensured that standard allocations only happen in an // allocator which is compatible with our `Global`. unsafe { @@ -259,7 +259,7 @@ impl Box { // value by the box, which for unsized types is the size of the // metadata. For sized types the value inside of the box. Global.take(Layout::for_value(b.as_ref()))?; - let raw = ::rust_alloc::boxed::Box::into_raw(b); + let raw = rust_alloc::boxed::Box::into_raw(b); Ok(Box::from_raw_in(raw, Global)) } } @@ -562,6 +562,12 @@ impl Box { let alloc = unsafe { ptr::read(&leaked.alloc) }; (leaked.ptr.as_ptr(), alloc) } + + #[inline] + pub(crate) fn into_unique_with_allocator(b: Self) -> (Unique, A) { + let (ptr, alloc) = Box::into_raw_with_allocator(b); + unsafe { (Unique::from(&mut *ptr), alloc) } + } } impl Box, A> { @@ -847,14 +853,14 @@ impl From> for Box<[u8], A> { } #[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::boxed::Box<[T]>> for Box<[T]> { +impl TryFrom> for Box<[T]> { type Error = Error; #[inline] - fn try_from(values: ::rust_alloc::boxed::Box<[T]>) -> Result { + fn try_from(values: rust_alloc::boxed::Box<[T]>) -> Result { let mut vec = Vec::try_with_capacity(values.len())?; - for value in ::rust_alloc::vec::Vec::from(values) { + for value in rust_alloc::vec::Vec::from(values) { vec.try_push(value)?; } @@ -988,7 +994,7 @@ impl TryFrom<&str> for Box { } #[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::string::String> for Box { +impl TryFrom for Box { type Error = Error; /// Converts a std `String` into a `Box`. @@ -1004,7 +1010,7 @@ impl TryFrom<::rust_alloc::string::String> for Box { /// # Ok::<_, rune::alloc::Error>(()) /// ``` #[inline] - fn try_from(string: ::rust_alloc::string::String) -> Result { + fn try_from(string: rust_alloc::string::String) -> Result { Box::from_std(string.into_boxed_str()) } } diff --git a/crates/rune-alloc/src/clone.rs b/crates/rune-alloc/src/clone.rs index 57030154d..e5bd25a6e 100644 --- a/crates/rune-alloc/src/clone.rs +++ b/crates/rune-alloc/src/clone.rs @@ -44,7 +44,98 @@ use crate::error::Error; -#[doc(inline)] +/// Derive to implement the `TryClone` trait. +/// +///
+/// +/// # Examples +/// +/// Basic usage example: +/// +/// ``` +/// use rune::alloc::String; +/// use rune::alloc::clone::TryClone; +/// +/// // String type implements TryClone +/// let s = String::new(); +/// // ... so we can clone it +/// let copy = s.try_clone()?; +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// To easily implement the TryClone trait, you can also use +/// `#[derive(TryClone)]`. Example: +/// +/// ``` +/// use rune::alloc::clone::TryClone; +/// +/// // we add the TryClone trait to Morpheus struct +/// #[derive(TryClone)] +/// struct Morpheus { +/// blue_pill: f32, +/// red_pill: i64, +/// } +/// +/// let f = Morpheus { blue_pill: 0.0, red_pill: 0 }; +/// // and now we can clone it! +/// let copy = f.try_clone()?; +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +///
+/// +/// ## Attributes +/// +///
+/// +/// ### `try_clone(with = )` +/// +/// Specify a custom method when cloning a field. +/// +/// ``` +/// use rune::alloc::clone::TryClone; +/// +/// #[derive(Debug, TryClone)] +/// #[non_exhaustive] +/// pub struct Struct { +/// #[try_clone(with = String::clone)] +/// string: String, +/// } +/// ``` +/// +///
+/// +/// ### `try_clone(try_with = )` +/// +/// Specify a custom fallible method when cloning a field. +/// +/// ``` +/// use rune::alloc::clone::TryClone; +/// +/// #[derive(Debug, TryClone)] +/// #[non_exhaustive] +/// pub struct Struct { +/// #[try_clone(try_with = rune::alloc::String::try_clone)] +/// string: rune::alloc::String, +/// } +/// ``` +/// +///
+/// +/// ### `try_clone(copy)` +/// +/// Specify that a field is `Copy`. +/// +/// ``` +/// use rune::alloc::prelude::*; +/// +/// #[derive(Debug, TryClone)] +/// #[non_exhaustive] +/// pub struct Struct { +/// #[try_clone(copy)] +/// number: u32, +/// } +/// ``` pub use rune_alloc_macros::TryClone; /// Fallible `TryClone` trait. @@ -162,37 +253,37 @@ where } #[cfg(feature = "alloc")] -impl TryClone for ::rust_alloc::sync::Arc { +impl TryClone for rust_alloc::sync::Arc { fn try_clone(&self) -> Result { Ok(self.clone()) } } #[cfg(feature = "alloc")] -impl TryClone for ::rust_alloc::rc::Rc { +impl TryClone for rust_alloc::rc::Rc { fn try_clone(&self) -> Result { Ok(self.clone()) } } #[cfg(feature = "alloc")] -impl TryClone for ::rust_alloc::boxed::Box +impl TryClone for rust_alloc::boxed::Box where T: TryClone, { fn try_clone(&self) -> Result { - Ok(::rust_alloc::boxed::Box::new(self.as_ref().try_clone()?)) + Ok(rust_alloc::boxed::Box::new(self.as_ref().try_clone()?)) } } #[cfg(feature = "alloc")] -impl TryClone for ::rust_alloc::boxed::Box<[T]> +impl TryClone for rust_alloc::boxed::Box<[T]> where T: TryClone, { fn try_clone(&self) -> Result { // TODO: use a fallible box allocation. - let mut out = ::rust_alloc::vec::Vec::with_capacity(self.len()); + let mut out = rust_alloc::vec::Vec::with_capacity(self.len()); for value in self.iter() { out.push(value.try_clone()?); @@ -203,7 +294,7 @@ where } #[cfg(feature = "alloc")] -impl TryClone for ::rust_alloc::string::String { +impl TryClone for rust_alloc::string::String { #[inline] fn try_clone(&self) -> Result { // TODO: use fallible allocations for component. @@ -212,13 +303,13 @@ impl TryClone for ::rust_alloc::string::String { } #[cfg(all(test, feature = "alloc"))] -impl TryClone for ::rust_alloc::vec::Vec +impl TryClone for rust_alloc::vec::Vec where T: TryClone, { #[inline] fn try_clone(&self) -> Result { - let mut out = ::rust_alloc::vec::Vec::with_capacity(self.len()); + let mut out = rust_alloc::vec::Vec::with_capacity(self.len()); for value in self { out.push(value.try_clone()?); diff --git a/crates/rune-alloc/src/hashbrown/map.rs b/crates/rune-alloc/src/hashbrown/map.rs index e7331951f..60ea71f87 100644 --- a/crates/rune-alloc/src/hashbrown/map.rs +++ b/crates/rune-alloc/src/hashbrown/map.rs @@ -7078,8 +7078,8 @@ mod test_map { use std::vec::Vec; use std::{format, println}; - use ::rust_alloc::string::{String, ToString}; - use ::rust_alloc::sync::Arc; + use rust_alloc::string::{String, ToString}; + use rust_alloc::sync::Arc; use rand::{rngs::SmallRng, Rng, SeedableRng}; @@ -7212,7 +7212,7 @@ mod test_map { #[test] fn test_drops() { DROP_VECTOR.with(|slot| { - *slot.borrow_mut() = ::rust_alloc::vec![0; 200]; + *slot.borrow_mut() = rust_alloc::vec![0; 200]; }); { @@ -7271,7 +7271,7 @@ mod test_map { #[test] fn test_into_iter_drops() { DROP_VECTOR.with(|v| { - *v.borrow_mut() = ::rust_alloc::vec![0; 200]; + *v.borrow_mut() = rust_alloc::vec![0; 200]; }); let hm = { @@ -7542,7 +7542,7 @@ mod test_map { #[test] fn test_keys() { - let vec = ::rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let vec = rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; let map: HashMap<_, _> = vec.into_iter().collect(); let keys: Vec<_> = map.keys().copied().collect(); assert_eq!(keys.len(), 3); @@ -7553,7 +7553,7 @@ mod test_map { #[test] fn test_values() { - let vec = ::rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let vec = rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; let map: HashMap<_, _> = vec.into_iter().collect(); let values: Vec<_> = map.values().copied().collect(); assert_eq!(values.len(), 3); @@ -7564,7 +7564,7 @@ mod test_map { #[test] fn test_values_mut() { - let vec = ::rust_alloc::vec![(1, 1), (2, 2), (3, 3)]; + let vec = rust_alloc::vec![(1, 1), (2, 2), (3, 3)]; let mut map: HashMap<_, _> = vec.into_iter().collect(); for value in map.values_mut() { *value *= 2; @@ -7578,7 +7578,7 @@ mod test_map { #[test] fn test_into_keys() { - let vec = ::rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let vec = rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; let map: HashMap<_, _> = vec.into_iter().collect(); let keys: Vec<_> = map.into_keys().collect(); @@ -7590,7 +7590,7 @@ mod test_map { #[test] fn test_into_values() { - let vec = ::rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let vec = rust_alloc::vec![(1, 'a'), (2, 'b'), (3, 'c')]; let map: HashMap<_, _> = vec.into_iter().collect(); let values: Vec<_> = map.into_values().collect(); @@ -8537,7 +8537,7 @@ mod test_map { let drained = map.extract_if(|&k, _| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); - assert_eq!(::rust_alloc::vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); + assert_eq!(rust_alloc::vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); assert_eq!(map.len(), 4); } { @@ -8904,7 +8904,7 @@ mod test_map { #[test] #[should_panic = "panic in clone"] fn test_clone_from_memory_leaks() { - use ::rust_alloc::vec::Vec; + use rust_alloc::vec::Vec; struct CheckedClone { panic_in_clone: bool, @@ -8926,7 +8926,7 @@ mod test_map { 1, CheckedClone { panic_in_clone: false, - need_drop: ::rust_alloc::vec![0, 1, 2], + need_drop: rust_alloc::vec![0, 1, 2], }, ) .unwrap(); @@ -8934,7 +8934,7 @@ mod test_map { 2, CheckedClone { panic_in_clone: false, - need_drop: ::rust_alloc::vec![3, 4, 5], + need_drop: rust_alloc::vec![3, 4, 5], }, ) .unwrap(); @@ -8942,7 +8942,7 @@ mod test_map { 3, CheckedClone { panic_in_clone: true, - need_drop: ::rust_alloc::vec![6, 7, 8], + need_drop: rust_alloc::vec![6, 7, 8], }, ) .unwrap(); @@ -9165,7 +9165,7 @@ mod test_map { let map: HashMap>, DefaultHashBuilder, MyAlloc> = match get_test_map( ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), - |n| ::rust_alloc::vec![n], + |n| rust_alloc::vec![n], MyAlloc::new(dropped.clone()), ) { Ok(map) => map, @@ -9224,7 +9224,7 @@ mod test_map { let mut map = match get_test_map( DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), - |n| ::rust_alloc::vec![n], + |n| rust_alloc::vec![n], MyAlloc::new(dropped.clone()), ) { Ok(map) => map, @@ -9234,7 +9234,7 @@ mod test_map { thread::scope(|s| { let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { let scope_map = - match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| ::rust_alloc::vec![n * 2], MyAlloc::new(dropped.clone())) { + match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| rust_alloc::vec![n * 2], MyAlloc::new(dropped.clone())) { Ok(map) => map, Err(msg) => return msg, }; @@ -9291,7 +9291,7 @@ mod test_map { let mut map = match get_test_map( [DISARMED].into_iter().zip([DISARMED]), - |n| ::rust_alloc::vec![n], + |n| rust_alloc::vec![n], MyAlloc::new(dropped.clone()), ) { Ok(map) => map, @@ -9302,7 +9302,7 @@ mod test_map { let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { let scope_map = match get_test_map( ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), - |n| ::rust_alloc::vec![n * 2], + |n| rust_alloc::vec![n * 2], MyAlloc::new(dropped.clone()), ) { Ok(map) => map, diff --git a/crates/rune-alloc/src/hashbrown/raw/mod.rs b/crates/rune-alloc/src/hashbrown/raw/mod.rs index b0b58b2f8..dec9703a4 100644 --- a/crates/rune-alloc/src/hashbrown/raw/mod.rs +++ b/crates/rune-alloc/src/hashbrown/raw/mod.rs @@ -1,10 +1,9 @@ use core::alloc::Layout; +use core::hint; use core::iter::FusedIterator; use core::marker::PhantomData; -use core::mem; -use core::mem::MaybeUninit; -use core::ptr::NonNull; -use core::{hint, ptr}; +use core::mem::{self, MaybeUninit}; +use core::ptr::{self, NonNull}; use crate::hashbrown::scopeguard::{guard, ScopeGuard}; @@ -3998,9 +3997,10 @@ impl Iterator for RawIterHashInner { mod test_map { use super::*; - use crate::alloc::into_ok; use core::convert::Infallible; + use crate::alloc::into_ok; + fn rehash_in_place( table: &mut RawTable, hasher: impl Fn(&mut (), &T) -> Result, @@ -4064,7 +4064,7 @@ mod test_map { /// AN UNINITIALIZED TABLE DURING THE DROP #[test] fn test_drop_uninitialized() { - use ::rust_alloc::vec::Vec; + use rust_alloc::vec::Vec; let table = unsafe { // SAFETY: The `buckets` is power of two and we're not @@ -4078,7 +4078,7 @@ mod test_map { /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. #[test] fn test_drop_zero_items() { - use ::rust_alloc::vec::Vec; + use rust_alloc::vec::Vec; unsafe { // SAFETY: The `buckets` is power of two and we're not // trying to actually use the returned RawTable. @@ -4124,12 +4124,16 @@ mod test_map { /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. #[test] fn test_catch_panic_clone_from() { - use crate::alloc::{AllocError, Allocator}; - use ::rust_alloc::sync::Arc; - use ::rust_alloc::vec::Vec; + use core::iter; use core::sync::atomic::{AtomicI8, Ordering}; + + use rust_alloc::sync::Arc; + use rust_alloc::vec::Vec; + use std::thread; + use crate::alloc::{AllocError, Allocator}; + struct MyAllocInner { drop_count: Arc, } @@ -4197,7 +4201,7 @@ mod test_map { }), }); - for (idx, panic_in_clone) in core::iter::repeat(DISARMED).take(7).enumerate() { + for (idx, panic_in_clone) in iter::repeat_n(DISARMED, 7).enumerate() { let idx = idx as u64; table .insert( @@ -4208,7 +4212,7 @@ mod test_map { CheckedCloneDrop { panic_in_clone, dropped: false, - need_drop: ::rust_alloc::vec![idx], + need_drop: rust_alloc::vec![idx], }, ), |_: &mut (), (k, _): &(u64, _)| Ok::<_, Infallible>(*k), @@ -4239,7 +4243,7 @@ mod test_map { CheckedCloneDrop { panic_in_clone, dropped: false, - need_drop: ::rust_alloc::vec![idx + 100], + need_drop: rust_alloc::vec![idx + 100], }, ), |_: &mut (), (k, _): &(u64, _)| Ok::<_, Infallible>(*k), diff --git a/crates/rune-alloc/src/lib.rs b/crates/rune-alloc/src/lib.rs index 376f01373..ced0756ce 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 @@ -36,10 +36,8 @@ #![no_std] #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_doc_tests)] -#![cfg_attr(rune_nightly, deny(rustdoc::missing_doc_code_examples))] #![cfg_attr(rune_nightly, allow(internal_features))] #![cfg_attr(rune_nightly, feature(fmt_internals))] -#![cfg_attr(rune_nightly, feature(rustdoc_missing_doc_code_examples))] #![cfg_attr(rune_nightly, feature(core_intrinsics))] #![cfg_attr(rune_nightly, feature(dropck_eyepatch))] #![cfg_attr(rune_nightly, feature(min_specialization))] @@ -123,6 +121,8 @@ pub mod iter; pub mod fmt; +pub mod sync; + mod option; pub(crate) mod hint; @@ -146,6 +146,9 @@ pub mod prelude { pub use crate::{try_format, try_vec}; } +#[cfg(feature = "musli")] +mod musli; + pub mod limit; #[cfg(test)] diff --git a/crates/rune-alloc/src/musli.rs b/crates/rune-alloc/src/musli.rs new file mode 100644 index 000000000..ca81af9d9 --- /dev/null +++ b/crates/rune-alloc/src/musli.rs @@ -0,0 +1,900 @@ +use core::fmt; +use core::hash::{BuildHasher, Hash}; + +use crate::borrow::Cow; +use crate::borrow::TryToOwned; +use crate::{BTreeMap, BTreeSet, Box, HashMap, HashSet, String, Vec, VecDeque}; + +use musli::alloc::ToOwned; +use musli::de::SizeHint; +use musli::de::{ + Decode, DecodeBytes, DecodeSliceBuilder, DecodeTrace, Decoder, EntryDecoder, MapDecoder, + SequenceDecoder, UnsizedVisitor, +}; +use musli::en::{ + Encode, EncodeBytes, EncodePacked, EncodeTrace, Encoder, EntryEncoder, MapEncoder, + SequenceEncoder, +}; +use musli::{Allocator, Context}; + +// Uses the same heuristic as: +// https://github.com/serde-rs/serde/blob/d91f8ba950e2faf4db4e283e917ba2ee94a9b8a4/serde/src/de/size_hint.rs#L12 +#[inline] +pub(crate) fn cautious(hint: impl Into) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + if size_of::() == 0 { + return 0; + } + + hint.into() + .or_default() + .min(MAX_PREALLOC_BYTES / size_of::()) +} + +impl Encode for String { + type Encode = str; + + const IS_BITWISE_ENCODE: bool = false; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + self.as_str().encode(encoder) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self + } +} + +impl<'de, M, A> Decode<'de, M, A> for String +where + A: Allocator, +{ + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M>, + { + struct Visitor; + + #[musli::de::unsized_visitor] + impl UnsizedVisitor<'_, C, str> for Visitor + where + C: Context, + { + type Ok = String; + + #[inline] + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "string") + } + + #[inline] + fn visit_ref(self, cx: C, string: &str) -> Result { + string.try_to_owned().map_err(|e| cx.custom(e)) + } + } + + decoder.decode_string(Visitor) + } +} + +impl<'de, M, A> Decode<'de, M, A> for Box +where + A: Allocator, +{ + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M>, + { + let cx = decoder.cx(); + decoder + .decode::()? + .try_into() + .map_err(|e| cx.custom(e)) + } +} + +impl<'de, M, A, T> Decode<'de, M, A> for Box<[T]> +where + A: Allocator, + T: Decode<'de, M, A>, +{ + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + let cx = decoder.cx(); + decoder + .decode::>()? + .try_into() + .map_err(|e| cx.custom(e)) + } +} + +macro_rules! cow { + ( + $encode:ident :: $encode_fn:ident, + $as_encode:ident, + $decode:ident :: $decode_fn:ident, + $encode_packed:ident, + $decode_packed:ident, + $ty:ty, $source:ty, + $decode_method:ident, $cx:pat, + |$owned:ident| $owned_expr:expr, + |$borrowed:ident| $borrowed_expr:expr, + |$reference:ident| $reference_expr:expr $(,)? + ) => { + impl $encode for Cow<'_, $ty> { + const $encode_packed: bool = false; + + type $encode = $ty; + + #[inline] + fn $encode_fn(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + self.as_ref().$encode_fn(encoder) + } + + #[inline] + fn $as_encode(&self) -> &Self::$encode { + self + } + } + + impl<'de, M, A> $decode<'de, M, A> for Cow<'_, $ty> + where + A: Allocator, + { + const $decode_packed: bool = false; + + #[inline] + fn $decode_fn(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + struct Visitor; + + #[musli::de::unsized_visitor] + impl<'de, C> UnsizedVisitor<'de, C, $source> for Visitor + where + C: Context, + { + type Ok = Cow<'static, $ty>; + + #[inline] + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "a string") + } + + #[inline] + fn visit_owned( + self, + $cx: C, + $owned: <$source as ToOwned>::Owned, + ) -> Result { + Ok($owned_expr) + } + + #[inline] + fn visit_borrowed( + self, + $cx: C, + $borrowed: &'de $source, + ) -> Result { + Ok($borrowed_expr) + } + + #[inline] + fn visit_ref( + self, + $cx: C, + $reference: &$source, + ) -> Result { + Ok($reference_expr) + } + } + + decoder.$decode_method(Visitor) + } + } + }; +} + +cow! { + Encode::encode, + as_encode, + Decode::decode, + IS_BITWISE_ENCODE, + IS_BITWISE_DECODE, + str, str, decode_string, cx, + |owned| { + match owned.into_std() { + Ok(owned) => Cow::Owned(owned.try_into().map_err(|e| cx.custom(e))?), + Err(owned) => { + Cow::Owned(TryToOwned::try_to_owned(owned.as_str()).map_err(|e| cx.custom(e))?) + } + } + }, + |borrowed| Cow::Owned(TryToOwned::try_to_owned(borrowed).map_err(|e| cx.custom(e))?), + |reference| Cow::Owned(TryToOwned::try_to_owned(reference).map_err(|e| cx.custom(e))?), +} + +cow! { + EncodeBytes::encode_bytes, + as_encode_bytes, + DecodeBytes::decode_bytes, + ENCODE_BYTES_PACKED, + DECODE_BYTES_PACKED, + [u8], [u8], decode_bytes, cx, + |owned| { + match owned.into_std() { + Ok(owned) => Cow::Owned(owned.try_into().map_err(|e| cx.custom(e))?), + Err(owned) => Cow::Owned(TryToOwned::try_to_owned(owned.as_slice()).map_err(|e| cx.custom(e))?), + } + }, + |borrowed| Cow::Owned(TryToOwned::try_to_owned(borrowed).map_err(|e| cx.custom(e))?), + |reference| Cow::Owned(TryToOwned::try_to_owned(reference).map_err(|e| cx.custom(e))?), +} + +macro_rules! sequence { + ( + $(#[$($meta:meta)*])* + $cx:ident, + $ty:ident , + $insert:ident, + $access:ident, + $factory:expr + ) => { + $(#[$($meta)*])* + impl Encode for $ty + where + T: Encode, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + const IS_BITWISE_ENCODE: bool = false; + + type Encode = Self; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + let $cx = encoder.cx(); + + encoder.encode_sequence_fn(self.len(), |seq| { + let mut index = 0; + + for value in self { + $cx.enter_sequence_index(index); + seq.push(value)?; + $cx.leave_sequence_index(); + index = index.wrapping_add(1); + } + + Ok(()) + }) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self + } + } + + $(#[$($meta)*])* + impl<'de, M, A, T $(, $extra)*> Decode<'de, M, A> for $ty + where + A: Allocator, + T: Decode<'de, M, A> $(+ $trait0 $(+ $trait)*)*, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + let $cx = decoder.cx(); + + decoder.decode_sequence(|$access| { + let mut out = $factory; + + let mut index = 0; + + while let Some(value) = $access.try_decode_next()? { + $cx.enter_sequence_index(index); + out.$insert(value.decode()?).map_err(|e| $cx.custom(e))?; + $cx.leave_sequence_index(); + index = index.wrapping_add(1); + } + + Ok(out) + }) + } + } + + $(#[$($meta)*])* + impl EncodePacked for $ty + where + T: Encode, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + #[inline] + fn encode_packed(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + let $cx = encoder.cx(); + + encoder.encode_pack_fn(|pack| { + let mut index = 0; + + for value in self { + $cx.enter_sequence_index(index); + pack.push(value)?; + $cx.leave_sequence_index(); + index = index.wrapping_add(1); + } + + Ok(()) + }) + } + } + } +} + +macro_rules! slice_sequence { + ( + $(#[$($meta:meta)*])* + $cx:ident, + $ty:ident , + || $new:expr, + |$vec:ident, $value:ident| $insert:expr, + |$reserve_vec:ident, $reserve_capacity:ident| $reserve:expr, + |$capacity:ident| $with_capacity:expr, + ) => { + $(#[$($meta)*])* + impl Encode for $ty + where + T: Encode, + $($alloc: Allocator,)* + { + const IS_BITWISE_ENCODE: bool = false; + + type Encode = Self; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + encoder.encode_slice(self) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self + } + } + + $(#[$($meta)*])* + impl<'de, M, A, T> Decode<'de, M, A> for $ty + where + A: Allocator, + T: Decode<'de, M, A>, + { + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + struct Builder<'de, M, A, T> + where + $($alloc: Allocator,)* + { + vec: $ty, + _marker: core::marker::PhantomData<(M, A, &'de ())> + } + + #[allow(unused_variables)] + impl<'de, M, A, T> DecodeSliceBuilder for Builder<'de, M, A, T> + where + T: Decode<'de, M, A>, + A: Allocator, + { + #[inline] + fn new($cx: C) -> Result + where + C: Context, + { + Ok(Builder { + vec: $new, + _marker: core::marker::PhantomData + }) + } + + #[inline] + fn with_capacity($cx: C, $capacity: usize) -> Result + where + C: Context, + { + Ok(Builder { + vec: $with_capacity, + _marker: core::marker::PhantomData + }) + } + + #[inline] + fn push(&mut self, $cx: C, $value: T) -> Result<(), C::Error> + where + C: Context, + { + let $vec = &mut self.vec; + $insert; + Ok(()) + } + + #[inline] + fn reserve( &mut self, $cx: C, $reserve_capacity: usize) -> Result<(), C::Error> + where + C: Context, + { + let $reserve_vec = &mut self.vec; + $reserve; + Ok(()) + } + + #[inline] + unsafe fn set_len(&mut self, len: usize) { + self.vec.set_len(len); + } + + #[inline] + fn as_mut_ptr(&mut self) -> *mut T { + self.vec.as_mut_ptr() + } + } + + let Builder { vec, _marker: core::marker::PhantomData } = decoder.decode_slice()?; + Ok(vec) + } + } + + $(#[$($meta)*])* + impl EncodePacked for $ty + where + T: Encode, + $($alloc: Allocator,)* + { + #[inline] + fn encode_packed(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + encoder.encode_pack_fn(|pack| { + SequenceEncoder::encode_slice(pack, self) + }) + } + } + } +} + +slice_sequence! { + cx, + Vec, + || Vec::new(), + |vec, value| vec.try_push(value).map_err(|e| cx.custom(e))?, + |vec, capacity| vec.try_reserve(capacity).map_err(|e| cx.custom(e))?, + |size| Vec::try_with_capacity(size).map_err(|e| cx.custom(e))?, +} + +impl Encode for VecDeque +where + T: Encode, +{ + type Encode = Self; + + const IS_BITWISE_ENCODE: bool = false; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + let (a, b) = self.as_slices(); + encoder.encode_slices(self.len(), [a, b]) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self + } +} + +impl<'de, M, A, T> Decode<'de, M, A> for VecDeque +where + A: Allocator, + T: Decode<'de, M, A>, +{ + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + Ok(VecDeque::from(Vec::decode(decoder)?)) + } +} + +impl EncodePacked for VecDeque +where + T: Encode, +{ + #[inline] + fn encode_packed(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + encoder.encode_pack_fn(|pack| { + let (a, b) = self.as_slices(); + pack.encode_slices([a, b]) + }) + } +} + +sequence! { + cx, + BTreeSet, + try_insert, + seq, + BTreeSet::new() +} + +sequence! { + cx, + HashSet, + try_insert, + seq, + HashSet::try_with_capacity_and_hasher(cautious::(seq.size_hint()), S::default()).map_err(|e| cx.custom(e))? +} + +macro_rules! map { + ( + $(#[$($meta:meta)*])* + $cx:ident, + $ty:ident, + $access:ident, + $with_capacity:expr + ) => { + $(#[$($meta)*])* + impl<'de, M, K, V $(, $extra)*> Encode for $ty + where + K: Encode, + V: Encode, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + const IS_BITWISE_ENCODE: bool = false; + + type Encode = Self; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + let hint = self.len(); + + encoder.encode_map_fn(hint, |map| { + for (k, v) in self { + map.insert_entry(k, v)?; + } + + Ok(()) + }) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self + } + } + + $(#[$($meta)*])* + impl<'de, M, K, V $(, $extra)*> EncodeTrace for $ty + where + K: fmt::Display + Encode, + V: Encode, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + #[inline] + fn trace_encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + let hint = self.len(); + + let $cx = encoder.cx(); + + encoder.encode_map_fn(hint, |map| { + for (k, v) in self { + $cx.enter_map_key(k); + map.encode_entry_fn(|entry| { + entry.encode_key()?.encode(k)?; + entry.encode_value()?.encode(v)?; + Ok(()) + })?; + $cx.leave_map_key(); + } + + Ok(()) + }) + } + } + + $(#[$($meta)*])* + impl<'de, K, V, A, M $(, $extra)*> Decode<'de, M, A> for $ty + where + A: Allocator, + K: Decode<'de, M, A> $(+ $key_bound0 $(+ $key_bound)*)*, + V: Decode<'de, M, A>, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + let $cx = decoder.cx(); + + decoder.decode_map(|$access| { + let mut out = $with_capacity; + + while let Some((key, value)) = $access.entry()? { + out.try_insert(key, value).map_err(|e| $cx.custom(e))?; + } + + Ok(out) + }) + } + } + + $(#[$($meta)*])* + impl<'de, K, V, A, M $(, $extra)*> DecodeTrace<'de, M, A> for $ty + where + A: Allocator, + K: fmt::Display + Decode<'de, M, A> $(+ $key_bound0 $(+ $key_bound)*)*, + V: Decode<'de, M, A>, + $($extra: $extra_bound0 $(+ $extra_bound)*),* + { + #[inline] + fn trace_decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + let $cx = decoder.cx(); + + decoder.decode_map(|$access| { + let mut out = $with_capacity; + + while let Some(mut entry) = $access.decode_entry()? { + let key = entry.decode_key()?.decode()?; + $cx.enter_map_key(&key); + let value = entry.decode_value()?.decode()?; + out.try_insert(key, value).map_err(|e| $cx.custom(e))?; + $cx.leave_map_key(); + } + + Ok(out) + }) + } + } + } +} + +map!(_cx, BTreeMap, map, BTreeMap::new()); + +map!( + cx, + HashMap, + map, + HashMap::try_with_capacity_and_hasher(cautious::<(K, V)>(map.size_hint()), S::default()).map_err(|e| cx.custom(e))? +); + +macro_rules! smart_pointer { + ($($ty:ident),* $(,)?) => { + $( + impl Encode for $ty + where + T: ?Sized + Encode, + { + const IS_BITWISE_ENCODE: bool = false; + + type Encode = T; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + self.as_ref().encode(encoder) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self + } + } + + impl<'de, M, A, T> Decode<'de, M, A> for $ty + where + A: Allocator, + T: Decode<'de, M, A>, + { + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + let cx = decoder.cx(); + $ty::try_new(decoder.decode()?).map_err(|e| cx.custom(e)) + } + } + + impl<'de, M, A> DecodeBytes<'de, M, A> for $ty<[u8]> + where + A: Allocator + { + const DECODE_BYTES_PACKED: bool = false; + + #[inline] + fn decode_bytes(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + let cx = decoder.cx(); + $ty::try_from(>::decode_bytes(decoder)?).map_err(|e| cx.custom(e)) + } + } + )* + }; +} + +smart_pointer!(Box); + +impl EncodeBytes for Vec { + const ENCODE_BYTES_PACKED: bool = false; + + type EncodeBytes = [u8]; + + #[inline] + fn encode_bytes(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + encoder.encode_bytes(self.as_slice()) + } + + #[inline] + fn as_encode_bytes(&self) -> &Self::EncodeBytes { + self + } +} + +impl EncodeBytes for Box<[u8]> { + const ENCODE_BYTES_PACKED: bool = false; + + type EncodeBytes = [u8]; + + #[inline] + fn encode_bytes(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + encoder.encode_bytes(self.as_ref()) + } + + #[inline] + fn as_encode_bytes(&self) -> &Self::EncodeBytes { + self + } +} + +impl<'de, M, A> DecodeBytes<'de, M, A> for Vec +where + A: Allocator, +{ + const DECODE_BYTES_PACKED: bool = false; + + #[inline] + fn decode_bytes(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + struct Visitor; + + #[musli::de::unsized_visitor] + impl<'de, C> UnsizedVisitor<'de, C, [u8]> for Visitor + where + C: Context, + { + type Ok = Vec; + + #[inline] + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "bytes") + } + + #[inline] + fn visit_borrowed(self, cx: C, bytes: &'de [u8]) -> Result { + Vec::try_from(bytes).map_err(|e| cx.custom(e)) + } + + #[inline] + fn visit_ref(self, cx: C, bytes: &[u8]) -> Result { + Vec::try_from(bytes).map_err(|e| cx.custom(e)) + } + } + + decoder.decode_bytes(Visitor) + } +} + +impl EncodeBytes for VecDeque { + const ENCODE_BYTES_PACKED: bool = false; + + type EncodeBytes = VecDeque; + + #[inline] + fn encode_bytes(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + let (first, second) = self.as_slices(); + encoder.encode_bytes_vectored(self.len(), &[first, second]) + } + + #[inline] + fn as_encode_bytes(&self) -> &Self::EncodeBytes { + self + } +} + +impl<'de, M, A> DecodeBytes<'de, M, A> for VecDeque +where + A: Allocator, +{ + const DECODE_BYTES_PACKED: bool = false; + + #[inline] + fn decode_bytes(decoder: D) -> Result + where + D: Decoder<'de, Mode = M, Allocator = A>, + { + Ok(VecDeque::from(>::decode_bytes(decoder)?)) + } +} diff --git a/crates/rune-alloc/src/path.rs b/crates/rune-alloc/src/path.rs index c64422ebd..74f7f28e6 100644 --- a/crates/rune-alloc/src/path.rs +++ b/crates/rune-alloc/src/path.rs @@ -16,7 +16,7 @@ impl Path { #[inline] pub fn new

(path: &P) -> &Path where - P: ?Sized + AsRef, + P: ?Sized + AsRef<[u8]>, { unsafe { &*(path.as_ref() as *const _ as *const Path) } } diff --git a/crates/rune-alloc/src/ptr.rs b/crates/rune-alloc/src/ptr.rs index 447deb54f..32f02747f 100644 --- a/crates/rune-alloc/src/ptr.rs +++ b/crates/rune-alloc/src/ptr.rs @@ -58,55 +58,3 @@ pub const fn invalid_mut(addr: usize) -> *mut T { // pointer). unsafe { mem::transmute(addr) } } - -cfg_if! { - if #[cfg(rune_nightly)] { - #[inline(always)] - pub(crate) unsafe fn sub_ptr(from: *const T, to: *const T) -> usize { - from.offset_from_unsigned(to) - } - } else { - #[inline(always)] - pub(crate) unsafe fn sub_ptr(from: *const T, to: *const T) -> usize { - const { - let pointee_size = mem::size_of::(); - assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); - } - - debug_assert!(addr(from) >= addr(to)); - addr(from).wrapping_sub(addr(to)).saturating_div(mem::size_of::()) - } - } -} - -cfg_if! { - if #[cfg(rune_nightly)] { - #[inline(always)] - pub(crate) fn addr(from: *const T) -> usize { - from.addr() - } - } else { - #[inline(always)] - pub(crate) fn addr(from: *const T) -> usize { - from as usize - } - } -} - -cfg_if! { - if #[cfg(rune_nightly)] { - #[inline(always)] - pub(crate) fn slice_len(from: *const [T]) -> usize { - from.len() - } - } else { - #[inline(always)] - pub(crate) fn slice_len(from: *const [T]) -> usize { - // SAFETY: This is *a bit* tricky, but the raw pointer contains the - // length and *should* be safe to dereference like this. However, - // walking through the dereferenced `[T]` is not necessarily - // correct. - unsafe { (*from).len() } - } - } -} diff --git a/crates/rune-alloc/src/slice/iter/macros.rs b/crates/rune-alloc/src/slice/iter/macros.rs index 4c8a534b5..d63c07205 100644 --- a/crates/rune-alloc/src/slice/iter/macros.rs +++ b/crates/rune-alloc/src/slice/iter/macros.rs @@ -22,7 +22,7 @@ macro_rules! if_zst { }}; ($this:ident, $len:ident => $zst_body:expr, $end:ident => $other_body:expr,) => {{ if T::IS_ZST { - let $len = ptr::addr($this.end_or_len); + let $len = $this.end_or_len.addr(); $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null @@ -50,7 +50,7 @@ macro_rules! len { // To get rid of some bounds checks (see `position`), we use ptr_sub instead of // offset_from (Tested by `codegen/slice-position-bounds-check`.) // SAFETY: by the type invariant pointers are aligned and `start <= end` - unsafe { ptr::sub_ptr(end.as_ptr(), $self.ptr.as_ptr()) } + unsafe { end.as_ptr().offset_from_unsigned($self.ptr.as_ptr()) } }, ) }}; diff --git a/crates/rune-alloc/src/str.rs b/crates/rune-alloc/src/str.rs index a091aec51..857cc72a4 100644 --- a/crates/rune-alloc/src/str.rs +++ b/crates/rune-alloc/src/str.rs @@ -7,6 +7,8 @@ use crate::borrow::TryToOwned; use crate::boxed::Box; use crate::error::Error; use crate::string::String; +use crate::vec::Vec; +use crate::Result; /// Converts a boxed slice of bytes to a boxed string slice without checking /// that the string contains valid UTF-8. @@ -59,6 +61,79 @@ pub fn into_string(this: Box) -> String { unsafe { String::::from_utf8_unchecked(vec) } } +/// Replaces all matches of a pattern with another string. +/// +/// `replace` creates a new [`String`], and copies the data from this string slice into it. +/// While doing so, it attempts to find matches of a pattern. If it finds any, it +/// replaces them with the replacement string slice. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let s = "this is old"; +/// +/// assert_eq!("this is new", rune::alloc::str::replace(s, "old", "new")?); +/// assert_eq!("than an old", rune::alloc::str::replace(s, "is", "an")?); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// When the pattern doesn't match, it returns this string slice as [`String`]: +/// +/// ``` +/// let s = "this is old"; +/// assert_eq!(s, rune::alloc::str::replace(s, "cookie monster", "little lamb")?); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// Single ascii-character replacements are optimized for performance: +/// +/// ``` +/// assert_eq!("say", rune::alloc::str::replace("bay", "b", "s")?); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +pub fn replace(string: &str, from: &str, to: &str) -> Result { + // Fast path for replacing a single ASCII character with another. + if let (&[from_byte], &[to_byte]) = (from.as_bytes(), to.as_bytes()) { + return unsafe { replace_ascii(string.as_bytes(), from_byte, to_byte) }; + } + + // Set result capacity to self.len() when from.len() <= to.len() + let default_capacity = if from.len() <= to.len() { + string.len() + } else { + 0 + }; + + let mut result = String::try_with_capacity(default_capacity)?; + let mut last_end = 0; + + for (start, part) in string.match_indices(from) { + result.try_push_str(unsafe { string.get_unchecked(last_end..start) })?; + result.try_push_str(to)?; + last_end = start + part.len(); + } + + result.try_push_str(unsafe { string.get_unchecked(last_end..string.len()) })?; + Ok(result) +} + +unsafe fn replace_ascii(bytes: &[u8], from: u8, to: u8) -> Result { + let mut result = Vec::try_with_capacity(bytes.len())?; + + for &b in bytes { + if b == from { + result.try_push(to)?; + } else { + result.try_push(b)?; + } + } + + // SAFETY: We replaced ascii with ascii on valid utf8 strings. + Ok(String::from_utf8_unchecked(result)) +} + impl TryToOwned for str { type Owned = String; diff --git a/crates/rune-alloc/src/string/mod.rs b/crates/rune-alloc/src/string/mod.rs index 887cb70bb..113b85f7d 100644 --- a/crates/rune-alloc/src/string/mod.rs +++ b/crates/rune-alloc/src/string/mod.rs @@ -466,9 +466,9 @@ impl String { /// /// The memory previously occupied by this vector will be released. #[cfg(feature = "alloc")] - pub fn into_std(self) -> ::rust_alloc::string::String { + pub fn into_std(self) -> rust_alloc::string::String { // SAFETY: The interior vector is valid UTF-8. - unsafe { ::rust_alloc::string::String::from_utf8_unchecked(self.vec.into_std()) } + unsafe { rust_alloc::string::String::from_utf8_unchecked(self.vec.into_std()) } } #[cfg(test)] @@ -2032,19 +2032,19 @@ impl From> for String { } #[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::boxed::Box> for String { +impl TryFrom> for String { type Error = Error; /// Try to convert a std `Box` into a [`String`]. /// /// The result is fallibly allocated on the heap. - fn try_from(s: ::rust_alloc::boxed::Box) -> Result { + fn try_from(s: rust_alloc::boxed::Box) -> Result { Self::try_from(s.as_ref()) } } #[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::string::String> for String { +impl TryFrom for String { type Error = Error; /// Try to convert a std `String` into a [`String`]. @@ -2062,7 +2062,7 @@ impl TryFrom<::rust_alloc::string::String> for String { /// assert_eq!("Hello World", s2); /// # Ok::<_, rune::alloc::Error>(()) /// ``` - fn try_from(string: ::rust_alloc::string::String) -> Result { + fn try_from(string: rust_alloc::string::String) -> Result { let mut string = ManuallyDrop::new(string.into_bytes()); let buf = string.as_mut_ptr(); @@ -2080,7 +2080,7 @@ impl TryFrom<::rust_alloc::string::String> for String { } #[cfg(feature = "alloc")] -impl From> for ::rust_alloc::string::String { +impl From> for rust_alloc::string::String { /// Try to convert a [`String`] into a std `String`. /// /// The result is allocated on the heap. @@ -2090,7 +2090,7 @@ impl From> for ::rust_alloc::string::String { } #[cfg(feature = "alloc")] -impl From<&String> for ::rust_alloc::string::String { +impl From<&String> for rust_alloc::string::String { /// Try to convert a [`String`] reference into a std `String`. /// /// The result is allocated on the heap. diff --git a/crates/rune-alloc/src/string/serde.rs b/crates/rune-alloc/src/string/serde.rs index 71f1f486e..895530d34 100644 --- a/crates/rune-alloc/src/string/serde.rs +++ b/crates/rune-alloc/src/string/serde.rs @@ -72,7 +72,7 @@ impl de::Visitor<'_> for StringVisitor { v.try_to_owned().map_err(E::custom) } - fn visit_string(self, v: ::rust_alloc::string::String) -> Result + fn visit_string(self, v: rust_alloc::string::String) -> Result where E: Error, { @@ -89,7 +89,7 @@ impl de::Visitor<'_> for StringVisitor { } } - fn visit_byte_buf(self, v: ::rust_alloc::vec::Vec) -> Result + fn visit_byte_buf(self, v: rust_alloc::vec::Vec) -> Result where E: Error, { @@ -121,7 +121,7 @@ impl de::Visitor<'_> for StringInPlaceVisitor<'_> { Ok(()) } - fn visit_string(self, v: ::rust_alloc::string::String) -> Result + fn visit_string(self, v: rust_alloc::string::String) -> Result where E: Error, { @@ -143,7 +143,7 @@ impl de::Visitor<'_> for StringInPlaceVisitor<'_> { } } - fn visit_byte_buf(self, v: ::rust_alloc::vec::Vec) -> Result + fn visit_byte_buf(self, v: rust_alloc::vec::Vec) -> Result where E: Error, { diff --git a/crates/rune-alloc/src/sync.rs b/crates/rune-alloc/src/sync.rs new file mode 100644 index 000000000..77bed2656 --- /dev/null +++ b/crates/rune-alloc/src/sync.rs @@ -0,0 +1,1749 @@ +use core::alloc::Layout; +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::hint; +use core::marker::PhantomData; +use core::mem; +use core::ops::Deref; +use core::panic::RefUnwindSafe; +use core::panic::UnwindSafe; +use core::ptr; +use core::ptr::NonNull; +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; + +use crate::abort; +use crate::alloc::{AllocError, Allocator, Global}; +use crate::{Box, Result}; + +fn is_dangling(ptr: *const T) -> bool { + (ptr.cast::<()>()).addr() == usize::MAX +} + +#[must_use] +unsafe fn for_value_raw(t: *const T) -> Layout +where + T: ?Sized, +{ + // SAFETY: we pass along the prerequisites of these functions to the caller + // TODO: Use mem::{size_of_val_raw, align_of_val_raw} when they become + // stable, for now we privately know that this can safely be turned into a + // reference since it's only used while dropping an owned value of type `T`. + let (size, align) = unsafe { (mem::size_of_val(&*t), mem::align_of_val(&*t)) }; + // SAFETY: see rationale in `new` for why this is using the unsafe variant + unsafe { Layout::from_size_align_unchecked(size, align) } +} + +/// A soft limit on the amount of references that may be made to an `Arc`. +/// +/// Going above this limit will abort your program (although not necessarily) at +/// _exactly_ `MAX_REFCOUNT + 1` references. Trying to go above it might call a +/// `panic` (if not actually going above it). +/// +/// This is a global invariant, and also applies when using a compare-exchange +/// loop. +/// +/// See comment in `Arc::clone`. +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + +/// The error in case either counter reaches above `MAX_REFCOUNT`, and we can `panic` safely. +const INTERNAL_OVERFLOW_ERROR: &str = "Arc counter overflow"; + +macro_rules! acquire { + ($x:expr) => { + core::sync::atomic::fence(Acquire) + }; +} + +/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically +/// Reference Counted'. +/// +/// The type `Arc` provides shared ownership of a value of type `T`, +/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces a new +/// `Arc` instance, which points to the same allocation on the heap as the +/// source `Arc`, while increasing a reference count. When the last `Arc` +/// pointer to a given allocation is destroyed, the value stored in that +/// allocation (often referred to as "inner value") is also dropped. +/// +/// Shared references in Rust disallow mutation by default, and `Arc` is no +/// exception: you cannot generally obtain a mutable reference to something +/// inside an `Arc`. If you do need to mutate through an `Arc`, you have several +/// options: +/// +/// 1. Use interior mutability with synchronization primitives like +/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] +/// types. +/// +/// 2. Use [`Arc::get_mut`] when you know your `Arc` is not shared (has a +/// reference count of 1), which provides direct mutable access to the inner +/// value without any cloning. +/// +/// ``` +/// use rune::alloc::sync::Arc; +/// use rune::alloc::try_vec; +/// +/// let mut data = Arc::try_new(try_vec![1, 2, 3])?; +/// +/// // This will clone the vector only if there are other references to it +/// Arc::get_mut(&mut data).unwrap().try_push(4)?; +/// +/// assert_eq!(*data, try_vec![1, 2, 3, 4]); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// **Note**: This type is only available on platforms that support atomic loads +/// and stores of pointers, which includes all platforms that support the `std` +/// crate but not all those which only support [`alloc`](crate). This may be +/// detected at compile time using `#[cfg(target_has_atomic = "ptr")]`. +/// +/// ## Thread Safety +/// +/// Unlike `Rc`, `Arc` uses atomic operations for its reference counting. +/// This means that it is thread-safe. The disadvantage is that atomic +/// operations are more expensive than ordinary memory accesses. If you are not +/// sharing reference-counted allocations between threads, consider using +/// `Rc` for lower overhead. `Rc` is a safe default, because the compiler +/// will catch any attempt to send an `Rc` between threads. However, a +/// library might choose `Arc` in order to give library consumers more +/// flexibility. +/// +/// `Arc` will implement [`Send`] and [`Sync`] as long as the `T` implements +/// [`Send`] and [`Sync`]. Why can't you put a non-thread-safe type `T` in an +/// `Arc` to make it thread-safe? This may be a bit counter-intuitive at +/// first: after all, isn't the point of `Arc` thread safety? The key is +/// this: `Arc` makes it thread safe to have multiple ownership of the same +/// data, but it doesn't add thread safety to its data. Consider +/// Arc<[RefCell\]>. [`RefCell`] isn't [`Sync`], and if +/// `Arc` was always [`Send`], Arc<[RefCell\]> would be as +/// well. But then we'd have a problem: [`RefCell`] is not thread safe; it +/// keeps track of the borrowing count using non-atomic operations. +/// +/// In the end, this means that you may need to pair `Arc` with some sort of +/// [`std::sync`] type, usually [`Mutex`][mutex]. +/// +/// ## Breaking cycles with `Weak` +/// +/// The [`downgrade`][downgrade] method can be used to create a non-owning +/// [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d to an +/// `Arc`, but this will return [`None`] if the value stored in the allocation +/// has already been dropped. In other words, `Weak` pointers do not keep the +/// value inside the allocation alive; however, they *do* keep the allocation +/// (the backing store for the value) alive. +/// +/// A cycle between `Arc` pointers will never be deallocated. For this reason, +/// [`Weak`] is used to break cycles. For example, a tree could have strong +/// `Arc` pointers from parent nodes to children, and [`Weak`] pointers from +/// children back to their parents. +/// +/// # Cloning references +/// +/// Creating a new reference from an existing reference-counted pointer is done +/// using the `Clone` trait implemented for [`Arc`][Arc] and +/// [`Weak`][Weak]. +/// +/// ``` +/// use rune::alloc::sync::Arc; +/// use rune::alloc::try_vec; +/// +/// let foo = Arc::try_new(try_vec![1.0, 2.0, 3.0])?; +/// // The two syntaxes below are equivalent. +/// let a = foo.clone(); +/// let b = Arc::clone(&foo); +/// // a, b, and foo are all Arcs that point to the same memory location +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// ## `Deref` behavior +/// +/// `Arc` automatically dereferences to `T` (via the [`Deref`] trait), so you +/// can call `T`'s methods on a value of type `Arc`. To avoid name clashes +/// with `T`'s methods, the methods of `Arc` itself are associated functions, +/// called using [fully qualified syntax]: +/// +/// ``` +/// use rune::alloc::sync::Arc; +/// +/// let my_arc = Arc::try_new(())?; +/// let my_weak = Arc::downgrade(&my_arc); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// `Arc`'s implementations of traits like `Clone` may also be called using +/// fully qualified syntax. Some people prefer to use fully qualified syntax, +/// while others prefer using method-call syntax. +/// +/// ``` +/// use rune::alloc::sync::Arc; +/// +/// let arc = Arc::try_new(())?; +/// // Method-call syntax +/// let arc2 = arc.clone(); +/// // Fully qualified syntax +/// let arc3 = Arc::clone(&arc); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// [`Weak`][Weak] does not auto-dereference to `T`, because the inner value +/// may have already been dropped. +/// +/// [clone]: Clone::clone +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [atomic]: core::sync::atomic +/// [downgrade]: Arc::downgrade +/// [upgrade]: Weak::upgrade +/// [RefCell\]: core::cell::RefCell +/// [`RefCell`]: core::cell::RefCell +/// [`std::sync`]: ../../std/sync/index.html +/// [`Arc::clone(&from)`]: Arc::clone +/// [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name +/// +/// # Examples +/// +/// Sharing some immutable data between threads: +/// +/// ``` +/// use std::thread; +/// +/// use rune::alloc::sync::Arc; +/// +/// let five = Arc::try_new(5)?; +/// +/// for _ in 0..10 { +/// let five = Arc::clone(&five); +/// +/// thread::spawn(move || { +/// println!("{five:?}"); +/// }); +/// } +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +/// +/// Sharing a mutable [`AtomicUsize`]: +/// +/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize" +/// +/// ``` +/// use std::sync::atomic::{AtomicUsize, Ordering}; +/// use std::thread; +/// +/// use rune::alloc::sync::Arc; +/// +/// let val = Arc::try_new(AtomicUsize::new(5))?; +/// +/// for _ in 0..10 { +/// let val = Arc::clone(&val); +/// +/// thread::spawn(move || { +/// let v = val.fetch_add(1, Ordering::Relaxed); +/// println!("{v:?}"); +/// }); +/// } +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +pub struct Arc +where + T: ?Sized, + A: Allocator, +{ + ptr: NonNull>, + phantom: PhantomData>, + alloc: A, +} + +unsafe impl Send for Arc +where + T: ?Sized + Sync + Send, + A: Allocator + Send, +{ +} + +unsafe impl Sync for Arc +where + T: ?Sized + Sync + Send, + A: Allocator + Sync, +{ +} + +impl UnwindSafe for Arc +where + T: RefUnwindSafe + ?Sized, + A: Allocator + UnwindSafe, +{ +} + +impl Arc<[T], A> +where + A: Allocator, +{ + /// Allocates an `ArcInner<[T]>` with the given length. + unsafe fn try_allocate_for_slice_in( + len: usize, + alloc: &A, + ) -> Result<*mut ArcInner<[T]>, AllocError> { + unsafe { + Self::try_allocate_for_layout( + Layout::array::(len).unwrap(), + |layout| alloc.allocate(layout), + |mem| ptr::slice_from_raw_parts_mut(mem.cast::(), len) as *mut ArcInner<[T]>, + ) + } + } + + /// Copy elements from slice into newly allocated `Arc<[T]>` + /// + /// Unsafe because the caller must either take ownership or bind `T: Copy`. + unsafe fn copy_from_slice_in(v: &[T], alloc: A) -> Result { + unsafe { + let ptr = Self::try_allocate_for_slice_in(v.len(), &alloc)?; + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).data) as *mut T, v.len()); + Ok(Self::from_ptr_in(ptr, alloc)) + } + } +} + +/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the +/// managed allocation. +/// +/// The allocation is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [Option]<[Arc]\>. +/// +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present. Thus it may return [`None`] +/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation +/// itself (the backing store) from being deallocated. +/// +/// A `Weak` pointer is useful for keeping a temporary reference to the allocation +/// managed by [`Arc`] without preventing its inner value from being dropped. It is also used to +/// prevent circular references between [`Arc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. +/// +/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. +/// +/// [`upgrade`]: Weak::upgrade +pub struct Weak +where + T: ?Sized, + A: Allocator, +{ + // This is a `NonNull` to allow optimizing the size of this type in enums, + // but it is not necessarily a valid pointer. + // `Weak::new` sets this to `usize::MAX` so that it doesn’t need + // to allocate space on the heap. That's not a value a real pointer + // will ever have because RcInner has alignment at least 2. + // This is only possible when `T: Sized`; unsized `T` never dangle. + ptr: NonNull>, + alloc: A, +} + +/// Helper type to allow accessing the reference counts without making any +/// assertions about the data field. +struct WeakInner<'a> { + weak: &'a AtomicUsize, + #[allow(unused)] + strong: &'a AtomicUsize, +} + +impl Weak +where + T: ?Sized, + A: Allocator, +{ + /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying dropping + /// of the inner value if successful. + /// + /// Returns [`None`] if the inner value has since been dropped. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// let weak_five = Arc::downgrade(&five); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[must_use = "this returns a new `Arc`, \ + without modifying the original weak pointer"] + pub fn upgrade(&self) -> Option> + where + A: Clone, + { + #[inline] + fn checked_increment(n: usize) -> Option { + // Any write of 0 we can observe leaves the field in permanently zero state. + if n == 0 { + return None; + } + + // See comments in `Arc::clone` for why we do this (for `mem::forget`). + assert!(n <= MAX_REFCOUNT, "{}", INTERNAL_OVERFLOW_ERROR); + Some(n + 1) + } + + // We use a CAS loop to increment the strong count instead of a + // fetch_add as this function should never take the reference count + // from zero to one. + // + // Relaxed is fine for the failure case because we don't have any expectations about the new state. + // Acquire is necessary for the success case to synchronise with `Arc::new_cyclic`, when the inner + // value can be initialized after `Weak` references have already been created. In that case, we + // expect to observe the fully initialized value. + if self + .inner()? + .strong + .fetch_update(Acquire, Relaxed, checked_increment) + .is_ok() + { + // SAFETY: pointer is not null, verified in checked_increment + unsafe { Some(Arc::from_inner_in(self.ptr, self.alloc.clone())) } + } else { + None + } + } + + /// Gets the number of strong (`Arc`) pointers pointing to this allocation. + #[must_use] + pub fn strong_count(&self) -> usize { + if let Some(inner) = self.inner() { + inner.strong.load(Relaxed) + } else { + 0 + } + } + + /// Gets an approximation of the number of `Weak` pointers pointing to this + /// allocation. + /// + /// # Accuracy + /// + /// Due to implementation details, the returned value can be off by 1 in + /// either direction when other threads are manipulating any `Arc`s or + /// `Weak`s pointing to the same allocation. + #[must_use] + pub fn weak_count(&self) -> usize { + if let Some(inner) = self.inner() { + let weak = inner.weak.load(Acquire); + let strong = inner.strong.load(Relaxed); + if strong == 0 { + 0 + } else { + // Since we observed that there was at least one strong pointer + // after reading the weak count, we know that the implicit weak + // reference (present whenever any strong references are alive) + // was still around when we observed the weak count, and can + // therefore safely subtract it. + weak - 1 + } + } else { + 0 + } + } + + /// Returns `None` when the pointer is dangling and there is no allocated + /// `ArcInner`. + #[inline] + fn inner(&self) -> Option> { + let ptr = self.ptr.as_ptr(); + + if is_dangling(ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" + // field, as the field may be mutated concurrently (for example, if + // the last `Arc` is dropped, the data field will be dropped + // in-place). + Some(unsafe { + WeakInner { + strong: &(*ptr).strong, + weak: &(*ptr).weak, + } + }) + } + } +} + +impl Clone for Weak +where + T: ?Sized, + A: Allocator + Clone, +{ + /// Makes a clone of the `Weak` pointer that points to the same allocation. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::{Arc, Weak}; + /// + /// let weak_five = Arc::downgrade(&Arc::try_new(5)?); + /// + /// let _ = Weak::clone(&weak_five); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn clone(&self) -> Weak { + if let Some(inner) = self.inner() { + // See comments in Arc::clone() for why this is relaxed. This can use a + // fetch_add (ignoring the lock) because the weak count is only locked + // where are *no other* weak pointers in existence. (So we can't be + // running this code in that case). + let old_size = inner.weak.fetch_add(1, Relaxed); + + // See comments in Arc::clone() for why we do this (for mem::forget). + if old_size > MAX_REFCOUNT { + abort(); + } + } + + Weak { + ptr: self.ptr, + alloc: self.alloc.clone(), + } + } +} + +impl Drop for Weak +where + T: ?Sized, + A: Allocator, +{ + /// Drops the `Weak` pointer. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::{Arc, Weak}; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Arc::try_new(Foo)?; + /// let weak_foo = Arc::downgrade(&foo); + /// let other_weak_foo = Weak::clone(&weak_foo); + /// + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn drop(&mut self) { + // If we find out that we were the last weak pointer, then its time to + // deallocate the data entirely. See the discussion in Arc::drop() about + // the memory orderings + // + // It's not necessary to check for the locked state here, because the + // weak count can only be locked if there was precisely one weak ref, + // meaning that drop could only subsequently run ON that remaining weak + // ref, which can only happen after the lock is released. + let Some(inner) = self.inner() else { + return; + }; + + if inner.weak.fetch_sub(1, Release) == 1 { + acquire!(inner.weak); + + // Make sure we aren't trying to "deallocate" the shared static for empty slices + // used by Default::default. + debug_assert!( + !ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner), + "Arc/Weaks backed by a static should never be deallocated. \ + Likely decrement_strong_count or from_raw were called too many times.", + ); + + unsafe { + self.alloc + .deallocate(self.ptr.cast(), for_value_raw(self.ptr.as_ptr())) + } + } + } +} + +unsafe impl Send for Weak +where + T: ?Sized + Sync + Send, + A: Allocator + Send, +{ +} +unsafe impl Sync for Weak +where + T: ?Sized + Sync + Send, + A: Allocator + Sync, +{ +} + +impl fmt::Debug for Weak +where + T: ?Sized, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "(Weak)") + } +} + +// This is repr(C) to future-proof against possible field-reordering, which +// would interfere with otherwise safe [into|from]_raw() of transmutable +// inner types. +#[repr(C)] +struct ArcInner +where + T: ?Sized, +{ + strong: AtomicUsize, + + // the value usize::MAX acts as a sentinel for temporarily "locking" the + // ability to upgrade weak pointers or downgrade strong ones; this is used + // to avoid races in `make_mut` and `get_mut`. + weak: AtomicUsize, + + data: T, +} + +/// Calculate layout for `ArcInner` using the inner value's layout +fn arcinner_layout_for_value_layout(layout: Layout) -> Layout { + // Calculate layout using the given value layout. + // Previously, layout was calculated on the expression + // `&*(ptr as *const ArcInner)`, but this created a misaligned + // reference (see #54908). + Layout::new::>() + .extend(layout) + .unwrap() + .0 + .pad_to_align() +} + +unsafe impl Send for ArcInner where T: ?Sized + Sync + Send {} +unsafe impl Sync for ArcInner where T: ?Sized + Sync + Send {} + +impl Arc { + /// Constructs a new `Arc`. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + pub fn try_new(data: T) -> Result> { + Self::try_new_in(data, Global) + } +} + +impl Arc +where + A: Allocator, +{ + /// Constructs a new `Arc` in the provided allocator. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// use rune::alloc::alloc::Global; + /// + /// let five = Arc::try_new_in(5, Global)?; + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + pub fn try_new_in(data: T, alloc: A) -> Result> { + // Start the weak pointer count as 1 which is the weak pointer that's + // held by all the strong pointers (kinda), see std/rc.rs for more info + let x = Box::try_new_in( + ArcInner { + strong: AtomicUsize::new(1), + weak: AtomicUsize::new(1), + data, + }, + alloc, + )?; + + let (ptr, alloc) = Box::into_unique_with_allocator(x); + Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) + } +} + +impl Arc +where + T: ?Sized, + A: Allocator, +{ + /// Returns a reference to the underlying allocator. + /// + /// Note: this is an associated function, which means that you have to call + /// it as `Arc::allocator(&a)` instead of `a.allocator()`. This is so that + /// there is no conflict with a method on the inner type. + #[inline] + pub fn allocator(this: &Self) -> &A { + &this.alloc + } + + /// Consumes the `Arc`, returning the wrapped pointer and allocator. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` + /// using [`Arc::from_raw_in`]. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::prelude::*; + /// use rune::alloc::sync::Arc; + /// use rune::alloc::alloc::Global; + /// + /// let x = Arc::try_new_in("hello".try_to_owned()?, Global)?; + /// let (ptr, alloc) = Arc::into_raw_with_allocator(x); + /// assert_eq!(unsafe { &*ptr }, "hello"); + /// let x = unsafe { Arc::from_raw_in(ptr, alloc) }; + /// assert_eq!(&*x, "hello"); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[must_use = "losing the pointer will leak memory"] + pub fn into_raw_with_allocator(this: Self) -> (*const T, A) { + let this = mem::ManuallyDrop::new(this); + let ptr = Self::as_ptr(&this); + // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped + let alloc = unsafe { ptr::read(&this.alloc) }; + (ptr, alloc) + } + + /// Provides a raw pointer to the data. + /// + /// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for + /// as long as there are strong counts in the `Arc`. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::prelude::*; + /// use rune::alloc::sync::Arc; + /// + /// let x = Arc::try_new("hello".try_to_owned()?)?; + /// let y = Arc::clone(&x); + /// let x_ptr = Arc::as_ptr(&x); + /// assert_eq!(x_ptr, Arc::as_ptr(&y)); + /// assert_eq!(unsafe { &*x_ptr }, "hello"); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[must_use] + pub fn as_ptr(this: &Self) -> *const T { + let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); + + // SAFETY: This cannot go through Deref::deref or RcInnerPtr::inner because + // this is required to retain raw/mut provenance such that e.g. `get_mut` can + // write through the pointer after the Rc is recovered through `from_raw`. + unsafe { &raw mut (*ptr).data } + } + + /// Constructs an `Arc` from a raw pointer. + /// + /// The raw pointer has the following requirements: + /// + /// * If `U` is sized, it must have the same size and alignment as `T`. This + /// is trivially true if `U` is `T`. + /// * If `U` is unsized, its data pointer must have the same size and + /// alignment as `T`. This is trivially true if `Arc` was constructed + /// through `Arc` and then converted to `Arc` through an [unsized + /// coercion]. + /// + /// Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`] for more information on what + /// restrictions apply in this case. + /// + /// The raw pointer must point to a block of memory allocated by `alloc` + /// + /// The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. + /// + /// This function is unsafe because improper use may lead to memory + /// unsafety, even if the returned `Arc` is never accessed. + /// + /// [unsized coercion]: + /// https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions + /// + /// # Safety + /// + /// The pointer must point to an instance which has previously ben returned + /// by [`Arc::into_raw_with_allocator`]. The allocator that was used must + /// also be compatible. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::prelude::*; + /// use rune::alloc::sync::Arc; + /// use rune::alloc::alloc::Global; + /// + /// let x = Arc::try_new_in("hello".try_to_owned()?, Global)?; + /// let (x_ptr, alloc) = Arc::into_raw_with_allocator(x); + /// + /// unsafe { + /// // Convert back to an `Arc` to prevent leak. + /// let x = Arc::from_raw_in(x_ptr, alloc); + /// assert_eq!(&*x, "hello"); + /// + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory-unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + /// + /// Convert a slice back into its original array: + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let original: &[u8] = &[1, 2, 3]; + /// let x: Arc<[u8]> = Arc::try_from(original)?; + /// let (x_ptr, alloc) = Arc::into_raw_with_allocator(x); + /// + /// unsafe { + /// let x: Arc<[u8; 3], _> = Arc::from_raw_in(x_ptr.cast::<[u8; 3]>(), alloc); + /// assert_eq!(&*x, &[1, 2, 3]); + /// } + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { + unsafe { + let offset = data_offset(ptr); + // Reverse the offset to find the original ArcInner. + let arc_ptr = ptr.byte_sub(offset) as *mut ArcInner; + Self::from_ptr_in(arc_ptr, alloc) + } + } + + /// Returns `true` if the two `Arc`s point to the same allocation in a vein + /// similar to [`ptr::eq`]. This function ignores the metadata of `dyn + /// Trait` pointers. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// let same_five = Arc::clone(&five); + /// let other_five = Arc::try_new(5)?; + /// + /// assert!(Arc::ptr_eq(&five, &same_five)); + /// assert!(!Arc::ptr_eq(&five, &other_five)); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + /// + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" + #[inline] + #[must_use] + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + ptr::addr_eq(this.ptr.as_ptr(), other.ptr.as_ptr()) + } + + /// Returns a mutable reference into the given `Arc`, if there are + /// no other `Arc` or [`Weak`] pointers to the same allocation. + /// + /// Returns [`None`] otherwise, because it is not safe to + /// mutate a shared value. + /// + /// [clone]: Clone::clone + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let mut x = Arc::try_new(3)?; + /// *Arc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = Arc::clone(&x); + /// assert!(Arc::get_mut(&mut x).is_none()); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + pub fn get_mut(this: &mut Self) -> Option<&mut T> { + if Self::is_unique(this) { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + unsafe { Some(Arc::get_mut_unchecked(this)) } + } else { + None + } + } + + /// Returns a mutable reference into the given `Arc`, without any check. + /// + /// See also [`get_mut`], which is safe and does appropriate checks. + /// + /// [`get_mut`]: Arc::get_mut + /// + /// # Safety + /// + /// If any other `Arc` or [`Weak`] pointers to the same allocation exist, + /// then they must not be dereferenced or have active borrows for the + /// duration of the returned borrow, and their inner type must be exactly + /// the same as the inner type of this Rc (including lifetimes). This is + /// trivially the case if no such pointers exist, for example immediately + /// after `Arc::new`. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// use rune::alloc::String; + /// + /// let mut x = Arc::try_new(String::new())?; + /// + /// unsafe { + /// Arc::get_mut_unchecked(&mut x).try_push_str("foo")? + /// } + /// + /// assert_eq!(*x, "foo"); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + /// + /// Other `Arc` pointers to the same allocation must be to the same type. + /// + /// ```no_run + /// use rune::alloc::sync::Arc; + /// + /// let x: Arc = Arc::try_from("Hello, world!")?; + /// let mut y: Arc<[u8]> = x.clone().try_into()?; + /// + /// unsafe { + /// // this is Undefined Behavior, because x's inner type is str, not [u8] + /// Arc::get_mut_unchecked(&mut y).fill(0xff); // 0xff is invalid in UTF-8 + /// } + /// + /// println!("{}", &*x); // Invalid UTF-8 in a str + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + /// + /// Other `Arc` pointers to the same allocation must be to the exact same + /// type, including lifetimes. + /// + /// ```no_run + /// use rune::alloc::sync::Arc; + /// + /// let x: Arc<&str> = Arc::try_new("Hello, world!")?; + /// + /// { + /// let s = String::from("Oh, no!"); + /// let mut y: Arc<&str> = x.clone(); + /// unsafe { + /// // this is Undefined Behavior, because x's inner type + /// // is &'long str, not &'short str + /// *Arc::get_mut_unchecked(&mut y) = &s; + /// } + /// } + /// + /// println!("{}", &*x); // Use-after-free + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { + // We are careful to *not* create a reference covering the "count" fields, as + // this would alias with concurrent access to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).data } + } + + /// Determine whether this is the unique reference to the underlying data. + /// + /// Returns `true` if there are no other `Arc` or [`Weak`] pointers to the same allocation; + /// returns `false` otherwise. + /// + /// If this function returns `true`, then is guaranteed to be safe to call [`get_mut_unchecked`] + /// on this `Arc`, so long as no clones occur in between. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let x = Arc::try_new(3)?; + /// assert!(Arc::is_unique(&x)); + /// + /// let y = Arc::clone(&x); + /// assert!(!Arc::is_unique(&x)); + /// drop(y); + /// + /// // Weak references also count, because they could be upgraded at any time. + /// let z = Arc::downgrade(&x); + /// assert!(!Arc::is_unique(&x)); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + /// + /// # Pointer invalidation + /// + /// This function will always return the same value as `Arc::get_mut(arc).is_some()`. However, + /// unlike that operation it does not produce any mutable references to the underlying data, + /// meaning no pointers to the data inside the `Arc` are invalidated by the call. Thus, the + /// following code is valid, even though it would be UB if it used `Arc::get_mut`: + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let arc = Arc::try_new(5)?; + /// let pointer: *const i32 = &*arc; + /// assert!(Arc::is_unique(&arc)); + /// assert_eq!(unsafe { *pointer }, 5); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + /// + /// # Atomic orderings + /// + /// Concurrent drops to other `Arc` pointers to the same allocation will synchronize with this + /// call - that is, this call performs an `Acquire` operation on the underlying strong and weak + /// ref counts. This ensures that calling `get_mut_unchecked` is safe. + /// + /// Note that this operation requires locking the weak ref count, so concurrent calls to + /// `downgrade` may spin-loop for a short period of time. + /// + /// [`get_mut_unchecked`]: Self::get_mut_unchecked + #[inline] + pub fn is_unique(this: &Self) -> bool { + // lock the weak pointer count if we appear to be the sole weak pointer + // holder. + // + // The acquire label here ensures a happens-before relationship with any + // writes to `strong` (in particular in `Weak::upgrade`) prior to decrements + // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded + // weak ref was never dropped, the CAS here will fail so we do not care to synchronize. + if this + .inner() + .weak + .compare_exchange(1, usize::MAX, Acquire, Relaxed) + .is_ok() + { + // This needs to be an `Acquire` to synchronize with the decrement of the `strong` + // counter in `drop` -- the only access that happens when any but the last reference + // is being dropped. + let unique = this.inner().strong.load(Acquire) == 1; + + // The release write here synchronizes with a read in `downgrade`, + // effectively preventing the above read of `strong` from happening + // after the write. + this.inner().weak.store(1, Release); // release the lock + unique + } else { + false + } + } + + /// Creates a new [`Weak`] pointer to this allocation. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// let weak_five = Arc::downgrade(&five); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[must_use = "this returns a new `Weak` pointer, \ + without modifying the original `Arc`"] + pub fn downgrade(this: &Self) -> Weak + where + A: Clone, + { + // This Relaxed is OK because we're checking the value in the CAS + // below. + let mut cur = this.inner().weak.load(Relaxed); + + loop { + // check if the weak counter is currently "locked"; if so, spin. + if cur == usize::MAX { + hint::spin_loop(); + cur = this.inner().weak.load(Relaxed); + continue; + } + + // We can't allow the refcount to increase much past `MAX_REFCOUNT`. + assert!(cur <= MAX_REFCOUNT, "{}", INTERNAL_OVERFLOW_ERROR); + + // NOTE: this code currently ignores the possibility of overflow + // into usize::MAX; in general both Rc and Arc need to be adjusted + // to deal with overflow. + + // Unlike with Clone(), we need this to be an Acquire read to + // synchronize with the write coming from `is_unique`, so that the + // events prior to that write happen before this read. + match this + .inner() + .weak + .compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) + { + Ok(_) => { + // Make sure we do not create a dangling Weak + debug_assert!(!is_dangling(this.ptr.as_ptr())); + return Weak { + ptr: this.ptr, + alloc: this.alloc.clone(), + }; + } + Err(old) => cur = old, + } + } + } + + /// Allocates an `ArcInner` with sufficient space for + /// a possibly-unsized inner value where the value has the layout provided. + /// + /// The function `mem_to_arcinner` is called with the data pointer + /// and must return back a (potentially fat)-pointer for the `ArcInner`. + unsafe fn try_allocate_for_layout( + value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result, AllocError>, + mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, + ) -> Result<*mut ArcInner, AllocError> { + let layout = arcinner_layout_for_value_layout(value_layout); + let ptr = allocate(layout)?; + Ok(unsafe { Self::initialize_arcinner(ptr, layout, mem_to_arcinner) }) + } + + unsafe fn initialize_arcinner( + ptr: NonNull<[u8]>, + layout: Layout, + mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, + ) -> *mut ArcInner { + let inner = mem_to_arcinner(ptr.cast().as_ptr()); + // TODO: Switch to `Layout::for_value_raw` once stable. + debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); + + unsafe { + (&raw mut (*inner).strong).write(AtomicUsize::new(1)); + (&raw mut (*inner).weak).write(AtomicUsize::new(1)); + } + + inner + } + + #[inline] + unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { + Self { + ptr, + phantom: PhantomData, + alloc, + } + } + + #[inline] + unsafe fn from_ptr_in(ptr: *mut ArcInner, alloc: A) -> Self { + unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) } + } + + #[inline] + fn inner(&self) -> &ArcInner { + // This unsafety is ok because while this arc is alive we're guaranteed + // that the inner pointer is valid. Furthermore, we know that the + // `ArcInner` structure itself is `Sync` because the inner data is + // `Sync` as well, so we're ok loaning out an immutable pointer to these + // contents. + unsafe { self.ptr.as_ref() } + } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Drop the weak ref collectively held by all strong references when this + // variable goes out of scope. This ensures that the memory is deallocated + // even if the destructor of `T` panics. + // Take a reference to `self.alloc` instead of cloning because 1. it'll last long + // enough, and 2. you should be able to drop `Arc`s with unclonable allocators + let _weak = Weak { + ptr: self.ptr, + alloc: &self.alloc, + }; + + // Destroy the data at this time, even though we must not free the box + // allocation itself (there might still be weak pointers lying around). + // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed. + unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) }; + } +} + +impl Clone for Arc +where + T: ?Sized, + A: Allocator + Clone, +{ + /// Makes a clone of the `Arc` pointer. + /// + /// This creates another pointer to the same allocation, increasing the + /// strong reference count. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// let _ = Arc::clone(&five); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn clone(&self) -> Arc { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object. + // + // As explained in the [Boost documentation][1], Increasing the + // reference counter can always be done with memory_order_relaxed: New + // references to an object can only be formed from an existing + // reference, and passing an existing reference from one thread to + // another must already provide any required synchronization. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + let old_size = self.inner().strong.fetch_add(1, Relaxed); + + // However we need to guard against massive refcounts in case someone is `mem::forget`ing + // Arcs. If we don't do this the count can overflow and users will use-after free. This + // branch will never be taken in any realistic program. We abort because such a program is + // incredibly degenerate, and we don't care to support it. + // + // This check is not 100% water-proof: we error when the refcount grows beyond `isize::MAX`. + // But we do that check *after* having done the increment, so there is a chance here that + // the worst already happened and we actually do overflow the `usize` counter. However, that + // requires the counter to grow from `isize::MAX` to `usize::MAX` between the increment + // above and the `abort` below, which seems exceedingly unlikely. + // + // This is a global invariant, and also applies when using a compare-exchange loop to increment + // counters in other methods. + // Otherwise, the counter could be brought to an almost-overflow using a compare-exchange loop, + // and then overflow using a few `fetch_add`s. + if old_size > MAX_REFCOUNT { + abort(); + } + + unsafe { Self::from_inner_in(self.ptr, self.alloc.clone()) } + } +} + +impl Deref for Arc +where + T: ?Sized, + A: Allocator, +{ + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.inner().data + } +} + +impl Borrow for Arc +where + T: ?Sized, + A: Allocator, +{ + #[inline] + fn borrow(&self) -> &T { + self + } +} + +impl AsRef for Arc +where + T: ?Sized, + A: Allocator, +{ + #[inline] + fn as_ref(&self) -> &T { + self + } +} + +impl Drop for Arc +where + T: ?Sized, + A: Allocator, +{ + /// Drops the `Arc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count reaches zero then the only other references (if any) are + /// [`Weak`], so we `drop` the inner value. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Arc::try_new(Foo)?; + /// let foo2 = Arc::clone(&foo); + /// + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn drop(&mut self) { + // Because `fetch_sub` is already atomic, we do not need to synchronize + // with other threads unless we are going to delete the object. This + // same logic applies to the below `fetch_sub` to the `weak` count. + if self.inner().strong.fetch_sub(1, Release) != 1 { + return; + } + + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // In particular, while the contents of an Arc are usually immutable, it's + // possible to have interior writes to something like a Mutex. Since a + // Mutex is not acquired when it is deleted, we can't rely on its + // synchronization logic to make writes in thread A visible to a destructor + // running in thread B. + // + // Also note that the Acquire fence here could probably be replaced with an + // Acquire load, which could improve performance in highly-contended + // situations. See [2]. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + // [2]: (https://github.com/rust-lang/rust/pull/41714) + acquire!(self.inner().strong); + + // Make sure we aren't trying to "drop" the shared static for empty + // slices used by Default::default. + debug_assert!( + !ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner), + "Arcs backed by a static should never reach a strong count of 0. \ + Likely decrement_strong_count or from_raw were called too many times.", + ); + + unsafe { + self.drop_slow(); + } + } +} + +impl PartialEq for Arc +where + T: ?Sized + PartialEq, + A: Allocator, +{ + /// Equality for two `Arc`s. + /// + /// Two `Arc`s are equal if their inner values are equal, even if they are + /// stored in different allocation. + /// + /// If `T` also implements `Eq` (implying reflexivity of equality), + /// two `Arc`s that point to the same allocation are always equal. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert!(five == Arc::try_new(5)?); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn eq(&self, other: &Arc) -> bool { + Arc::ptr_eq(self, other) || **self == **other + } + + /// Inequality for two `Arc`s. + /// + /// Two `Arc`s are not equal if their inner values are not equal. + /// + /// If `T` also implements `Eq` (implying reflexivity of equality), + /// two `Arc`s that point to the same value are always equal. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert!(five != Arc::try_new(6)?); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[allow(clippy::partialeq_ne_impl)] + #[inline] + fn ne(&self, other: &Arc) -> bool { + !Arc::ptr_eq(self, other) && **self != **other + } +} + +impl PartialOrd for Arc { + /// Partial comparison for two `Arc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::try_new(6)?)); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn partial_cmp(&self, other: &Arc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `Arc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert!(five < Arc::try_new(6)?); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn lt(&self, other: &Arc) -> bool { + *(*self) < *(*other) + } + + /// 'Less than or equal to' comparison for two `Arc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert!(five <= Arc::try_new(5)?); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn le(&self, other: &Arc) -> bool { + *(*self) <= *(*other) + } + + /// Greater-than comparison for two `Arc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert!(five > Arc::try_new(4)?); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn gt(&self, other: &Arc) -> bool { + *(*self) > *(*other) + } + + /// 'Greater than or equal to' comparison for two `Arc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert!(five >= Arc::try_new(5)?); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn ge(&self, other: &Arc) -> bool { + *(*self) >= *(*other) + } +} + +impl Ord for Arc { + /// Comparison for two `Arc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// use std::cmp::Ordering; + /// + /// let five = Arc::try_new(5)?; + /// + /// assert_eq!(Ordering::Less, five.cmp(&Arc::try_new(6)?)); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + fn cmp(&self, other: &Arc) -> Ordering { + (**self).cmp(&**other) + } +} + +impl Eq for Arc +where + T: ?Sized + Eq, + A: Allocator, +{ +} + +impl fmt::Display for Arc +where + T: ?Sized + fmt::Display, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl fmt::Debug for Arc +where + T: ?Sized + fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl fmt::Pointer for Arc +where + T: ?Sized, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +impl Hash for Arc +where + T: ?Sized + Hash, + A: Allocator, +{ + #[inline] + fn hash(&self, state: &mut H) + where + H: Hasher, + { + (**self).hash(state) + } +} + +impl TryFrom<&[u8]> for Arc<[u8], A> +where + A: Default + Allocator, +{ + type Error = AllocError; + + /// Allocates a reference-counted slice and fills it by cloning `v`'s items. + /// + /// # Example + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let original: &[u8] = &[1, 2, 3]; + /// let shared: Arc<[u8]> = Arc::try_from(original)?; + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn try_from(v: &[u8]) -> Result { + // SAFETY: `T` is Copy. + unsafe { Arc::copy_from_slice_in(v, A::default()) } + } +} + +impl TryFrom<&str> for Arc +where + A: Default + Allocator, +{ + type Error = AllocError; + + /// Allocates a reference-counted `str` and copies `v` into it. + /// + /// # Example + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let shared: Arc = Arc::try_from("eggplant")?; + /// assert_eq!("eggplant", &shared[..]); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn try_from(v: &str) -> Result { + let arc = Arc::try_from(v.as_bytes())?; + let (ptr, alloc) = Arc::into_raw_with_allocator(arc); + Ok(unsafe { Arc::from_raw_in(ptr as *const str, alloc) }) + } +} + +impl From> for Arc<[u8], A> +where + A: Allocator, +{ + /// Converts an atomically reference-counted string slice into a byte slice. + /// + /// # Example + /// + /// ``` + /// use rune::alloc::sync::Arc; + /// + /// let string: Arc = Arc::try_from("eggplant")?; + /// let bytes: Arc<[u8]> = Arc::from(string); + /// assert_eq!("eggplant".as_bytes(), bytes.as_ref()); + /// # Ok::<_, rune::alloc::Error>(()) + /// ``` + #[inline] + fn from(arc: Arc) -> Self { + // SAFETY: `str` has the same layout as `[u8]`. + let (ptr, alloc) = Arc::into_raw_with_allocator(arc); + unsafe { Arc::from_raw_in(ptr as *const [u8], alloc) } + } +} + +/// Gets the offset within an `ArcInner` for the payload behind a pointer. +/// +/// # Safety +/// +/// The pointer must point to (and have valid metadata for) a previously +/// valid instance of T, but the T is allowed to be dropped. +unsafe fn data_offset(ptr: *const T) -> usize +where + T: ?Sized, +{ + // Align the unsized value to the end of the ArcInner. Because RcInner is + // repr(C), it will always be the last field in memory. SAFETY: since the + // only unsized types possible are slices, trait objects, and extern types, + // the input safety requirement is currently enough to satisfy the + // requirements of align_of_val_raw; this is an implementation detail of the + // language that must not be relied upon outside of std. + // TODO: Switch to `align_of_val_raw` once stable. + unsafe { data_offset_align(align_of_val(&*ptr)) } +} + +#[inline] +fn data_offset_align(align: usize) -> usize { + let layout = Layout::new::>(); + layout.size() + padding_needed_for(&layout, align) +} + +const fn padding_needed_for(this: &Layout, align: usize) -> usize { + // TODO: Switch to `Alignment` once stable. + let align = if align.is_power_of_two() { + align + } else { + return usize::MAX; + }; + let len_rounded_up = size_rounded_up_to_custom_align(this, align); + // SAFETY: Cannot overflow because the rounded-up value is never less + unsafe { len_rounded_up.unchecked_sub(this.size()) } +} + +/// Returns the smallest multiple of `align` greater than or equal to +/// `self.size()`. +/// +/// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`) because the +/// original size is at most `isize::MAX`. +#[inline] +const fn size_rounded_up_to_custom_align(layout: &Layout, align: usize) -> usize { + // SAFETY: Rounded up value is: size_rounded_up = (size + align - 1) & + // !(align - 1); + // + // The arithmetic we do here can never overflow: + // + // 1. align is guaranteed to be > 0, so align - 1 is always valid. + // + // 2. size is at most `isize::MAX`, so adding `align - 1` (which is at most + // `isize::MAX`) can never overflow a `usize`. + // + // 3. masking by the alignment can remove at most `align - 1`, which is what + // we just added, thus the value we return is never less than the + // original `size`. + // + // (Size 0 Align MAX is already aligned, so stays the same, but things like + // Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + + // 1`.) + unsafe { + let align_m1 = align.unchecked_sub(1); + layout.size().unchecked_add(align_m1) & !align_m1 + } +} + +/// Struct to hold the static `ArcInner` used for empty `Arc` as +/// returned by `Default::default`. +/// +/// Layout notes: +/// * `repr(align(16))` so we can use it for `[T]` with `align_of::() <= 16`. +/// * `repr(C)` so `inner` is at offset 0 (and thus guaranteed to actually be +/// aligned to 16). +/// * `[u8; 1]` (to be initialized with 0) so it can be used for `Arc`. +#[repr(C, align(16))] +struct SliceArcInnerForStatic { + inner: ArcInner<[u8; 1]>, +} + +static STATIC_INNER_SLICE: SliceArcInnerForStatic = SliceArcInnerForStatic { + inner: ArcInner { + strong: AtomicUsize::new(1), + weak: AtomicUsize::new(1), + data: [0], + }, +}; diff --git a/crates/rune-alloc/src/testing/mod.rs b/crates/rune-alloc/src/testing/mod.rs index a71b73145..e05cc4bef 100644 --- a/crates/rune-alloc/src/testing/mod.rs +++ b/crates/rune-alloc/src/testing/mod.rs @@ -49,7 +49,7 @@ impl TestExt for Result { fn abort(self) -> T { match self { Ok(value) => value, - Err(error) => ::rust_alloc::alloc::handle_alloc_error(error.layout), + Err(error) => rust_alloc::alloc::handle_alloc_error(error.layout), } } } @@ -73,7 +73,7 @@ where fn handle_error(error: Error) -> ! { match error { - Error::AllocError { error } => ::rust_alloc::alloc::handle_alloc_error(error.layout), + Error::AllocError { error } => rust_alloc::alloc::handle_alloc_error(error.layout), error => { panic!("{}", error) } diff --git a/crates/rune-alloc/src/tests.rs b/crates/rune-alloc/src/tests.rs index 39c76fce8..6fd8e9660 100644 --- a/crates/rune-alloc/src/tests.rs +++ b/crates/rune-alloc/src/tests.rs @@ -10,6 +10,6 @@ fn test_vec_macro() -> Result<(), Error> { assert_eq!(vec, [1, 1, 1]); let vec: Vec = try_vec![]; - assert_eq!(vec, []); + assert!(vec.is_empty()); Ok(()) } diff --git a/crates/rune-alloc/src/vec/drain.rs b/crates/rune-alloc/src/vec/drain.rs index c6c798e7d..b36a34fb2 100644 --- a/crates/rune-alloc/src/vec/drain.rs +++ b/crates/rune-alloc/src/vec/drain.rs @@ -224,7 +224,7 @@ impl Drop for Drain<'_, T, A> { // it from the original vec but also avoid creating a &mut to the front since that could // invalidate raw pointers to it which some unsafe code might rely on. let vec_ptr = vec.as_mut().as_mut_ptr(); - let drop_offset = ptr::sub_ptr(drop_ptr, vec_ptr); + let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr); let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); ptr::drop_in_place(to_drop); } diff --git a/crates/rune-alloc/src/vec/into_iter.rs b/crates/rune-alloc/src/vec/into_iter.rs index 71f26bcc3..c3221d4fa 100644 --- a/crates/rune-alloc/src/vec/into_iter.rs +++ b/crates/rune-alloc/src/vec/into_iter.rs @@ -125,9 +125,9 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { let exact = if T::IS_ZST { - ptr::addr(self.end).wrapping_sub(ptr::addr(self.ptr)) + self.end.addr().wrapping_sub(self.ptr.addr()) } else { - unsafe { ptr::sub_ptr(self.end, self.ptr) } + unsafe { self.end.offset_from_unsigned(self.ptr) } }; (exact, Some(exact)) } diff --git a/crates/rune-alloc/src/vec/mod.rs b/crates/rune-alloc/src/vec/mod.rs index 726af842b..79206052c 100644 --- a/crates/rune-alloc/src/vec/mod.rs +++ b/crates/rune-alloc/src/vec/mod.rs @@ -487,7 +487,7 @@ impl Vec { /// /// The memory previously occupied by this vector will be released. #[cfg(feature = "alloc")] - pub fn into_std(self) -> ::rust_alloc::vec::Vec { + pub fn into_std(self) -> rust_alloc::vec::Vec { let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc(); if let Ok(layout) = Layout::array::(cap) { @@ -497,7 +497,7 @@ impl Vec { // SAFETY: All the internal invariants of this vector matches what is // needed to construct a rust vector, and the memory has been allocated // using the std `Global` allocator. - unsafe { ::rust_alloc::vec::Vec::from_raw_parts(ptr, len, cap) } + unsafe { rust_alloc::vec::Vec::from_raw_parts(ptr, len, cap) } } } @@ -1010,7 +1010,7 @@ impl Vec { /// /// let mut vec = try_vec![1, 2, 3]; /// vec.truncate(0); - /// assert_eq!(vec, []); + /// assert!(vec.is_empty()); /// # Ok::<_, rune::alloc::Error>(()) /// ``` /// @@ -1750,7 +1750,7 @@ impl Vec { /// insufficient capacity. The caller should use [`try_reserve`] to ensure /// that there is enough capacity. /// - /// [`try_push`]: Vec::try?push + /// [`try_push`]: Vec::try_push /// [`try_reserve`]: Vec::try_reserve /// /// # Examples @@ -1834,7 +1834,7 @@ impl Vec { /// let mut vec2 = try_vec![4, 5, 6]; /// vec.try_append(&mut vec2)?; /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]); - /// assert_eq!(vec2, []); + /// assert!(vec2.is_empty()); /// # Ok::<_, rune::alloc::Error>(()) /// ``` #[inline] @@ -1850,7 +1850,7 @@ impl Vec { /// Appends elements to `self` from other buffer. #[inline] unsafe fn try_append_elements(&mut self, other: *const [T]) -> Result<(), Error> { - let count = unsafe { (*other).len() }; + let count = other.len(); self.try_reserve(count)?; let len = self.len(); unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; @@ -1915,7 +1915,7 @@ impl Vec { /// /// // A full range clears the vector, like `clear()` does /// v.drain(..); - /// assert_eq!(v, &[]); + /// assert!(v.is_empty()); /// # Ok::<_, rune::alloc::Error>(()) /// ``` pub fn drain(&mut self, range: R) -> Drain<'_, T, A> @@ -2898,13 +2898,13 @@ impl TryFrom<[T; N]> for Vec { } #[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::vec::Vec> for Vec { +impl TryFrom> for Vec { type Error = Error; /// Converts a std `Vec` into a [`Vec`]. /// /// The result is allocated on the heap. - fn try_from(vec: ::rust_alloc::vec::Vec) -> Result { + fn try_from(vec: rust_alloc::vec::Vec) -> Result { let mut vec = ManuallyDrop::new(vec); let ptr = vec.as_mut_ptr(); diff --git a/crates/rune-alloc/src/vec/partial_eq.rs b/crates/rune-alloc/src/vec/partial_eq.rs index 1a28d4b24..fb86e591d 100644 --- a/crates/rune-alloc/src/vec/partial_eq.rs +++ b/crates/rune-alloc/src/vec/partial_eq.rs @@ -19,9 +19,9 @@ macro_rules! __impl_slice_eq1 { } #[cfg(feature = "alloc")] -__impl_slice_eq1! { [A: Allocator] Vec, ::rust_alloc::vec::Vec } +__impl_slice_eq1! { [A: Allocator] Vec, rust_alloc::vec::Vec } #[cfg(feature = "alloc")] -__impl_slice_eq1! { [A: Allocator] ::rust_alloc::vec::Vec, Vec } +__impl_slice_eq1! { [A: Allocator] rust_alloc::vec::Vec, Vec } __impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec, Vec } __impl_slice_eq1! { [A: Allocator] Vec, &[U] } __impl_slice_eq1! { [A: Allocator] Vec, &mut [U] } diff --git a/crates/rune-alloc/src/vec_deque/drain.rs b/crates/rune-alloc/src/vec_deque/drain.rs index 01c46fdf3..be6c6162a 100644 --- a/crates/rune-alloc/src/vec_deque/drain.rs +++ b/crates/rune-alloc/src/vec_deque/drain.rs @@ -155,8 +155,8 @@ impl Drop for Drain<'_, T, A> { // SAFETY: We just checked that `self.remaining != 0`. let (front, back) = guard.0.as_slices(); // since idx is a logical index, we don't need to worry about wrapping. - guard.0.idx += ptr::slice_len(front); - guard.0.remaining -= ptr::slice_len(front); + guard.0.idx += front.len(); + guard.0.remaining -= front.len(); ptr::drop_in_place(front); guard.0.remaining = 0; ptr::drop_in_place(back); diff --git a/crates/rune-alloc/src/vec_deque/mod.rs b/crates/rune-alloc/src/vec_deque/mod.rs index 6e6e1f86d..8177078f0 100644 --- a/crates/rune-alloc/src/vec_deque/mod.rs +++ b/crates/rune-alloc/src/vec_deque/mod.rs @@ -1842,7 +1842,7 @@ impl VecDeque { /// let mut buf2: VecDeque<_> = [3, 4].try_into()?; /// buf.try_append(&mut buf2)?; /// assert_eq!(buf, [1, 2, 3, 4]); - /// assert_eq!(buf2, []); + /// assert!(buf2.is_empty()); /// # Ok::<_, rune::alloc::Error>(()) /// ``` #[inline] diff --git a/crates/rune-cli/Cargo.toml b/crates/rune-cli/Cargo.toml index fbc54f050..c22c1f4a0 100644 --- a/crates/rune-cli/Cargo.toml +++ b/crates/rune-cli/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-cli" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" 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 5a9243a6c..f33ebb623 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-core/Cargo.toml b/crates/rune-core/Cargo.toml index 118ce3d57..a79312dfe 100644 --- a/crates/rune-core/Cargo.toml +++ b/crates/rune-core/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-core" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "Core components for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -23,11 +23,11 @@ std = ["alloc", "rune-alloc/std"] alloc = ["serde/alloc", "rune-alloc/alloc"] [dependencies] -rune-alloc = { version = "0.14.0", path = "../rune-alloc", default-features = false, features = ["serde"] } +rune-alloc = { version = "0.14.0", path = "../rune-alloc", default-features = false, features = ["serde", "musli"] } twox-hash = { version = "2.0.0", default-features = false, features = ["xxhash64"] } serde = { version = "1.0.163", default-features = false, features = ["derive"] } -musli = { version = "0.0.124", default-features = false, optional = true } +musli = { version = "0.0.131", default-features = false, optional = true } [dev-dependencies] -rune = { package = "rune-shim", path = "../rune-shim", features = ["core", "alloc"] } +rune = { path = "../rune", features = ["alloc"] } diff --git a/crates/rune-core/src/hash.rs b/crates/rune-core/src/hash.rs index c978a2eeb..8ee2fb414 100644 --- a/crates/rune-core/src/hash.rs +++ b/crates/rune-core/src/hash.rs @@ -6,12 +6,37 @@ mod to_type_hash; use core::fmt; use core::hash::{BuildHasher, BuildHasherDefault, Hash as _, Hasher}; +use core::num::NonZero; #[cfg(feature = "musli")] use musli::{Decode, Encode}; use serde::{Deserialize, Serialize}; use twox_hash::XxHash64; +/// Error raised when too many parameters are added to a [`ParametersBuilder`]. +/// +/// # Examples +/// +/// ``` +/// use rune::TypeHash; +/// use rune::hash::ParametersBuilder; +/// +/// let mut params = ParametersBuilder::new(); +/// +/// let err = 'outer: { +/// for _ in 0.. { +/// params = match params.add(i64::HASH) { +/// Ok(params) => params, +/// Err(err) => break 'outer err, +/// }; +/// }; +/// +/// panic!("expected error"); +/// }; +/// +/// let err = err.to_string(); +/// # Ok::<_, rune::hash::TooManyParameters>(()) +/// ``` #[derive(Debug)] #[non_exhaustive] pub struct TooManyParameters; @@ -75,6 +100,74 @@ const PARAMETERS: [u64; 32] = [ /// The primitive hash that among other things is used to reference items, /// types, and native functions. +/// +/// # Examples +/// +/// ``` +/// use rune::Hash; +/// +/// assert!(Hash::index(0).as_non_empty().is_some()); +/// ``` +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] +#[repr(transparent)] +pub struct NonZeroHash(#[doc(hidden)] pub NonZero); + +impl NonZeroHash { + /// Get the value as a hash. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// + /// let hash = Hash::index(0).as_non_empty().ok_or("expected non-empty")?; + /// assert_eq!(hash.get(), Hash::index(0)); + /// # Ok::<_, &'static str>(()) + /// ``` + pub const fn get(self) -> Hash { + Hash(self.0.get()) + } +} + +impl TryClone for NonZeroHash { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(*self) + } +} + +impl fmt::Display for NonZeroHash { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{:x}", self.0.get()) + } +} + +impl fmt::Debug for NonZeroHash { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{:x}", self.0.get()) + } +} + +impl PartialEq for NonZeroHash { + #[inline] + fn eq(&self, other: &Hash) -> bool { + self.0.get() == other.0 + } +} + +/// The primitive hash that among other things is used to reference items, +/// types, and native functions. +/// +/// # Examples +/// +/// ``` +/// use rune::Hash; +/// +/// assert_ne!(Hash::index(0), Hash::index(1)); +/// ``` #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] #[repr(transparent)] @@ -82,6 +175,15 @@ pub struct Hash(#[doc(hidden)] pub u64); impl Hash { /// The empty hash. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// + /// assert_ne!(Hash::index(0), Hash::EMPTY); + /// assert!(Hash::EMPTY.as_non_empty().is_none()); + /// ``` pub const EMPTY: Self = Self(0); /// Construct a new raw hash. @@ -97,13 +199,18 @@ impl Hash { } /// Return the current hash if it is non-empty. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// + /// assert!(Hash::index(0).as_non_empty().is_some()); + /// assert!(Hash::EMPTY.as_non_empty().is_none()); + /// ``` #[inline] - pub fn as_non_empty(&self) -> Option { - if self.is_empty() { - None - } else { - Some(*self) - } + pub fn as_non_empty(&self) -> Option { + Some(NonZeroHash(NonZero::new(self.0)?)) } /// Coerce a hash into its inner numerical value. @@ -119,6 +226,14 @@ impl Hash { } /// Construct a hash from an index. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// + /// assert_ne!(Hash::index(0), Hash::index(1)); + /// ``` #[inline] pub fn index(index: usize) -> Self { Self(INDEX ^ (index as u64)) @@ -126,6 +241,14 @@ impl Hash { /// Get the hash corresponding to a string identifier like `function` or /// `hello_world`. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// + /// assert_ne!(Hash::ident("foo"), Hash::index(0)); + /// ``` pub fn ident(name: &str) -> Hash { let mut hasher = Self::new_hasher(); name.hash(&mut hasher); @@ -133,12 +256,30 @@ impl Hash { } /// Get the hash of a type. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// + /// assert!(!Hash::type_hash(["main"]).is_empty()); + /// assert!(!Hash::type_hash(["main", "other"]).is_empty()); + /// ``` pub fn type_hash(path: impl ToTypeHash) -> Self { path.to_type_hash() } /// Construct a hash to an instance function, where the instance is a /// pre-determined type. + /// + /// # Examples + /// + /// ``` + /// use rune::Hash; + /// use rune::runtime::Protocol; + /// + /// assert!(!Hash::associated_function("main", &Protocol::INTO_TYPE_NAME).is_empty()); + /// ``` #[inline] pub fn associated_function(type_hash: impl IntoHash, name: impl IntoHash) -> Self { let type_hash = type_hash.into_hash(); @@ -147,6 +288,15 @@ impl Hash { } /// Construct a hash corresponding to a field function. + /// + /// # Examples + /// + /// ``` + /// use rune::{Hash, TypeHash}; + /// use rune::runtime::Protocol; + /// + /// assert!(!Hash::field_function(&Protocol::ADD, i64::HASH, "field").is_empty()); + /// ``` #[inline] pub fn field_function(protocol: impl IntoHash, type_hash: Hash, name: impl IntoHash) -> Self { let protocol = protocol.into_hash(); @@ -154,6 +304,15 @@ impl Hash { } /// Construct an index function. + /// + /// # Examples + /// + /// ``` + /// use rune::{Hash, TypeHash}; + /// use rune::runtime::Protocol; + /// + /// assert!(!Hash::index_function(&Protocol::ADD, i64::HASH, Hash::index(1)).is_empty()); + /// ``` #[inline] pub fn index_function(protocol: impl IntoHash, type_hash: Hash, index: Hash) -> Self { let protocol = protocol.into_hash(); @@ -170,8 +329,7 @@ impl Hash { /// Hash the given iterator of object keys. pub fn object_keys(keys: I) -> Self where - I: IntoIterator, - I::Item: AsRef, + I: IntoIterator>, { let mut hasher = Self::new_hasher(); OBJECT_KEYS.hash(&mut hasher); @@ -226,18 +384,21 @@ impl Hash { } impl TryClone for Hash { + #[inline] fn try_clone(&self) -> alloc::Result { Ok(*self) } } impl fmt::Display for Hash { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{:x}", self.0) } } impl fmt::Debug for Hash { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{:x}", self.0) } @@ -273,6 +434,19 @@ pub struct ParametersBuilder { impl ParametersBuilder { /// Construct a new collection of parameters. + /// + /// # Examples + /// + /// ``` + /// use rune::{Hash, TypeHash}; + /// use rune::hash::ParametersBuilder; + /// + /// let mut params = ParametersBuilder::new(); + /// + /// let hash = params.finish(); + /// assert_eq!(hash, Hash::EMPTY); + /// # Ok::<_, rune::hash::TooManyParameters>(()) + /// ``` pub const fn new() -> Self { Self { base: 0, @@ -286,6 +460,21 @@ impl ParametersBuilder { /// # Errors /// /// Errors if too many parameters are added. + /// + /// # Examples + /// + /// ``` + /// use rune::TypeHash; + /// use rune::hash::ParametersBuilder; + /// + /// let mut params = ParametersBuilder::new(); + /// + /// let params = params.add(String::HASH)?; + /// let params = params.add(i64::HASH)?; + /// + /// let hash = params.finish(); + /// # Ok::<_, rune::hash::TooManyParameters>(()) + /// ``` pub const fn add(mut self, Hash(hash): Hash) -> Result { if self.index >= PARAMETERS.len() { self.shift += 8; @@ -302,7 +491,29 @@ impl ParametersBuilder { } /// Finish building the parameters hash. + /// + /// # Examples + /// + /// ``` + /// use rune::TypeHash; + /// use rune::hash::ParametersBuilder; + /// + /// let mut params = ParametersBuilder::new(); + /// + /// let params = params.add(String::HASH)?; + /// let params = params.add(i64::HASH)?; + /// + /// let hash = params.finish(); + /// # Ok::<_, rune::hash::TooManyParameters>(()) + /// ``` pub const fn finish(self) -> Hash { Hash::new(self.base) } } + +impl PartialEq for Hash { + #[inline] + fn eq(&self, other: &NonZeroHash) -> bool { + self.0 == other.0.get() + } +} diff --git a/crates/rune-core/src/hash/into_hash.rs b/crates/rune-core/src/hash/into_hash.rs index f39c0841b..010d24ba0 100644 --- a/crates/rune-core/src/hash/into_hash.rs +++ b/crates/rune-core/src/hash/into_hash.rs @@ -14,8 +14,9 @@ mod sealed { impl Sealed for Params {} } -/// Trait for types which can be converted into a -/// [Hash][struct@crate::hash::Hash]. +/// Trait for types which can be converted into a [Hash]. +/// +/// [Hash]: struct@crate::hash::Hash pub trait IntoHash: self::sealed::Sealed { /// Convert current type into a hash. fn into_hash(self) -> Hash; diff --git a/crates/rune-core/src/item.rs b/crates/rune-core/src/item.rs index 05fb5f416..f6daa7195 100644 --- a/crates/rune-core/src/item.rs +++ b/crates/rune-core/src/item.rs @@ -22,6 +22,8 @@ pub use self::into_component::IntoComponent; mod internal; +#[cfg(feature = "musli")] +mod musli; mod serde; #[cfg(test)] diff --git a/crates/rune-core/src/item/into_component.rs b/crates/rune-core/src/item/into_component.rs index 2f62e45ad..274eb64f3 100644 --- a/crates/rune-core/src/item/into_component.rs +++ b/crates/rune-core/src/item/into_component.rs @@ -172,7 +172,7 @@ impl_into_component_for_str!(&Box, self, self.try_clone()?); impl_into_component_for_str!(Cow<'_, str>, self, self.as_ref().try_into()?); #[cfg(feature = "alloc")] impl_into_component_for_str!( - ::rust_alloc::borrow::Cow<'_, str>, + rust_alloc::borrow::Cow<'_, str>, self, self.as_ref().try_into()? ); diff --git a/crates/rune-core/src/item/item.rs b/crates/rune-core/src/item/item.rs index 89b58d86d..8a8f1d628 100644 --- a/crates/rune-core/src/item/item.rs +++ b/crates/rune-core/src/item/item.rs @@ -445,14 +445,21 @@ impl fmt::Display for Item { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut it = self.iter(); - if let Some(last) = it.next_back() { - for p in it { - write!(f, "{}::", p)?; + let Some(last) = it.next_back() else { + f.write_str("{root}")?; + return Ok(()); + }; + + let mut first = true; + + for c in it.chain([last]) { + if !first { + write!(f, "::{c}")?; + } else { + write!(f, "{c}")?; } - write!(f, "{}", last)?; - } else { - f.write_str("{root}")?; + first = false; } Ok(()) diff --git a/crates/rune-core/src/item/item_buf.rs b/crates/rune-core/src/item/item_buf.rs index 249b4f4b8..9f2e524ea 100644 --- a/crates/rune-core/src/item/item_buf.rs +++ b/crates/rune-core/src/item/item_buf.rs @@ -322,12 +322,14 @@ impl Deref for ItemBuf { /// Format implementation for an [ItemBuf], defers to [Item]. impl fmt::Display for ItemBuf { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Item::fmt(self, f) } } impl fmt::Debug for ItemBuf { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Item::fmt(self, f) } diff --git a/crates/rune-core/src/item/musli.rs b/crates/rune-core/src/item/musli.rs new file mode 100644 index 000000000..e0053e995 --- /dev/null +++ b/crates/rune-core/src/item/musli.rs @@ -0,0 +1,56 @@ +use musli::{Allocator, Decode, Decoder, Encode, Encoder}; + +use crate::alloc::Vec; +use crate::item::{Item, ItemBuf}; + +impl Encode for Item { + type Encode = [u8]; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + self.as_bytes().encode(encoder) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self.as_bytes() + } +} + +impl Encode for ItemBuf { + type Encode = [u8]; + + #[inline] + fn encode(&self, encoder: E) -> Result<(), E::Error> + where + E: Encoder, + { + self.as_bytes().encode(encoder) + } + + #[inline] + fn as_encode(&self) -> &Self::Encode { + self.as_bytes() + } +} + +impl<'de, M, A> Decode<'de, M, A> for ItemBuf +where + A: Allocator, +{ + const IS_BITWISE_DECODE: bool = false; + + #[inline] + fn decode(decoder: D) -> Result + where + D: Decoder<'de>, + { + let bytes = Vec::::decode(decoder)?; + + // TODO: validate byte sequence. + unsafe { Ok(ItemBuf::from_raw(bytes)) } + } +} diff --git a/crates/rune-core/src/lib.rs b/crates/rune-core/src/lib.rs index 3d63c1d0b..1746c7522 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-core/src/params.rs b/crates/rune-core/src/params.rs index 37b9f324d..82380cd90 100644 --- a/crates/rune-core/src/params.rs +++ b/crates/rune-core/src/params.rs @@ -4,6 +4,20 @@ use crate::hash::{Hash, IntoHash}; /// /// This is used to wrap the name of the function in order to associated /// parameters with it. +/// +/// # Examples +/// +/// ``` +/// use rune::{Params, TypeHash}; +/// use rune::hash::IntoHash; +/// use rune::runtime::Vec; +/// +/// let params = Params::new("collect", []); +/// assert_eq!(params.into_hash(), "collect".into_hash()); +/// +/// let params = Params::new("collect", [Vec::HASH]); +/// assert_eq!(params.into_hash(), "collect".into_hash()); +/// ``` #[derive(Clone)] #[non_exhaustive] pub struct Params { @@ -15,6 +29,20 @@ pub struct Params { impl Params { /// Construct a new parameters wrapper. + /// + /// # Examples + /// + /// ``` + /// use rune::{Params, TypeHash}; + /// use rune::hash::IntoHash; + /// use rune::runtime::Vec; + /// + /// let params = Params::new("collect", []); + /// assert_eq!(params.into_hash(), "collect".into_hash()); + /// + /// let params = Params::new("collect", [Vec::HASH]); + /// assert_eq!(params.into_hash(), "collect".into_hash()); + /// ``` pub const fn new(name: T, parameters: [Hash; N]) -> Self { Self { name, parameters } } diff --git a/crates/rune-core/src/protocol.rs b/crates/rune-core/src/protocol.rs index b4aacd61f..8afe2b3a7 100644 --- a/crates/rune-core/src/protocol.rs +++ b/crates/rune-core/src/protocol.rs @@ -7,7 +7,16 @@ use crate::alloc; use crate::hash::{Hash, ToTypeHash}; use crate::item::ItemBuf; -/// A built in instance function. +/// A pre-defined protocol function. +/// +/// # Examples +/// +/// ``` +/// use rune::runtime::Protocol; +/// +/// let protocol = Protocol::GET; +/// assert_eq!(protocol.name, "GET"); +/// ``` #[derive(Debug)] #[non_exhaustive] pub struct Protocol { @@ -74,7 +83,7 @@ macro_rules! maybe { macro_rules! define { ( $( - $(#[$($meta:meta)*])* + $(#[doc = $outer_doc:literal])* $vis:vis const $ident:ident: Protocol = Protocol { $(method: $method:expr,)? hash: $hash:expr, @@ -85,7 +94,18 @@ macro_rules! define { ) => { impl Protocol { $( - $(#[$($meta)*])* + $(#[doc = $outer_doc])* + /// + /// # Examples + /// + /// ``` + /// use rune::hash::IntoHash; + /// use rune::runtime::Protocol; + /// + #[doc = concat!(" let hash = Protocol::", stringify!($ident), ".into_hash();")] + /// let protocol = Protocol::from_hash(hash); + #[doc = concat!(" assert_eq!(protocol, Some(Protocol::", stringify!($ident), "));")] + /// ``` $vis const $ident: Protocol = Protocol { name: stringify!($ident), method: maybe!($($method)*), @@ -98,7 +118,18 @@ macro_rules! define { )* /// Look up protocol for the given hash. - pub fn from_hash(hash: Hash) -> Option { + /// + /// # Examples + /// + /// ``` + /// use rune::runtime::Protocol; + /// + /// let hash = Protocol::GET.hash; + /// let protocol = Protocol::from_hash(hash).ok_or("missing protocol")?; + /// assert_eq!(protocol, Protocol::GET); + /// # Ok::<_, &'static str>(()) + /// ``` + pub const fn from_hash(hash: Hash) -> Option { match hash { $( Hash($hash) => { @@ -229,140 +260,154 @@ define! { /// Allows for total ordering to work. }; - /// The function to implement for the addition operation. + /// The protocol for the unary negation operation. + pub const NEG: Protocol = Protocol { + hash: 0x9ffb490461f68150u64, + repr: "let $out = -$value", + /// Allows the `-` operator to apply to values of this type. + }; + + /// The protocol for the unary not operation. + pub const NOT: Protocol = Protocol { + hash: 0xea93fbfca4da3b36u64, + repr: "let $out = !$value", + /// Allows the `!` operator to apply to values of this type. + }; + + /// The protocol for the addition operation. pub const ADD: Protocol = Protocol { hash: 0xe4ecf51fa0bf1076u64, repr: "let $out = $value + $b", /// Allows the `+` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the addition assign operation. + /// The protocol for the addition assign operation. pub const ADD_ASSIGN: Protocol = Protocol { hash: 0x42451ccb0a2071a9u64, repr: "$value += $b", /// Allows the `+=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the subtraction operation. + /// The protocol for the subtraction operation. pub const SUB: Protocol = Protocol { hash: 0x6fa86a5f18d0bf71u64, repr: "let $out = $value - $b", /// Allows the `-` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the subtraction assign operation. + /// The protocol for the subtraction assign operation. pub const SUB_ASSIGN: Protocol = Protocol { hash: 0x5939bb56a1415284u64, repr: "$value -= $b", /// Allows the `-=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the multiply operation. + /// The protocol for the multiply operation. pub const MUL: Protocol = Protocol { hash: 0xb09e99dc94091d1cu64, repr: "let $out = $value * $b", /// Allows the `*` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the multiply assign operation. + /// The protocol for the multiply assign operation. pub const MUL_ASSIGN: Protocol = Protocol { hash: 0x29a54b727f980ebfu64, repr: "$value *= $b", /// Allows the `*=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the division operation. + /// The protocol for the division operation. pub const DIV: Protocol = Protocol { hash: 0xf26d6eea1afca6e8u64, repr: "let $out = $value / $b", /// Allows the `/` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the division assign operation. + /// The protocol for the division assign operation. pub const DIV_ASSIGN: Protocol = Protocol { hash: 0x4dd087a8281c04e6u64, repr: "$value /= $b", /// Allows the `/=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the remainder operation. + /// The protocol for the remainder operation. pub const REM: Protocol = Protocol { hash: 0x5c6293639c74e671u64, repr: "let $out = $value % $b", /// Allows the `%` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the remainder assign operation. + /// The protocol for the remainder assign operation. pub const REM_ASSIGN: Protocol = Protocol { hash: 0x3a8695980e77baf4u64, repr: "$value %= $b", /// Allows the `%=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise and operation. + /// The protocol for the bitwise and operation. pub const BIT_AND: Protocol = Protocol { hash: 0x0e11f20d940eebe8u64, repr: "let $out = $value & $b", /// Allows the `&` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise and assign operation. + /// The protocol for the bitwise and assign operation. pub const BIT_AND_ASSIGN: Protocol = Protocol { hash: 0x95cb1ba235dfb5ecu64, repr: "$value &= $b", /// Allows the `&=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise xor operation. + /// The protocol for the bitwise xor operation. pub const BIT_XOR: Protocol = Protocol { hash: 0xa3099c54e1de4cbfu64, repr: "let $out = $value ^ $b", /// Allows the `^` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise xor assign operation. + /// The protocol for the bitwise xor assign operation. pub const BIT_XOR_ASSIGN: Protocol = Protocol { hash: 0x01fa9706738f9867u64, repr: "$value ^= $b", /// Allows the `^=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise or operation. + /// The protocol for the bitwise or operation. pub const BIT_OR: Protocol = Protocol { hash: 0x05010afceb4a03d0u64, repr: "let $out = $value | $b", /// Allows the `|` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise xor assign operation. + /// The protocol for the bitwise xor assign operation. pub const BIT_OR_ASSIGN: Protocol = Protocol { hash: 0x606d79ff1750a7ecu64, repr: "$value |= $b", /// Allows the `|=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise shift left operation. + /// The protocol for the bitwise shift left operation. pub const SHL: Protocol = Protocol { hash: 0x6845f7d0cc9e002du64, repr: "let $out = $value << $b", /// Allows the `<<` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise shift left assign operation. + /// The protocol for the bitwise shift left assign operation. pub const SHL_ASSIGN: Protocol = Protocol { hash: 0xdc4702d0307ba27bu64, repr: "$value <<= $b", /// Allows the `<<=` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise shift right operation. + /// The protocol for the bitwise shift right operation. pub const SHR: Protocol = Protocol { hash: 0x6b485e8e6e58fbc8u64, repr: "let $out = $value >> $b", /// Allows the `>>` operator to apply to values of this type, where the current type is the left-hand side. }; - /// The function to implement for the bitwise shift right assign operation. + /// The protocol for the bitwise shift right assign operation. pub const SHR_ASSIGN: Protocol = Protocol { hash: 0x61ff7c46ff00e74au64, repr: "$value >>= $b", diff --git a/crates/rune-languageserver/Cargo.toml b/crates/rune-languageserver/Cargo.toml index c62dc8f06..10338d54f 100644 --- a/crates/rune-languageserver/Cargo.toml +++ b/crates/rune-languageserver/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-languageserver" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" 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 5b54b32f5..12e508e71 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-macros/Cargo.toml b/crates/rune-macros/Cargo.toml index f0a3b3df3..83ca94fed 100644 --- a/crates/rune-macros/Cargo.toml +++ b/crates/rune-macros/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-macros" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "Macros for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -24,3 +24,4 @@ proc-macro = true [dev-dependencies] rune = { path = "../rune" } +rune-core = { path = "../rune-core" } diff --git a/crates/rune-macros/src/any.rs b/crates/rune-macros/src/any.rs index 18f27c7c2..d83fb3411 100644 --- a/crates/rune-macros/src/any.rs +++ b/crates/rune-macros/src/any.rs @@ -7,13 +7,13 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::Token; -use crate::context::{Context, Generate, GenerateTarget, Tokens, TypeAttr}; +use crate::context::{Context, FieldAttr, Generate, GenerateTarget, Tokens, TypeAttr, TypeFields}; struct InternalItem { attrs: Vec, #[allow(unused)] impl_token: Token![impl], - params: Option, + generics: syn::Generics, item: syn::Path, #[allow(unused)] for_token: Token![for], @@ -21,15 +21,12 @@ struct InternalItem { } impl syn::parse::Parse for InternalItem { + #[inline] fn parse(input: syn::parse::ParseStream) -> syn::Result { Ok(Self { attrs: syn::Attribute::parse_outer(input)?, impl_token: input.parse()?, - params: if input.peek(Token![<]) { - Some(input.parse()?) - } else { - None - }, + generics: input.parse()?, item: input.parse()?, for_token: input.parse()?, ty: input.parse()?, @@ -66,7 +63,6 @@ impl InternalCall { pub(super) fn into_any_builders<'a>( self, cx: &Context, - attr: &'a TypeAttr, tokens: &'a Tokens, ) -> Vec> { let mut output = Vec::new(); @@ -115,15 +111,13 @@ impl InternalCall { }; output.push(TypeBuilder { - attr, ident: item.ty, type_hash, type_item, installers: Vec::new(), tokens, - generics: syn::Generics::default(), + generics: item.generics, attrs, - params: item.params, kind, }); } @@ -176,7 +170,7 @@ impl Derive { expand_install_with(cx, &self.input, tokens, attr, &mut installers, &args)?; if matches!(&self.input.data, syn::Data::Enum(..)) { - if let Some(span) = attr.constructor { + if let Some(span) = attr.constructor.as_span() { cx.error(syn::Error::new( span, "#[rune(constructor)] is not supported on enums, only its variants", @@ -185,7 +179,6 @@ impl Derive { } Ok(TypeBuilder { - attr, ident: self.input.ident, type_hash, type_item, @@ -193,7 +186,6 @@ impl Derive { tokens, generics: self.input.generics, attrs: Vec::new(), - params: None, kind: TypeKind::Derive, }) } @@ -252,8 +244,11 @@ fn expand_struct_install_with( tokens: &Tokens, attr: &TypeAttr, ) -> Result<(), ()> { + let mut field_attrs = Vec::new(); + for (n, field) in st.fields.iter().enumerate() { - let attrs = cx.field_attrs(&field.attrs); + let attr = cx.field_attrs(&field.attrs); + let name; let index; @@ -277,16 +272,18 @@ fn expand_struct_install_with( let ty = &field.ty; - for protocol in &attrs.protocols { + for protocol in &attr.protocols { installers.push((protocol.generate)(Generate { tokens, + attr: &attr, protocol, - attrs: &attrs, field, ty, target, })); } + + field_attrs.push(attr); } let mut docs = syn::ExprArray { @@ -299,36 +296,69 @@ fn expand_struct_install_with( docs.elems.push(el.clone()); } - match &st.fields { - syn::Fields::Named(fields) => { - let constructor = attr - .constructor - .is_some() - .then(|| make_constructor(syn::parse_quote!(#ident), &fields.named)); + let make_constructor; + let make_fields; - let fields = fields.named.iter().flat_map(|f| { - let ident = f.ident.as_ref()?; - Some(syn::LitStr::new(&ident.to_string(), ident.span())) - }); + match &attr.fields { + TypeFields::Default => match &st.fields { + syn::Fields::Named(fields) => { + make_constructor = attr.constructor.or_implicit(|| { + make_named_constructor( + tokens, + syn::parse_quote!(#ident), + &fields.named, + &field_attrs, + ) + }); - installers.push(quote! { - module.type_meta::()?.make_named_struct(&[#(#fields,)*])?.static_docs(&#docs)?#constructor; - }); - } - syn::Fields::Unnamed(fields) => { - let len = fields.unnamed.len(); + let fields = fields.named.iter().zip(&field_attrs).filter_map(|(f, a)| { + if !a.field { + return None; + } - installers.push(quote! { - module.type_meta::()?.make_unnamed_struct(#len)?.static_docs(&#docs)?; - }); + let ident = f.ident.as_ref()?; + Some(syn::LitStr::new(&ident.to_string(), ident.span())) + }); + + make_fields = Some(quote!(.make_named_struct(&[#(#fields,)*])?)); + } + syn::Fields::Unnamed(fields) => { + make_constructor = attr.constructor.or_implicit(|| { + make_unnamed_constructor( + tokens, + syn::parse_quote!(#ident), + &fields.unnamed, + &field_attrs, + ) + }); + + let len = field_attrs.iter().take_while(|f| f.field).count(); + make_fields = Some(quote!(.make_unnamed_struct(#len)?)); + } + syn::Fields::Unit => { + make_constructor = attr.constructor.or_implicit(|| quote!(|| #ident)); + make_fields = Some(quote!(.make_empty_struct()?)); + } + }, + TypeFields::Empty => { + make_constructor = attr.constructor.as_explicit(); + make_fields = Some(quote!(.make_empty_struct()?)); } - syn::Fields::Unit => { - installers.push(quote! { - module.type_meta::()?.make_empty_struct()?.static_docs(&#docs)?; - }); + TypeFields::Unnamed(n) => { + make_constructor = attr.constructor.as_explicit(); + make_fields = Some(quote!(.make_unnamed_struct(#n)?)); } } + let make_constructor = make_constructor.map(|c| quote!(.constructor(#c)?)); + + installers.push(quote! { + module.type_meta::()? + .static_docs(&#docs)? + #make_constructor + #make_fields; + }); + Ok(()) } @@ -343,14 +373,12 @@ fn expand_enum_install_with( args: &crate::hash::Arguments, ) -> Result<(), ()> { let Tokens { - protocol, - runtime_error, - to_value, - vm_result, - vm_try, any_t, - try_clone, hash, + protocol, + result, + to_value, + errors, .. } = tokens; @@ -359,7 +387,6 @@ fn expand_enum_install_with( let mut is_variant = Vec::new(); let mut variant_metas = Vec::new(); let mut variant_names = Vec::new(); - let mut variants = Vec::new(); // Protocol::GET implementations per available field. Each implementation // needs to match the enum to extract the appropriate field. @@ -393,96 +420,102 @@ fn expand_enum_install_with( is_variant.push(quote!((#ident::#variant_ident { .. }, #hash(#variant_hash)) => true)); - match &variant.fields { - syn::Fields::Named(fields) => { - let mut field_names = Vec::new(); - - for f in &fields.named { - let attrs = cx.field_attrs(&f.attrs); - - let Some(f_ident) = &f.ident else { - cx.error(syn::Error::new_spanned(f, "Missing field name")); - return Err(()); - }; + let mut field_attrs = Vec::new(); - if attrs.field { - let f_name = f_ident.to_string(); - let name = syn::LitStr::new(&f_name, f.span()); - field_names.push(name); + for f in variant.fields.iter() { + field_attrs.push(cx.field_attrs(&f.attrs)); + } - let fields = field_fns.entry(f_name).or_default(); + let make_constructor; + let make_fields; - let to_value = if attrs.copy { - quote!(#vm_try!(#to_value::to_value(*#f_ident))) - } else { - quote!(#vm_try!(#to_value::to_value(#vm_try!(#try_clone::try_clone(#f_ident))))) + match &attr.fields { + TypeFields::Default => match &variant.fields { + syn::Fields::Named(fields) => { + for (f, attrs) in fields.named.iter().zip(&field_attrs) { + let Some(field_ident) = &f.ident else { + cx.error(syn::Error::new_spanned(f, "Missing field name")); + return Err(()); }; - fields.push(quote!(#ident::#variant_ident { #f_ident, .. } => #vm_result::Ok(#to_value))); + if attrs.field { + let field_name = field_ident.to_string(); + let fields = field_fns.entry(field_name).or_default(); + let access = attrs.clone_with.decorate(tokens, quote!(#field_ident)); + fields.push(quote!(#ident::#variant_ident { #field_ident, .. } => #result::Ok(#to_value::to_value(#access)?))); + } } - } - let constructor = variant_attr.constructor.is_some().then(|| { - make_constructor(syn::parse_quote!(#ident::#variant_ident), &fields.named) - }); - - variant_metas.push(quote! { - enum_.variant_mut(#variant_index)?.make_named(&[#(#field_names),*])?.static_docs(&#variant_docs)?#constructor - }); + make_constructor = variant_attr.constructor.or_implicit(|| { + make_named_constructor( + tokens, + syn::parse_quote!(#ident::#variant_ident), + &fields.named, + &field_attrs, + ) + }); - variants.push((None, variant_attr)); - } - syn::Fields::Unnamed(fields) => { - let mut fields_len = 0usize; + let fields = fields.named.iter().zip(&field_attrs).filter_map(|(f, a)| { + if !a.field { + return None; + } - for (n, field) in fields.unnamed.iter().enumerate() { - let span = field.span(); - let attrs = cx.field_attrs(&field.attrs); + let ident = f.ident.as_ref()?; + Some(syn::LitStr::new(&ident.to_string(), ident.span())) + }); - if attrs.field { - fields_len += 1; - let fields = index_fns.entry(n).or_default(); - let n = syn::LitInt::new(&n.to_string(), span); + make_fields = Some(quote!(.make_named(&[#(#fields),*])?)); + } + syn::Fields::Unnamed(fields) => { + for (n, field) in fields.unnamed.iter().enumerate() { + let attrs = cx.field_attrs(&field.attrs); - let to_value = if attrs.copy { - quote!(#vm_try!(#to_value::to_value(*value))) - } else { - quote!(#vm_try!(#to_value::to_value(#vm_try!(#try_clone::try_clone(value))))) - }; + if attrs.field { + let fields = index_fns.entry(n).or_default(); + let n = syn::LitInt::new(&n.to_string(), field.span()); - fields.push(quote!(#ident::#variant_ident { #n: value, .. } => #vm_result::Ok(#to_value))); + let access = attrs.clone_with.decorate(tokens, quote!(value)); + fields.push(quote!(#ident::#variant_ident { #n: value, .. } => #result::Ok(#to_value::to_value(#access)?))); + } } - } - variant_metas.push(quote! { - enum_.variant_mut(#variant_index)?.make_unnamed(#fields_len)?.static_docs(&#variant_docs)? - }); + make_constructor = variant_attr.constructor.or_implicit(|| { + make_unnamed_constructor( + tokens, + syn::parse_quote!(#ident #type_generics :: #variant_ident), + &fields.unnamed, + &field_attrs, + ) + }); - if variant_attr.constructor.is_some() && fields_len != fields.unnamed.len() { - cx.error(syn::Error::new_spanned(fields, "#[rune(constructor)] can only be used if all fields are marked with #[rune(get)")); + let len = field_attrs.iter().take_while(|f| f.field).count(); + make_fields = Some(quote!(.make_unnamed(#len)?)); } - - let constructor = variant_attr - .constructor - .is_some() - .then(|| quote!(#ident #type_generics :: #variant_ident)); - - variants.push((constructor, variant_attr)); + syn::Fields::Unit => { + make_constructor = variant_attr + .constructor + .or_implicit(|| quote!(|| #ident #type_generics :: #variant_ident)); + make_fields = Some(quote!(.make_empty()?)); + } + }, + TypeFields::Empty => { + make_constructor = attr.constructor.as_explicit(); + make_fields = Some(quote!(.make_empty()?)); } - syn::Fields::Unit => { - variant_metas.push(quote! { - enum_.variant_mut(#variant_index)?.make_empty()?.static_docs(&#variant_docs)? - }); - - let constructor = if variant_attr.constructor.is_some() { - Some(quote!(|| #ident #type_generics :: #variant_ident)) - } else { - None - }; - - variants.push((constructor, variant_attr)); + TypeFields::Unnamed(n) => { + make_constructor = attr.constructor.as_explicit(); + make_fields = Some(quote!(.make_unnamed(#n)?)); } } + + let make_constructor = make_constructor.map(|c| quote!(.constructor(#c)?)); + + variant_metas.push(quote! { + enum_.variant_mut(#variant_index)? + .static_docs(&#variant_docs)? + #make_fields + #make_constructor; + }); } let is_variant = quote! { @@ -501,8 +534,8 @@ fn expand_enum_install_with( module.field_function(&#protocol::GET, #field, |this: &Self| { match this { #(#matches,)* - _ => return #vm_result::err( - #runtime_error::__rune_macros__unsupported_object_field_get( + _ => #result::Err( + #errors::unsupported_object_field_get( ::ANY_TYPE_INFO ) ), @@ -516,11 +549,8 @@ fn expand_enum_install_with( module.index_function(&#protocol::GET, #index, |this: &Self| { match this { #(#matches,)* - _ => return #vm_result::err( - #runtime_error::__rune_macros__unsupported_tuple_index_get( - ::ANY_TYPE_INFO, - #index - ) + _ => return #result::Err( + #errors::unsupported_tuple_index_get(::ANY_TYPE_INFO, #index) ), } })?; @@ -539,29 +569,10 @@ fn expand_enum_install_with( let enum_meta = quote! { let mut enum_ = module.type_meta::()?.make_enum(&[#(#variant_names,)*])?.static_docs(&#docs)?; - #(#variant_metas;)* + #(#variant_metas)* }; installers.push(enum_meta); - - for (index, (constructor, attr)) in variants.iter().enumerate() { - let mut docs = syn::ExprArray { - attrs: Vec::new(), - bracket_token: syn::token::Bracket::default(), - elems: Punctuated::default(), - }; - - for el in &attr.docs { - docs.elems.push(el.clone()); - } - - let constructor = constructor.as_ref().map(|c| quote!(.constructor(#c)?)); - - installers.push(quote! { - module.variant_meta::(#index)?.static_docs(&#docs)?#constructor; - }); - } - Ok(()) } @@ -572,7 +583,6 @@ enum TypeKind { } pub struct TypeBuilder<'a, T> { - attr: &'a TypeAttr, ident: T, /// Hash of the type. type_hash: Hash, @@ -582,7 +592,6 @@ pub struct TypeBuilder<'a, T> { tokens: &'a Tokens, generics: syn::Generics, attrs: Vec, - params: Option, kind: TypeKind, } @@ -601,7 +610,6 @@ where pub(super) fn expand_derive(self) -> TokenStream { let TypeBuilder { - attr, ident, type_hash, type_item, @@ -642,30 +650,8 @@ where .. } = tokens; - let empty; - let mut current; - let generic_names; - - let (impl_generics, type_generics, where_clause) = match &attr.impl_params { - Some(params) => { - empty = syn::Generics::default(); - current = syn::Generics::default(); - - for p in params { - current.params.push(syn::GenericParam::Type(p.clone())); - } - - let (impl_generics, _, where_clause) = empty.split_for_impl(); - let (_, type_generics, _) = current.split_for_impl(); - generic_names = Vec::new(); - (impl_generics, type_generics, where_clause) - } - None => { - current = generics; - generic_names = current.type_params().map(|v| &v.ident).collect::>(); - current.split_for_impl() - } - }; + let generic_names = generics.type_params().map(|v| &v.ident).collect::>(); + let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); let named_rest = if let [first_name, remainder @ ..] = &generic_names[..] { Some(quote! { @@ -966,7 +952,7 @@ where type_item, tokens, attrs, - params, + generics, type_hash, .. } = self; @@ -984,11 +970,7 @@ where .. } = tokens; - let p = params - .as_ref() - .into_iter() - .flat_map(|p| p.params.iter()) - .collect::>(); + let p = generics.type_params().collect::>(); let type_hash = type_hash.into_inner(); let make_hash = quote!(#hash::new(#type_hash)); @@ -996,13 +978,13 @@ where quote! { #[automatically_derived] #(#attrs)* - impl #params #type_hash_t for #ident { + impl #generics #type_hash_t for #ident { const HASH: #hash = #make_hash; } #[automatically_derived] #(#attrs)* - impl #params #type_of for #ident + impl #generics #type_of for #ident where #(#p: #maybe_type_of,)* { @@ -1020,7 +1002,7 @@ where #[automatically_derived] #(#attrs)* - impl #params #maybe_type_of for #ident + impl #generics #maybe_type_of for #ident where #(#p: #maybe_type_of,)* { @@ -1033,64 +1015,83 @@ where } } -struct Params { - lt_token: Token![<], - params: Punctuated, - gt_token: Token![>], -} - -impl syn::parse::Parse for Params { - #[inline] - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let lt_token: Token![<] = input.parse()?; - - let mut params = Punctuated::new(); - - loop { - if input.peek(Token![>]) { - break; +fn make_named_constructor( + tokens: &Tokens, + path: syn::Path, + named: &Punctuated, + attrs: &[FieldAttr], +) -> TokenStream { + let Tokens { default, .. } = tokens; + + let args = named + .iter() + .zip(attrs) + .flat_map(|(syn::Field { ident, ty, .. }, a)| { + if !a.field { + return None; } - params.push_value(input.parse()?); - - if input.peek(Token![>]) { - break; - } + let ident = ident.as_ref()?; + Some(quote!(#ident: #ty)) + }); - params.push_punct(input.parse()?); + let field_names = named.iter().zip(attrs).flat_map(|(f, a)| { + if !a.field { + return None; } - Ok(Self { - lt_token, - params, - gt_token: input.parse()?, - }) + f.ident.as_ref() + }); + + // Pad out remaining fields with calls to `Default::default()`. + let remaining = named + .iter() + .zip(attrs) + .filter(|(_, a)| !a.field) + .filter_map(|(syn::Field { ident, ty, .. }, _)| { + let ident = ident.as_ref()?; + Some(quote!(#ident: <#ty as #default>::default())) + }); + + quote! { + |#(#args,)*| #path { #(#field_names,)* #(#remaining,)* } } } -impl ToTokens for Params { - #[inline] - fn to_tokens(&self, tokens: &mut TokenStream) { - self.lt_token.to_tokens(tokens); - self.params.to_tokens(tokens); - self.gt_token.to_tokens(tokens); +fn make_unnamed_constructor( + tokens: &Tokens, + path: syn::Path, + named: &Punctuated, + attrs: &[FieldAttr], +) -> TokenStream { + // If all fields are visible, then we can simply just return the path as a + // constructor. Otherwise we need to pad them out with default impls. + if attrs.iter().all(|f| f.field) { + return quote!(#path); } -} -fn make_constructor(path: syn::Path, named: &Punctuated) -> impl ToTokens { - let args = named.iter().flat_map(|f| { - let ident = f.ident.as_ref()?; - let typ = &f.ty; - Some(quote!(#ident: #typ)) - }); + let Tokens { default, .. } = tokens; - let field_names = named.iter().flat_map(|f| f.ident.as_ref()); + let field_names = named + .iter() + .zip(attrs) + .enumerate() + .take_while(|(_, (_, a))| a.field) + .map(|(n, _)| quote::format_ident!("v{n}")); + + let args = named + .iter() + .zip(field_names.clone()) + .flat_map(|(syn::Field { ty, .. }, ident)| Some(quote!(#ident: #ty))); + + // Pad out remaining fields with calls to `Default::default()`. + let remaining = named + .iter() + .zip(attrs) + .skip_while(|(_, a)| a.field) + .map(|(syn::Field { ty, .. }, _)| quote!(<#ty as #default>::default())); quote! { - .constructor(|#(#args),*| { - #path { - #(#field_names),* - } - })? + |#(#args,)*| #path(#(#field_names,)* #(#remaining,)*) } } diff --git a/crates/rune-macros/src/context.rs b/crates/rune-macros/src/context.rs index 9f213ad43..090524603 100644 --- a/crates/rune-macros/src/context.rs +++ b/crates/rune-macros/src/context.rs @@ -13,10 +13,51 @@ use rune_core::protocol::Protocol; use super::RUNE; +#[derive(Default, Clone)] +pub(super) enum CloneWith { + /// Use `rune::alloc::clone::TryClone`. + #[default] + TryClone, + /// Use `::alloc::clone::Clone`. + Clone, + /// The field is `Copy`. + Copy, + /// The field can be cloned with the given function. + With(syn::Path), + /// The field can be fallibly cloned with the given function. + TryWith(syn::Path), +} + +impl CloneWith { + pub(super) fn decorate(&self, tokens: &Tokens, access: TokenStream) -> TokenStream { + let Tokens { + try_clone, clone, .. + } = tokens; + + match self { + Self::TryClone => { + quote!(#try_clone::try_clone(#access)?) + } + Self::Clone => { + quote!(#clone::clone(#access)) + } + Self::Copy => { + quote!(*#access) + } + Self::With(path) => { + quote!(#path(#access)) + } + Self::TryWith(path) => { + quote!(#path(#access)?) + } + } + } +} + /// Parsed `#[rune(..)]` field attributes. #[derive(Default)] #[must_use = "Attributes must be used or explicitly ignored"] -pub(crate) struct FieldAttrs { +pub(crate) struct FieldAttr { /// A field that is an identifier. Should use `Default::default` to be /// constructed and ignored during `ToTokens` and `Spanned`. pub(crate) id: Option, @@ -30,18 +71,17 @@ pub(crate) struct FieldAttrs { pub(crate) meta: Option, /// A single field marked with `#[rune(span)]`. pub(crate) span: Option, - /// Custom parser `#[rune(parse_with = "..")]`. - pub(crate) parse_with: Option, + /// Custom parser `#[rune(parse_with)]`. + pub(crate) parse_with: Option, /// `#[rune(..)]` to generate a protocol function. pub(crate) protocols: Vec, - /// `#[rune(copy)]` to indicate that a field is copy and does not need to be - /// cloned. - pub(crate) copy: bool, + /// The method to use when cloning the field. + pub(crate) clone_with: CloneWith, /// Whether this field should be known at compile time or not. pub(crate) field: bool, } -impl FieldAttrs { +impl FieldAttr { /// Indicate if the field should be skipped. pub(crate) fn skip(&self) -> bool { self.skip.is_some() || self.id.is_some() @@ -71,6 +111,54 @@ impl Default for ParseKind { } } +#[derive(Default)] +pub(crate) enum TypeFields { + #[default] + Default, + Empty, + Unnamed(syn::LitInt), +} + +#[derive(Default)] +pub(crate) enum TypeConstructor { + #[default] + None, + /// An implicit constructor using all visible fields. + Implicit(Span), + /// Path to an explicit constructor. + Explicit(syn::Path), +} + +impl TypeConstructor { + /// Get the explicit type constructor, or generate an implicit if specified. + #[inline] + pub(crate) fn or_implicit(&self, f: impl FnOnce() -> TokenStream) -> Option { + match self { + Self::None => None, + Self::Implicit(..) => Some(f()), + Self::Explicit(path) => Some(quote! { #path }), + } + } + + /// Get the explicit type constructor, if any. + #[inline] + pub(crate) fn as_explicit(&self) -> Option { + match self { + Self::Explicit(path) => Some(quote! { #path }), + _ => None, + } + } + + /// Get the span of the constructor, if any. + pub(crate) fn as_span(&self) -> Option { + match self { + Self::None => None, + Self::Implicit(span) => Some(*span), + Self::Explicit(path) => Some(path.span()), + } + } +} + /// Parsed field attributes. #[derive(Default)] #[must_use = "Attributes must be used or explicitly ignored"] @@ -85,12 +173,12 @@ pub(crate) struct TypeAttr { pub(crate) parse: ParseKind, /// `#[rune(item = )]`. pub(crate) item: Option, + /// `#[rune(fields)]` to suppress default metadata. + pub(crate) fields: TypeFields, /// `#[rune(constructor)]`. - pub(crate) constructor: Option, + pub(crate) constructor: TypeConstructor, /// Parsed documentation. pub(crate) docs: Vec, - /// Method to use to convert from value. - pub(crate) impl_params: Option>, } /// Parsed #[const_value(..)] field attributes. @@ -105,8 +193,10 @@ pub(crate) struct ConstValueTypeAttr { #[derive(Default)] #[must_use = "Attributes must be used or explicitly ignored"] pub(crate) struct VariantAttrs { + /// `#[rune(fields)]` to suppress default metadata. + pub(crate) fields: TypeFields, /// `#[rune(constructor)]`. - pub(crate) constructor: Option, + pub(crate) constructor: TypeConstructor, /// Discovered documentation. pub(crate) docs: Vec, } @@ -125,7 +215,7 @@ pub(crate) enum GenerateTarget<'a> { #[derive(Clone)] pub(crate) struct Generate<'a> { pub(crate) tokens: &'a Tokens, - pub(crate) attrs: &'a FieldAttrs, + pub(crate) attr: &'a FieldAttr, pub(crate) protocol: &'a FieldProtocol, pub(crate) field: &'a syn::Field, pub(crate) ty: &'a syn::Type, @@ -260,7 +350,7 @@ impl Context { } /// Parse field attributes. - pub(crate) fn field_attrs(&self, input: &[syn::Attribute]) -> FieldAttrs { + pub(crate) fn field_attrs(&self, input: &[syn::Attribute]) -> FieldAttr { macro_rules! generate_assign { ($proto:ident, $op:tt) => { |g| { @@ -351,7 +441,7 @@ impl Context { }; } - let mut attr = FieldAttrs::default(); + let mut attr = FieldAttr::default(); for a in input { if !a.path().is_ident(RUNE) { @@ -419,7 +509,24 @@ impl Context { } if meta.path.is_ident("copy") { - attr.copy = true; + attr.clone_with = CloneWith::Copy; + return Ok(()); + } + + if meta.path.is_ident("clone") { + attr.clone_with = CloneWith::Clone; + return Ok(()); + } + + if meta.path.is_ident("clone_with") { + meta.input.parse::()?; + attr.clone_with = CloneWith::With(meta.input.parse()?); + return Ok(()); + } + + if meta.path.is_ident("try_clone_with") { + meta.input.parse::()?; + attr.clone_with = CloneWith::TryWith(meta.input.parse()?); return Ok(()); } @@ -427,7 +534,7 @@ impl Context { if let Some(old) = &attr.parse_with { let mut error = syn::Error::new_spanned( &meta.path, - "#[rune(parse_with = \"..\")] can only be used once", + "#[rune(parse_with)] can only be used once", ); error.combine(syn::Error::new_spanned(old, "previously defined here")); @@ -435,8 +542,7 @@ impl Context { } meta.input.parse::()?; - let s = meta.input.parse::()?; - attr.parse_with = Some(syn::Ident::new(&s.value(), s.span())); + attr.parse_with = Some(meta.input.parse()?); return Ok(()); } @@ -451,37 +557,26 @@ impl Context { } = g; let Tokens { - try_clone, - vm_try, - vm_result, + result, + runtime_error, .. } = g.tokens; match target { GenerateTarget::Named { field_ident, field_name } => { - let access = if g.attrs.copy { - quote!(s.#field_ident) - } else { - quote!(#vm_try!(#try_clone::try_clone(&s.#field_ident))) - }; - + let access = g.attr.clone_with.decorate(g.tokens, quote!(&s.#field_ident)); let protocol = g.tokens.protocol(&Protocol::GET); quote_spanned! { g.field.span() => - module.field_function(&#protocol, #field_name, |s: &Self| #vm_result::Ok(#access))?; + module.field_function(&#protocol, #field_name, |s: &Self| #result::<_, #runtime_error>::Ok(#access))?; } } GenerateTarget::Numbered { field_index } => { - let access = if g.attrs.copy { - quote!(s.#field_index) - } else { - quote!(#vm_try!(#try_clone::try_clone(&s.#field_index))) - }; - + let access = g.attr.clone_with.decorate(g.tokens, quote!(&s.#field_index)); let protocol = g.tokens.protocol(&Protocol::GET); quote_spanned! { g.field.span() => - module.index_function(&#protocol, #field_index, |s: &Self| #vm_result::Ok(#access))?; + module.index_function(&#protocol, #field_index, |s: &Self| #result::<_, #runtime_error>::Ok(#access))?; } } } @@ -625,6 +720,18 @@ impl Context { return Ok(()); } + if meta.path.is_ident("empty") { + attr.fields = TypeFields::Empty; + return Ok(()); + } + + if meta.path.is_ident("unnamed") { + let input; + _ = syn::parenthesized!(input in meta.input); + attr.fields = TypeFields::Unnamed(input.parse::()?); + return Ok(()); + } + if meta.path.is_ident("name") { meta.input.parse::()?; attr.name = Some(meta.input.parse()?); @@ -648,23 +755,22 @@ impl Context { } if meta.path.is_ident("constructor") { - if attr.constructor.is_some() { - return Err(syn::Error::new( + if let Some(span) = attr.constructor.as_span() { + let mut error = syn::Error::new( meta.path.span(), "#[rune(constructor)] must only be used once", - )); + ); + + error.combine(syn::Error::new(span, "Previously defined here")); + return Err(error); } - attr.constructor = Some(meta.path.span()); - return Ok(()); - } + if meta.input.parse::>()?.is_some() { + attr.constructor = TypeConstructor::Explicit(meta.input.parse()?); + } else { + attr.constructor = TypeConstructor::Implicit(meta.path.span()); + } - if meta.path.is_ident("impl_params") { - meta.input.parse::()?; - let content; - syn::bracketed!(content in meta.input); - attr.impl_params = - Some(syn::punctuated::Punctuated::parse_terminated(&content)?); return Ok(()); } @@ -700,20 +806,39 @@ impl Context { } let result = a.parse_nested_meta(|meta| { + if meta.path.is_ident("empty") { + attr.fields = TypeFields::Empty; + return Ok(()); + } + + if meta.path.is_ident("unnamed") { + let input; + _ = syn::parenthesized!(input in meta.input); + attr.fields = TypeFields::Unnamed(input.parse::()?); + return Ok(()); + } + if meta.path.is_ident("constructor") { - if attr.constructor.is_some() { - return Err(syn::Error::new( + if let Some(span) = attr.constructor.as_span() { + let mut error = syn::Error::new( meta.path.span(), "#[rune(constructor)] must only be used once", - )); + ); + + error.combine(syn::Error::new(span, "Previously defined here")); + return Err(error); } - attr.constructor = Some(meta.path.span()); - } else { - return Err(syn::Error::new_spanned(&meta.path, "Unsupported attribute")); + if meta.input.parse::>()?.is_some() { + attr.constructor = TypeConstructor::Explicit(meta.input.parse()?); + } else { + attr.constructor = TypeConstructor::Implicit(meta.path.span()); + } + + return Ok(()); } - Ok(()) + Err(syn::Error::new_spanned(&meta.path, "Unsupported attribute")) }); if let Err(e) = result { @@ -779,64 +904,63 @@ impl Context { Tokens { alloc: path(m, ["alloc"]), - any_marker_t: path(m, ["__private", "AnyMarker"]), + any_marker_t: path(m, ["__priv", "AnyMarker"]), any_t: path(m, ["Any"]), - any_type_info: path(m, ["runtime", "AnyTypeInfo"]), - arc: path(m, ["__private", "Arc"]), + any_type_info: path(m, ["__priv", "AnyTypeInfo"]), + arc: path(m, ["__priv", "Arc"]), + clone: path(m, ["__priv", "Clone"]), compile_error: path(m, ["compile", "Error"]), - const_construct_t: path(m, ["runtime", "ConstConstruct"]), - const_value: path(m, ["runtime", "ConstValue"]), + const_construct_t: path(m, ["__priv", "ConstConstruct"]), + const_value: path(m, ["__priv", "ConstValue"]), context_error: path(m, ["compile", "ContextError"]), + default: path(core, ["default", "Default"]), double_ended_iterator: path(core, ["iter", "DoubleEndedIterator"]), + errors: path(m, ["__priv", "e"]), fmt: path(core, ["fmt"]), - from_const_value_t: path(m, ["runtime", "FromConstValue"]), - from_value: path(m, ["runtime", "FromValue"]), + from_const_value_t: path(m, ["__priv", "FromConstValue"]), + from_value: path(m, ["__priv", "FromValue"]), hash: path(m, ["Hash"]), id: path(m, ["parse", "Id"]), - install_with: path(m, ["__private", "InstallWith"]), + install_with: path(m, ["__priv", "InstallWith"]), into_iterator: path(core, ["iter", "IntoIterator"]), - item: path(m, ["Item"]), + item: path(m, ["__priv", "Item"]), iterator: path(core, ["iter", "Iterator"]), macro_context: path(m, ["macros", "MacroContext"]), - maybe_type_of: path(m, ["runtime", "MaybeTypeOf"]), + maybe_type_of: path(m, ["__priv", "MaybeTypeOf"]), meta: path(m, ["compile", "meta"]), - module: path(m, ["__private", "Module"]), + module: path(m, ["__priv", "Module"]), named: path(m, ["compile", "Named"]), non_null: path(core, ["ptr", "NonNull"]), - object: path(m, ["runtime", "Object"]), + object: path(m, ["__priv", "Object"]), opaque: path(m, ["parse", "Opaque"]), option_spanned: path(m, ["ast", "OptionSpanned"]), option: path(core, ["option", "Option"]), - owned_tuple: path(m, ["runtime", "OwnedTuple"]), + owned_tuple: path(m, ["__priv", "OwnedTuple"]), parse: path(m, ["parse", "Parse"]), parser: path(m, ["parse", "Parser"]), - protocol: path(m, ["runtime", "Protocol"]), - raw_value_guard: path(m, ["runtime", "RawValueGuard"]), + protocol: path(m, ["__priv", "Protocol"]), + raw_value_guard: path(m, ["__priv", "RawValueGuard"]), result: path(core, ["result", "Result"]), - runtime_error: path(m, ["runtime", "RuntimeError"]), + runtime_error: path(m, ["__priv", "RuntimeError"]), span: path(m, ["ast", "Span"]), spanned: path(m, ["ast", "Spanned"]), - string: path(m, ["alloc", "String"]), - to_const_value_t: path(m, ["runtime", "ToConstValue"]), + to_const_value_t: path(m, ["__priv", "ToConstValue"]), to_tokens: path(m, ["macros", "ToTokens"]), - to_value: path(m, ["runtime", "ToValue"]), + to_value: path(m, ["__priv", "ToValue"]), token_stream: path(m, ["macros", "TokenStream"]), try_clone: path(m, ["alloc", "clone", "TryClone"]), try_from: path(core, ["convert", "TryFrom"]), - tuple: path(m, ["runtime", "Tuple"]), - type_hash_t: path(m, ["runtime", "TypeHash"]), + tuple: path(m, ["__priv", "Tuple"]), + type_hash_t: path(m, ["__priv", "TypeHash"]), type_name: path(core, ["any", "type_name"]), - type_of: path(m, ["runtime", "TypeOf"]), - type_value: path(m, ["runtime", "TypeValue"]), - unsafe_to_mut: path(m, ["runtime", "UnsafeToMut"]), - unsafe_to_ref: path(m, ["runtime", "UnsafeToRef"]), - unsafe_to_value: path(m, ["runtime", "UnsafeToValue"]), - value_mut_guard: path(m, ["runtime", "ValueMutGuard"]), - value_ref_guard: path(m, ["runtime", "ValueRefGuard"]), - value: path(m, ["runtime", "Value"]), - vec: path(m, ["alloc", "Vec"]), - vm_result: path(m, ["runtime", "VmResult"]), - vm_try: path(m, ["vm_try"]), + type_of: path(m, ["__priv", "TypeOf"]), + type_value: path(m, ["__priv", "TypeValue"]), + unsafe_to_mut: path(m, ["__priv", "UnsafeToMut"]), + unsafe_to_ref: path(m, ["__priv", "UnsafeToRef"]), + unsafe_to_value: path(m, ["__priv", "UnsafeToValue"]), + value_mut_guard: path(m, ["__priv", "ValueMutGuard"]), + value_ref_guard: path(m, ["__priv", "ValueRefGuard"]), + value: path(m, ["__priv", "Value"]), write: path(core, ["write"]), } } @@ -877,11 +1001,14 @@ pub(crate) struct Tokens { pub(crate) any_t: syn::Path, pub(crate) any_type_info: syn::Path, pub(crate) arc: syn::Path, + pub(crate) clone: syn::Path, pub(crate) compile_error: syn::Path, pub(crate) const_construct_t: syn::Path, pub(crate) const_value: syn::Path, pub(crate) context_error: syn::Path, + pub(crate) default: syn::Path, pub(crate) double_ended_iterator: syn::Path, + pub(crate) errors: syn::Path, pub(crate) fmt: syn::Path, pub(crate) from_const_value_t: syn::Path, pub(crate) from_value: syn::Path, @@ -910,7 +1037,6 @@ pub(crate) struct Tokens { pub(crate) runtime_error: syn::Path, pub(crate) span: syn::Path, pub(crate) spanned: syn::Path, - pub(crate) string: syn::Path, pub(crate) to_const_value_t: syn::Path, pub(crate) to_tokens: syn::Path, pub(crate) to_value: syn::Path, @@ -928,9 +1054,6 @@ pub(crate) struct Tokens { pub(crate) value_mut_guard: syn::Path, pub(crate) value_ref_guard: syn::Path, pub(crate) value: syn::Path, - pub(crate) vec: syn::Path, - pub(crate) vm_result: syn::Path, - pub(crate) vm_try: syn::Path, pub(crate) write: syn::Path, } diff --git a/crates/rune-macros/src/from_value.rs b/crates/rune-macros/src/from_value.rs index 7d9cdb265..dfd6a1c7b 100644 --- a/crates/rune-macros/src/from_value.rs +++ b/crates/rune-macros/src/from_value.rs @@ -107,6 +107,7 @@ impl Expander<'_> { value, result, runtime_error, + errors, .. } = &self.tokens; @@ -139,14 +140,14 @@ impl Expander<'_> { let missing = quote! { name => { - return #result::Err(#runtime_error::__rune_macros__missing_variant(name)?); + return #result::Err(#errors::missing_variant(name)); } }; let variant = quote! { #type_value::EmptyStruct(data) => { let Some(name) = data.rtti().item().base_name() else { - return #result::Err(#runtime_error::__rune_macros__missing_variant_name()); + return #result::Err(#errors::missing_variant_name()); }; match name { @@ -155,7 +156,7 @@ impl Expander<'_> { } #type_value::TupleStruct(tuple) => { let Some(name) = tuple.rtti().item().base_name() else { - return #result::Err(#runtime_error::__rune_macros__missing_variant_name()); + return #result::Err(#errors::missing_variant_name()); }; match name { @@ -164,7 +165,7 @@ impl Expander<'_> { } #type_value::Struct(object) => { let Some(name) = object.rtti().item().base_name() else { - return #result::Err(#runtime_error::__rune_macros__missing_variant_name()); + return #result::Err(#errors::missing_variant_name()); }; match name { @@ -180,7 +181,7 @@ impl Expander<'_> { match #value::as_type_value(&value)? { #variant, actual => { - #result::Err(#runtime_error::__rune_macros__expected_variant(#type_value::type_info(&actual))) + #result::Err(#errors::expected_variant(#type_value::type_info(&actual))) } } } @@ -211,7 +212,7 @@ impl Expander<'_> { result, type_name, try_clone, - runtime_error, + errors, .. } = &self.tokens; @@ -225,7 +226,7 @@ impl Expander<'_> { #from_value::from_value(value)? } None => { - return #result::Err(#runtime_error::__rune_macros__missing_tuple_index(#type_name::(), #index)); + return #result::Err(#errors::missing_tuple_index(#type_name::(), #index)); } } }); @@ -247,8 +248,8 @@ impl Expander<'_> { let Tokens { from_value, result, - runtime_error, type_name, + errors, .. } = &self.tokens; @@ -257,7 +258,7 @@ impl Expander<'_> { #ident: match object.get(#name) { Some(value) => #from_value::from_value(value.clone())?, None => { - return #result::Err(#runtime_error::__rune_macros__missing_struct_field(#type_name::(), #name)); + return #result::Err(#errors::missing_struct_field(#type_name::(), #name)); } } }); diff --git a/crates/rune-macros/src/function.rs b/crates/rune-macros/src/function.rs index e046705f7..f9a7d9166 100644 --- a/crates/rune-macros/src/function.rs +++ b/crates/rune-macros/src/function.rs @@ -281,11 +281,11 @@ impl Function { for argument in arguments { array.elems.push(syn::Expr::Verbatim(quote! { - <#argument as rune::__private::TypeHash>::HASH + <#argument as rune::__priv::TypeHash>::HASH })); } - quote!(rune::__private::Params::new(#name, #array)) + quote!(rune::__priv::Params::new(#name, #array)) } else { quote!(#name) }; @@ -323,16 +323,18 @@ impl Function { let vm_result = VmResult::new(); if attrs.vm_result { - let vm_result = &vm_result.vm_result; + let VmResult { + result, vm_error, .. + } = &vm_result; sig.output = match sig.output { syn::ReturnType::Default => syn::ReturnType::Type( ]>::default(), - Box::new(syn::Type::Verbatim(quote!(#vm_result<()>))), + Box::new(syn::Type::Verbatim(quote!(#result<(), #vm_error>))), ), syn::ReturnType::Type(arrow, ty) => syn::ReturnType::Type( arrow, - Box::new(syn::Type::Verbatim(quote!(#vm_result<#ty>))), + Box::new(syn::Type::Verbatim(quote!(#result<#ty, #vm_error>))), ), }; } @@ -374,12 +376,12 @@ impl Function { #[automatically_derived] #attributes #[doc(hidden)] - pub(crate) fn #meta_fn #impl_generics() -> rune::alloc::Result + pub(crate) fn #meta_fn #impl_generics() -> rune::alloc::Result #where_clause { - Ok(rune::__private::FunctionMetaData { - kind: rune::__private::FunctionMetaKind::#meta_kind(#name, #real_fn_path #type_generics)?#build_with, - statics: rune::__private::FunctionMetaStatics { + Ok(rune::__priv::FunctionMetaData { + kind: rune::__priv::FunctionMetaKind::#meta_kind(#name, #real_fn_path #type_generics)?#build_with, + statics: rune::__priv::FunctionMetaStatics { name: #name_string, deprecated: #deprecated, docs: &#docs[..], @@ -419,23 +421,23 @@ fn expr_lit(ident: &syn::Ident) -> syn::Expr { } struct VmResult { - vm_result: syn::Path, - from: syn::Path, result: syn::Path, + from: syn::Path, + vm_error: syn::Path, } impl VmResult { fn new() -> Self { Self { - vm_result: syn::parse_quote!(rune::runtime::VmResult), - from: syn::parse_quote!(core::convert::From), - result: syn::parse_quote!(core::result::Result), + result: syn::parse_quote!(::core::result::Result), + from: syn::parse_quote!(::core::convert::From), + vm_error: syn::parse_quote!(rune::VmError), } } /// Modify the block so that it is fallible. fn block(&self, ast: &mut syn::Block, top_level: bool) -> syn::Result<()> { - let vm_result = &self.vm_result; + let result = &self.result; for stmt in &mut ast.stmts { match stmt { @@ -468,7 +470,7 @@ impl VmResult { found = true; *expr = syn::Expr::Verbatim(quote_spanned! { - expr.span() => #vm_result::Ok(#expr) + expr.span() => #result::Ok(#expr) }); } @@ -478,7 +480,7 @@ impl VmResult { if !found { ast.stmts.push(syn::Stmt::Expr( - syn::Expr::Verbatim(quote!(#vm_result::Ok(()))), + syn::Expr::Verbatim(quote!(#result::Ok(()))), None, )); } @@ -488,11 +490,7 @@ impl VmResult { } fn expr(&self, ast: &mut syn::Expr) -> syn::Result<()> { - let Self { - vm_result, - from, - result, - } = self; + let Self { result, from, .. } = self; let outcome = 'outcome: { match ast { @@ -600,9 +598,9 @@ impl VmResult { expr.expr = Some(Box::new(match expr.expr.take() { Some(expr) => syn::Expr::Verbatim(quote_spanned! { expr.span() => - #vm_result::Ok(#expr) + #result::Ok(#expr) }), - None => syn::Expr::Verbatim(quote!(#vm_result::Ok(()))), + None => syn::Expr::Verbatim(quote!(#result::Ok(()))), })); } syn::Expr::Struct(expr) => { @@ -615,18 +613,18 @@ impl VmResult { self.expr(&mut expr.expr)?; - break 'outcome if let Some((expr, ident)) = as_vm_expr(&mut expr.expr) { - let vm_try = syn::Ident::new("vm_try", ident.span()); - quote_spanned!(span => rune::#vm_try!(#expr)) + break 'outcome if let Some(expr) = as_vm_expr(&mut expr.expr) { + quote_spanned!(span => #expr?) } else { let value = &mut expr.expr; - let from = quote_spanned!(expr.question_token.span() => #from::from); quote_spanned! { span => match #value { #result::Ok(value) => value, - #result::Err(error) => return #vm_result::Ok(#result::Err(#[allow(clippy::useless_conversion)] #from(error))), + #result::Err(error) => { + return #result::Ok(#result::Err(#[allow(clippy::useless_conversion)] #from::from(error))); + } } } }; @@ -663,7 +661,7 @@ impl VmResult { } /// If this is a field expression like `.vm`. -fn as_vm_expr(expr: &mut syn::Expr) -> Option<(&mut syn::Expr, &syn::Ident)> { +fn as_vm_expr(expr: &mut syn::Expr) -> Option<&mut syn::Expr> { let syn::Expr::Field(expr) = expr else { return None; }; @@ -672,5 +670,5 @@ fn as_vm_expr(expr: &mut syn::Expr) -> Option<(&mut syn::Expr, &syn::Ident)> { return None; }; - (ident == "vm").then_some((&mut expr.base, ident)) + (ident == "vm").then_some(&mut expr.base) } diff --git a/crates/rune-macros/src/item.rs b/crates/rune-macros/src/item.rs index dc5c6ff5c..dd7305936 100644 --- a/crates/rune-macros/src/item.rs +++ b/crates/rune-macros/src/item.rs @@ -1,10 +1,16 @@ use core::mem::take; use proc_macro2::Span; -use rune_core::item::{ComponentRef, ItemBuf}; +use rune_core::item::{ComponentRef, Item, ItemBuf}; /// Construct a static item from a path. pub(crate) fn build_item(path: &syn::Path) -> syn::Result { + let buf = build_buf(path)?; + Ok(buf_as_bytes(&buf)) +} + +/// Construct a static item from a path. +pub(crate) fn build_buf(path: &syn::Path) -> syn::Result { let mut buf = ItemBuf::new(); let mut first = path.leading_colon.is_some(); @@ -37,6 +43,10 @@ pub(crate) fn build_item(path: &syn::Path) -> syn::Result { } } + Ok(buf) +} + +pub(crate) fn buf_as_bytes(buf: &Item) -> syn::ExprArray { let mut elems = syn::punctuated::Punctuated::new(); for &byte in buf.as_bytes() { @@ -48,9 +58,9 @@ pub(crate) fn build_item(path: &syn::Path) -> syn::Result { })); } - Ok(syn::ExprArray { + syn::ExprArray { attrs: Vec::new(), bracket_token: syn::token::Bracket::default(), elems, - }) + } } diff --git a/crates/rune-macros/src/lib.rs b/crates/rune-macros/src/lib.rs index 9564ab7e9..e6969fec8 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 @@ -52,6 +52,7 @@ use syn::{Generics, Path}; const RUNE: &str = "rune"; #[proc_macro] +#[doc(hidden)] pub fn quote(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = proc_macro2::TokenStream::from(input); let parser = crate::quote::Quote::new(); @@ -65,6 +66,7 @@ pub fn quote(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } #[proc_macro_attribute] +#[doc(hidden)] pub fn function( attrs: proc_macro::TokenStream, item: proc_macro::TokenStream, @@ -81,6 +83,7 @@ pub fn function( } #[proc_macro_attribute] +#[doc(hidden)] pub fn macro_( attrs: proc_macro::TokenStream, item: proc_macro::TokenStream, @@ -97,6 +100,7 @@ pub fn macro_( } #[proc_macro_attribute] +#[doc(hidden)] pub fn module( attrs: proc_macro::TokenStream, item: proc_macro::TokenStream, @@ -113,6 +117,7 @@ pub fn module( } #[proc_macro_attribute] +#[doc(hidden)] pub fn attribute_macro( attrs: proc_macro::TokenStream, item: proc_macro::TokenStream, @@ -142,8 +147,8 @@ pub fn parse(input: proc_macro::TokenStream) -> proc_macro::TokenStream { Context::build(|cx| derive.expand(cx)).into() } +/// Helper derive to implement `Spanned`. #[proc_macro_derive(Spanned, attributes(rune))] -#[doc(hidden)] pub fn spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let derive = syn::parse_macro_input!(input as spanned::Derive); Context::build(|cx| derive.expand(cx, false)).into() @@ -164,18 +169,21 @@ pub fn opaque(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } #[proc_macro_derive(FromValue, attributes(rune))] +#[doc(hidden)] pub fn from_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); Context::build(|cx| from_value::expand(cx, &input)).into() } #[proc_macro_derive(ToValue, attributes(rune))] +#[doc(hidden)] pub fn to_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); Context::build(|cx| to_value::expand(cx, &input)).into() } #[proc_macro_derive(Any, attributes(rune))] +#[doc(hidden)] pub fn any(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let derive = syn::parse_macro_input!(input as any::Derive); @@ -189,21 +197,14 @@ pub fn any(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } #[proc_macro_derive(ToConstValue, attributes(const_value))] +#[doc(hidden)] pub fn const_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let derive = syn::parse_macro_input!(input as const_value::Derive); Context::build(|cx| Ok(derive.into_builder(cx)?.expand())).into() } -/// Calculate a type hash at compile time. -/// -/// # Examples -/// -/// ``` -/// use rune::Hash; -/// -/// let hash: Hash = rune::hash!(::std::ops::generator::Generator); -/// ``` #[proc_macro] +#[doc(hidden)] pub fn hash(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let args = syn::parse_macro_input!(input as self::hash::Arguments); @@ -216,8 +217,8 @@ pub fn hash(input: proc_macro::TokenStream) -> proc_macro::TokenStream { stream.into() } -#[doc(hidden)] #[proc_macro] +#[doc(hidden)] pub fn hash_in(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let path_in::PathIn { in_crate, item, .. } = syn::parse_macro_input!(input as path_in::PathIn); @@ -230,24 +231,8 @@ pub fn hash_in(input: proc_macro::TokenStream) -> proc_macro::TokenStream { stream.into() } -/// Calculate an item reference at compile time. -/// -/// # Examples -/// -/// ``` -/// use rune::{Item, ItemBuf}; -/// -/// static ITEM: &Item = rune::item!(::std::ops::generator::Generator); -/// -/// let mut item = ItemBuf::with_crate("std")?; -/// item.push("ops")?; -/// item.push("generator")?; -/// item.push("Generator")?; -/// -/// assert_eq!(item, ITEM); -/// # Ok::<_, rune::alloc::Error>(()) -/// ``` #[proc_macro] +#[doc(hidden)] pub fn item(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let path = syn::parse_macro_input!(input as syn::Path); @@ -276,9 +261,6 @@ pub fn item_in(input: proc_macro::TokenStream) -> proc_macro::TokenStream { stream.into() } -/// Helper to generate bindings for an external type. -/// -/// This can *only* be used inside of the `rune` crate itself. #[proc_macro] #[doc(hidden)] pub fn binding(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -286,10 +268,9 @@ pub fn binding(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let stream = Context::build_with_crate(|cx| { let mut stream = TokenStream::default(); - let attr = context::TypeAttr::default(); let tokens = cx.tokens_with_module(None); - for builder in derive.into_any_builders(cx, &attr, &tokens) { + for builder in derive.into_any_builders(cx, &tokens) { stream.extend(builder.expand()); } @@ -299,7 +280,6 @@ pub fn binding(input: proc_macro::TokenStream) -> proc_macro::TokenStream { stream.into() } -/// Shim for an ignored `#[stable]` attribute. #[proc_macro_attribute] #[doc(hidden)] pub fn stable( @@ -309,7 +289,6 @@ pub fn stable( item } -/// Shim for an ignored `#[unstable]` attribute. #[proc_macro_attribute] #[doc(hidden)] pub fn unstable( diff --git a/crates/rune-macros/src/macro_.rs b/crates/rune-macros/src/macro_.rs index e44d3d346..b7886fe3d 100644 --- a/crates/rune-macros/src/macro_.rs +++ b/crates/rune-macros/src/macro_.rs @@ -180,9 +180,9 @@ impl Macro { stream.extend(quote! { /// Get function metadata. #[automatically_derived] - #meta_vis fn #meta_fn() -> rune::alloc::Result { - Ok(rune::__private::MacroMetaData { - kind: rune::__private::MacroMetaKind::#macro_kind(#meta_name, #real_fn_path)?, + #meta_vis fn #meta_fn() -> rune::alloc::Result { + Ok(rune::__priv::MacroMetaData { + kind: rune::__priv::MacroMetaKind::#macro_kind(#meta_name, #real_fn_path)?, name: #name_string, docs: &#docs[..], }) diff --git a/crates/rune-macros/src/module.rs b/crates/rune-macros/src/module.rs index 9dd74f899..d82ed497c 100644 --- a/crates/rune-macros/src/module.rs +++ b/crates/rune-macros/src/module.rs @@ -1,4 +1,4 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use syn::parse::ParseStream; use syn::punctuated::Punctuated; @@ -65,47 +65,26 @@ impl Module { pub(crate) fn expand(self, attrs: ModuleAttrs) -> syn::Result { let docs = self.docs; - let item = match attrs.path.leading_colon { - Some(..) => { - let mut it = attrs.path.segments.iter(); - - let Some(krate) = it.next() else { - return Err(syn::Error::new_spanned( - &attrs.path, - "missing leading segment", - )); - }; - - let krate = syn::LitStr::new(&krate.ident.to_string(), krate.ident.span()); - let item = build_item(it); - - if item.elems.is_empty() { - quote!(rune::__private::ItemBuf::with_crate(#krate)?) - } else { - quote!(rune::__private::ItemBuf::with_crate_item(#krate, #item)?) - } - } - None => { - let item = build_item(attrs.path.segments.iter()); - - if item.elems.is_empty() { - quote!(rune::__private::ItemBuf::new()?) - } else { - quote!(rune::__private::ItemBuf::from_item(#item)?) - } - } - }; + let item_buf = crate::item::build_buf(&attrs.path)?; + let item_bytes = crate::item::buf_as_bytes(&item_buf); let mut stream = TokenStream::new(); + let name = quote::format_ident!("{}__meta", self.signature.ident); + let doc = syn::LitStr::new( + &format!(" Module metadata for `{item_buf}`."), + Span::call_site(), + ); + stream.extend(quote! { - /// Get module metadata. + #[doc = #doc] #[automatically_derived] + #[allow(non_snake_case)] #[doc(hidden)] - fn module_meta() -> rune::alloc::Result { - Ok(rune::__private::ModuleMetaData { + fn #name() -> rune::alloc::Result { + Ok(rune::__priv::ModuleMetaData { + item: unsafe { rune::__priv::Item::from_bytes(&#item_bytes) }, docs: &#docs[..], - item: #item, }) } }); @@ -122,21 +101,3 @@ impl Module { Ok(stream) } } - -fn build_item(it: syn::punctuated::Iter<'_, syn::PathSegment>) -> syn::ExprArray { - let mut item = syn::ExprArray { - attrs: Vec::new(), - bracket_token: syn::token::Bracket::default(), - elems: Punctuated::default(), - }; - - for p in it { - let p = syn::LitStr::new(&p.ident.to_string(), p.ident.span()); - - item.elems.push(syn::Expr::Lit(syn::ExprLit { - attrs: Vec::new(), - lit: syn::Lit::Str(p), - })) - } - item -} diff --git a/crates/rune-macros/src/to_value.rs b/crates/rune-macros/src/to_value.rs index 04b307322..2ec3380ad 100644 --- a/crates/rune-macros/src/to_value.rs +++ b/crates/rune-macros/src/to_value.rs @@ -56,25 +56,27 @@ impl Expander<'_> { let mut to_values = Vec::new(); let Tokens { - to_value, - value, + alloc, owned_tuple, result, + to_value, try_from, - vec, + value, .. } = &self.tokens; for (index, f) in unnamed.unnamed.iter().enumerate() { _ = self.cx.field_attrs(&f.attrs); let index = syn::Index::from(index); - to_values.push(quote!(#vec::try_push(&mut tuple, #to_value::to_value(self.#index)?)?)); + to_values.push( + quote!(#alloc::Vec::try_push(&mut tuple, #to_value::to_value(self.#index)?)?), + ); } let cap = unnamed.unnamed.len(); Ok(quote! { - let mut tuple = #vec::try_with_capacity(#cap)?; + let mut tuple = #alloc::Vec::try_with_capacity(#cap)?; #(#to_values;)* let tuple = <#owned_tuple as #try_from<_>>::try_from(tuple)?; #result::Ok(<#value as #try_from<_>>::try_from(tuple)?) @@ -84,12 +86,12 @@ impl Expander<'_> { /// Expand named fields. fn expand_named(&mut self, named: &syn::FieldsNamed) -> Result { let Tokens { - to_value, - value, + alloc, object, result, - string, + to_value, try_from, + value, .. } = &self.tokens; @@ -102,7 +104,7 @@ impl Expander<'_> { let name = syn::LitStr::new(&ident.to_string(), ident.span()); to_values.push(quote! { - object.insert(<#string as #try_from<_>>::try_from(#name)?, #to_value::to_value(self.#ident)?)? + object.insert(<#alloc::String as #try_from<_>>::try_from(#name)?, #to_value::to_value(self.#ident)?)? }); } diff --git a/crates/rune-modules/Cargo.toml b/crates/rune-modules/Cargo.toml index 038dafc53..81a84aa29 100644 --- a/crates/rune-modules/Cargo.toml +++ b/crates/rune-modules/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-modules" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "Native modules for Rune, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -24,36 +24,50 @@ full = [ "process", "signal", "rand", + "os_rng", + "small_rng", + "std_rng", + "thread_rng", "io", "fmt", "base64", ] -time = ["tokio", "tokio?/time"] -fs = ["tokio", "tokio?/fs"] +time = ["tokio/time"] +fs = ["tokio/fs"] http = ["reqwest"] json = ["serde_json"] process = ["tokio/process", "rune/std"] signal = ["tokio/signal"] -rand = ["nanorand"] test = [] core = [] io = [] fmt = [] macros = [] +rand = ["dep:rand"] +os_rng = ["getrandom", "rand?/os_rng"] +small_rng = ["rand?/small_rng"] +std_rng = ["rand?/std_rng"] +thread_rng = ["rand?/thread_rng"] [dependencies] base64 = { version = "0.22.0", optional = true } -reqwest = { version = "0.12.8", optional = true, default-features = false, features = [ - "rustls-tls", - "gzip", - "json", -] } tokio = { version = "1.28.1", optional = true } serde_json = { version = "1.0.96", optional = true } toml = { version = "0.8.19", optional = true } -nanorand = { version = "0.7.0", optional = true, features = ["getrandom"] } +rand = { version = "0.9.0", optional = true, default-features = false } +getrandom = { version = "0.3.0", optional = true } rune = { version = "0.14.0", path = "../rune" } +[dependencies.reqwest] +version = "0.12.8" +optional = true +default-features = false +features = [ + "rustls-tls", + "gzip", + "json", +] + [package.metadata.docs.rs] all-features = true diff --git a/crates/rune-modules/src/base64.rs b/crates/rune-modules/src/base64.rs index f6ebe77a8..c99d21672 100644 --- a/crates/rune-modules/src/base64.rs +++ b/crates/rune-modules/src/base64.rs @@ -1,11 +1,9 @@ use base64::prelude::*; use rune::alloc::fmt::TryWrite; -use rune::alloc::{String, Vec}; -use rune::runtime::Bytes; -use rune::runtime::{Formatter, VmResult}; -use rune::{vm_panic, ContextError, Module}; +use rune::alloc::{self, String, Vec}; +use rune::runtime::{Bytes, Formatter, VmError}; +use rune::{nested_try, ContextError, Module}; -#[rune::module(::base64)] /// Correct and fast [base64] encoding based on the [`base64`] crate. /// /// [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64 @@ -17,14 +15,15 @@ use rune::{vm_panic, ContextError, Module}; /// let encoded = base64::encode(b"\xFF\xEC\x20\x55\0"); /// assert_eq!(base64::decode(encoded), Ok(b"\xFF\xEC\x20\x55\0")); /// ``` +#[rune::module(::base64)] pub fn module(_stdio: bool) -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; - module.ty::()?; + m.ty::()?; - module.function_meta(decode)?; - module.function_meta(encode)?; - Ok(module) + m.function_meta(decode)?; + m.function_meta(encode)?; + Ok(m) } /// Decode a base64 String into data @@ -34,19 +33,21 @@ pub fn module(_stdio: bool) -> Result { /// ```rune /// assert_eq!(base64::decode("+uwgVQA=")?, b"\xFA\xEC\x20\x55\0"); /// ``` -#[rune::function(vm_result)] -fn decode(inp: &str) -> Result { +#[rune::function] +fn decode(inp: &str) -> alloc::Result> { // estimate the max size let decoded_size = base64::decoded_len_estimate(inp.len()); // try to allocate enough bytes let mut v = Vec::new(); - v.try_resize(decoded_size, 0).vm?; + + v.try_resize(decoded_size, 0)?; // decode - let len = BASE64_STANDARD.decode_slice(inp, &mut v)?; + let len = nested_try!(BASE64_STANDARD.decode_slice(inp, &mut v)); + v.truncate(len); - Ok(Bytes::from_vec(v)) + Ok(Ok(Bytes::from_vec(v))) } /// Encode a data into a base64 String. @@ -56,27 +57,24 @@ fn decode(inp: &str) -> Result { /// ```rune /// assert_eq!(base64::encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA="); /// ``` -#[rune::function(vm_result)] -fn encode(bytes: &[u8]) -> String { +#[rune::function] +fn encode(bytes: &[u8]) -> Result { let Some(encoded_size) = base64::encoded_len(bytes.len(), true) else { - vm_panic!("encoded input length overflows usize"); + return Err(VmError::panic("encoded input length overflows usize")); }; let mut buf = Vec::new(); - buf.try_resize(encoded_size, 0).vm?; + buf.try_resize(encoded_size, 0)?; // this should never panic if let Err(e) = BASE64_STANDARD.encode_slice(bytes, &mut buf) { - vm_panic!(e); + return Err(VmError::panic(e)); } // base64 should only return valid utf8 strings - let string = match String::from_utf8(buf) { - Ok(s) => s, - Err(e) => vm_panic!(e), - }; + let string = String::from_utf8(buf).map_err(VmError::panic)?; - string + Ok(string) } /// Errors that can occur while decoding. @@ -95,7 +93,7 @@ impl From for DecodeError { impl DecodeError { #[rune::function(instance, protocol = DISPLAY_FMT)] - fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.inner) + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) } } diff --git a/crates/rune-modules/src/http.rs b/crates/rune-modules/src/http.rs index ad0e29db5..b5007745c 100644 --- a/crates/rune-modules/src/http.rs +++ b/crates/rune-modules/src/http.rs @@ -51,10 +51,11 @@ use core::cmp::Ordering; use core::hash::Hash; +use rune::alloc; use rune::alloc::fmt::TryWrite; use rune::alloc::prelude::*; -use rune::runtime::{Bytes, Formatter, Hasher, Ref, VmResult}; -use rune::{docstring, item, Any, ContextError, Module, ToConstValue, Value}; +use rune::runtime::{Bytes, Formatter, Hasher, Ref}; +use rune::{docstring, item, nested_try, Any, ContextError, Module, ToConstValue, Value}; /// A simple HTTP module for Rune. /// @@ -67,1370 +68,1305 @@ use rune::{docstring, item, Any, ContextError, Module, ToConstValue, Value}; /// ``` #[rune::module(::http)] pub fn module(_stdio: bool) -> Result { - let mut module = Module::from_meta(self::module_meta)?; - - module.function_meta(get)?; - - module.ty::()?; - module.function_meta(Client::new__meta)?; - module.function_meta(Client::get__meta)?; - module.function_meta(Client::post__meta)?; - module.function_meta(Client::put__meta)?; - module.function_meta(Client::delete__meta)?; - module.function_meta(Client::head__meta)?; - - module.ty::()?; - module.function_meta(Response::text__meta)?; - module.function_meta(Response::json__meta)?; - module.function_meta(Response::bytes__meta)?; - module.function_meta(Response::status__meta)?; - module.function_meta(Response::version__meta)?; - module.function_meta(Response::content_length__meta)?; - - module.ty::()?; - module.function_meta(RequestBuilder::send__meta)?; - module.function_meta(RequestBuilder::header__meta)?; - module.function_meta(RequestBuilder::basic_auth__meta)?; - module.function_meta(RequestBuilder::bearer_auth__meta)?; - module.function_meta(RequestBuilder::fetch_mode_no_cors__meta)?; - module.function_meta(RequestBuilder::body_bytes__meta)?; - - module.ty::()?; - module.function_meta(StatusCode::as_u16__meta)?; - module.function_meta(StatusCode::as_str__meta)?; - module.function_meta(StatusCode::canonical_reason__meta)?; - module.function_meta(StatusCode::is_informational__meta)?; - module.function_meta(StatusCode::is_success__meta)?; - module.function_meta(StatusCode::is_redirection__meta)?; - module.function_meta(StatusCode::is_client_error__meta)?; - module.function_meta(StatusCode::is_server_error__meta)?; - module.function_meta(StatusCode::partial_eq__meta)?; - module.implement_trait::(item!(::std::cmp::PartialEq))?; - module.function_meta(StatusCode::eq__meta)?; - module.implement_trait::(item!(::std::cmp::Eq))?; - module.function_meta(StatusCode::partial_cmp__meta)?; - module.implement_trait::(item!(::std::cmp::PartialOrd))?; - module.function_meta(StatusCode::cmp__meta)?; - module.implement_trait::(item!(::std::cmp::Ord))?; - module.function_meta(StatusCode::hash__meta)?; - module.function_meta(StatusCode::debug_fmt__meta)?; - module.function_meta(StatusCode::display_fmt__meta)?; - - module - .constant( - "CONTINUE", - StatusCode { - inner: reqwest::StatusCode::CONTINUE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Continue - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::CONTINUE; - /// ``` - })?; - - module - .constant( - "SWITCHING_PROTOCOLS", - StatusCode { - inner: reqwest::StatusCode::SWITCHING_PROTOCOLS, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Switching Protocols - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::SWITCHING_PROTOCOLS; - /// ``` - })?; - - module - .constant( - "PROCESSING", - StatusCode { - inner: reqwest::StatusCode::PROCESSING, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Processing - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PROCESSING; - /// ``` - })?; - - module - .constant( - "OK", - StatusCode { - inner: reqwest::StatusCode::OK, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: OK - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::OK; - /// ``` - })?; - - module - .constant( - "CREATED", - StatusCode { - inner: reqwest::StatusCode::CREATED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Created - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::CREATED; - /// ``` - })?; - - module - .constant( - "ACCEPTED", - StatusCode { - inner: reqwest::StatusCode::ACCEPTED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Accepted - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::ACCEPTED; - /// ``` - })?; - - module - .constant( - "NON_AUTHORITATIVE_INFORMATION", - StatusCode { - inner: reqwest::StatusCode::NON_AUTHORITATIVE_INFORMATION, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Non Authoritative Information - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NON_AUTHORITATIVE_INFORMATION; - /// ``` - })?; - - module - .constant( - "NO_CONTENT", - StatusCode { - inner: reqwest::StatusCode::NO_CONTENT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: No Content - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NO_CONTENT; - /// ``` - })?; - - module - .constant( - "RESET_CONTENT", - StatusCode { - inner: reqwest::StatusCode::RESET_CONTENT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Reset Content - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::RESET_CONTENT; - /// ``` - })?; - - module - .constant( - "PARTIAL_CONTENT", - StatusCode { - inner: reqwest::StatusCode::PARTIAL_CONTENT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Partial Content - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PARTIAL_CONTENT; - /// ``` - })?; - - module - .constant( - "MULTI_STATUS", - StatusCode { - inner: reqwest::StatusCode::MULTI_STATUS, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Multi-Status - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::MULTI_STATUS; - /// ``` - })?; - - module - .constant( - "ALREADY_REPORTED", - StatusCode { - inner: reqwest::StatusCode::ALREADY_REPORTED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Already Reported - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::ALREADY_REPORTED; - /// ``` - })?; - - module - .constant( - "IM_USED", - StatusCode { - inner: reqwest::StatusCode::IM_USED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: IM Used - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::IM_USED; - /// ``` - })?; - - module - .constant( - "MULTIPLE_CHOICES", - StatusCode { - inner: reqwest::StatusCode::MULTIPLE_CHOICES, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Multiple Choices - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::MULTIPLE_CHOICES; - /// ``` - })?; - - module - .constant( - "MOVED_PERMANENTLY", - StatusCode { - inner: reqwest::StatusCode::MOVED_PERMANENTLY, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Moved Permanently - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::MOVED_PERMANENTLY; - /// ``` - })?; - - module - .constant( - "FOUND", - StatusCode { - inner: reqwest::StatusCode::FOUND, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Found - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::FOUND; - /// ``` - })?; - - module - .constant( - "SEE_OTHER", - StatusCode { - inner: reqwest::StatusCode::SEE_OTHER, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: See Other - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::SEE_OTHER; - /// ``` - })?; - - module - .constant( - "NOT_MODIFIED", - StatusCode { - inner: reqwest::StatusCode::NOT_MODIFIED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Not Modified - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NOT_MODIFIED; - /// ``` - })?; - - module - .constant( - "USE_PROXY", - StatusCode { - inner: reqwest::StatusCode::USE_PROXY, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Use Proxy - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::USE_PROXY; - /// ``` - })?; - - module - .constant( - "TEMPORARY_REDIRECT", - StatusCode { - inner: reqwest::StatusCode::TEMPORARY_REDIRECT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Temporary Redirect - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::TEMPORARY_REDIRECT; - /// ``` - })?; - - module - .constant( - "PERMANENT_REDIRECT", - StatusCode { - inner: reqwest::StatusCode::PERMANENT_REDIRECT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Permanent Redirect - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PERMANENT_REDIRECT; - /// ``` - })?; - - module - .constant( - "BAD_REQUEST", - StatusCode { - inner: reqwest::StatusCode::BAD_REQUEST, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Bad Request - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::BAD_REQUEST; - /// ``` - })?; - - module - .constant( - "UNAUTHORIZED", - StatusCode { - inner: reqwest::StatusCode::UNAUTHORIZED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Unauthorized - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::UNAUTHORIZED; - /// ``` - })?; - - module - .constant( - "PAYMENT_REQUIRED", - StatusCode { - inner: reqwest::StatusCode::PAYMENT_REQUIRED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Payment Required - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PAYMENT_REQUIRED; - /// ``` - })?; - - module - .constant( - "FORBIDDEN", - StatusCode { - inner: reqwest::StatusCode::FORBIDDEN, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Forbidden - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::FORBIDDEN; - /// ``` - })?; - - module - .constant( - "NOT_FOUND", - StatusCode { - inner: reqwest::StatusCode::NOT_FOUND, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Not Found - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NOT_FOUND; - /// ``` - })?; - - module - .constant( - "METHOD_NOT_ALLOWED", - StatusCode { - inner: reqwest::StatusCode::METHOD_NOT_ALLOWED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Method Not Allowed - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::METHOD_NOT_ALLOWED; - /// ``` - })?; - - module - .constant( - "NOT_ACCEPTABLE", - StatusCode { - inner: reqwest::StatusCode::NOT_ACCEPTABLE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Not Acceptable - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NOT_ACCEPTABLE; - /// ``` - })?; - - module - .constant( - "PROXY_AUTHENTICATION_REQUIRED", - StatusCode { - inner: reqwest::StatusCode::PROXY_AUTHENTICATION_REQUIRED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Proxy Authentication Required - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PROXY_AUTHENTICATION_REQUIRED; - /// ``` - })?; - - module - .constant( - "REQUEST_TIMEOUT", - StatusCode { - inner: reqwest::StatusCode::REQUEST_TIMEOUT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Request Timeout - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::REQUEST_TIMEOUT; - /// ``` - })?; - - module - .constant( - "CONFLICT", - StatusCode { - inner: reqwest::StatusCode::CONFLICT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Conflict - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::CONFLICT; - /// ``` - })?; - - module - .constant( - "GONE", - StatusCode { - inner: reqwest::StatusCode::GONE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Gone - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::GONE; - /// ``` - })?; - - module - .constant( - "LENGTH_REQUIRED", - StatusCode { - inner: reqwest::StatusCode::LENGTH_REQUIRED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Length Required - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::LENGTH_REQUIRED; - /// ``` - })?; - - module - .constant( - "PRECONDITION_FAILED", - StatusCode { - inner: reqwest::StatusCode::PRECONDITION_FAILED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Precondition Failed - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PRECONDITION_FAILED; - /// ``` - })?; - - module - .constant( - "PAYLOAD_TOO_LARGE", - StatusCode { - inner: reqwest::StatusCode::PAYLOAD_TOO_LARGE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Payload Too Large - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PAYLOAD_TOO_LARGE; - /// ``` - })?; - - module - .constant( - "URI_TOO_LONG", - StatusCode { - inner: reqwest::StatusCode::URI_TOO_LONG, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: URI Too Long - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::URI_TOO_LONG; - /// ``` - })?; - - module - .constant( - "UNSUPPORTED_MEDIA_TYPE", - StatusCode { - inner: reqwest::StatusCode::UNSUPPORTED_MEDIA_TYPE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Unsupported Media Type - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::UNSUPPORTED_MEDIA_TYPE; - /// ``` - })?; - - module - .constant( - "RANGE_NOT_SATISFIABLE", - StatusCode { - inner: reqwest::StatusCode::RANGE_NOT_SATISFIABLE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Range Not Satisfiable - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::RANGE_NOT_SATISFIABLE; - /// ``` - })?; - - module - .constant( - "EXPECTATION_FAILED", - StatusCode { - inner: reqwest::StatusCode::EXPECTATION_FAILED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Expectation Failed - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::EXPECTATION_FAILED; - /// ``` - })?; - - module - .constant( - "IM_A_TEAPOT", - StatusCode { - inner: reqwest::StatusCode::IM_A_TEAPOT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: I'm a teapot - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::IM_A_TEAPOT; - /// ``` - })?; - - module - .constant( - "MISDIRECTED_REQUEST", - StatusCode { - inner: reqwest::StatusCode::MISDIRECTED_REQUEST, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Misdirected Request - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::MISDIRECTED_REQUEST; - /// ``` - })?; - - module - .constant( - "UNPROCESSABLE_ENTITY", - StatusCode { - inner: reqwest::StatusCode::UNPROCESSABLE_ENTITY, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Unprocessable Entity - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::UNPROCESSABLE_ENTITY; - /// ``` - })?; - - module - .constant( - "LOCKED", - StatusCode { - inner: reqwest::StatusCode::LOCKED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Locked - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::LOCKED; - /// ``` - })?; - - module - .constant( - "FAILED_DEPENDENCY", - StatusCode { - inner: reqwest::StatusCode::FAILED_DEPENDENCY, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Failed Dependency - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::FAILED_DEPENDENCY; - /// ``` - })?; - - module - .constant( - "UPGRADE_REQUIRED", - StatusCode { - inner: reqwest::StatusCode::UPGRADE_REQUIRED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Upgrade Required - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::UPGRADE_REQUIRED; - /// ``` - })?; - - module - .constant( - "PRECONDITION_REQUIRED", - StatusCode { - inner: reqwest::StatusCode::PRECONDITION_REQUIRED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Precondition Required - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::PRECONDITION_REQUIRED; - /// ``` - })?; - - module - .constant( - "TOO_MANY_REQUESTS", - StatusCode { - inner: reqwest::StatusCode::TOO_MANY_REQUESTS, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Too Many Requests - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::TOO_MANY_REQUESTS; - /// ``` - })?; - - module - .constant( - "REQUEST_HEADER_FIELDS_TOO_LARGE", - StatusCode { - inner: reqwest::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Request Header Fields Too Large - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE; - /// ``` - })?; - - module - .constant( - "UNAVAILABLE_FOR_LEGAL_REASONS", - StatusCode { - inner: reqwest::StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Unavailable For Legal Reasons - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS; - /// ``` - })?; - - module - .constant( - "INTERNAL_SERVER_ERROR", - StatusCode { - inner: reqwest::StatusCode::INTERNAL_SERVER_ERROR, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Internal Server Error - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::INTERNAL_SERVER_ERROR; - /// ``` - })?; - - module - .constant( - "NOT_IMPLEMENTED", - StatusCode { - inner: reqwest::StatusCode::NOT_IMPLEMENTED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Not Implemented - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NOT_IMPLEMENTED; - /// ``` - })?; - - module - .constant( - "BAD_GATEWAY", - StatusCode { - inner: reqwest::StatusCode::BAD_GATEWAY, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Bad Gateway - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::BAD_GATEWAY; - /// ``` - })?; - - module - .constant( - "SERVICE_UNAVAILABLE", - StatusCode { - inner: reqwest::StatusCode::SERVICE_UNAVAILABLE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Service Unavailable - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::SERVICE_UNAVAILABLE; - /// ``` - })?; - - module - .constant( - "GATEWAY_TIMEOUT", - StatusCode { - inner: reqwest::StatusCode::GATEWAY_TIMEOUT, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Gateway Timeout - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::GATEWAY_TIMEOUT; - /// ``` - })?; - - module - .constant( - "HTTP_VERSION_NOT_SUPPORTED", - StatusCode { - inner: reqwest::StatusCode::HTTP_VERSION_NOT_SUPPORTED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: HTTP Version Not Supported - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::HTTP_VERSION_NOT_SUPPORTED; - /// ``` - })?; - - module - .constant( - "VARIANT_ALSO_NEGOTIATES", - StatusCode { - inner: reqwest::StatusCode::VARIANT_ALSO_NEGOTIATES, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Variant Also Negotiates - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::VARIANT_ALSO_NEGOTIATES; - /// ``` - })?; - - module - .constant( - "INSUFFICIENT_STORAGE", - StatusCode { - inner: reqwest::StatusCode::INSUFFICIENT_STORAGE, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Insufficient Storage - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::INSUFFICIENT_STORAGE; - /// ``` - })?; - - module - .constant( - "LOOP_DETECTED", - StatusCode { - inner: reqwest::StatusCode::LOOP_DETECTED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Loop Detected - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::LOOP_DETECTED; - /// ``` - })?; - - module - .constant( - "NOT_EXTENDED", - StatusCode { - inner: reqwest::StatusCode::NOT_EXTENDED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Not Extended - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NOT_EXTENDED; - /// ``` - })?; - - module - .constant( - "NETWORK_AUTHENTICATION_REQUIRED", - StatusCode { - inner: reqwest::StatusCode::NETWORK_AUTHENTICATION_REQUIRED, - }, - ) - .build_associated::()? - .docs(docstring! { - /// Status Code: Network Authentication Required - /// - /// # Examples - /// - /// ```rune - /// use http::StatusCode; - /// - /// let status_code = StatusCode::NETWORK_AUTHENTICATION_REQUIRED; - /// ``` - })?; - - module.ty::()?; - module.function_meta(Version::partial_eq__meta)?; - module.implement_trait::(item!(::std::cmp::PartialEq))?; - module.function_meta(Version::eq__meta)?; - module.implement_trait::(item!(::std::cmp::Eq))?; - module.function_meta(Version::partial_cmp__meta)?; - module.implement_trait::(item!(::std::cmp::PartialOrd))?; - module.function_meta(Version::cmp__meta)?; - module.implement_trait::(item!(::std::cmp::Ord))?; - module.function_meta(Version::hash__meta)?; - module.function_meta(Version::debug_fmt__meta)?; - - module - .constant( - "HTTP_09", - Version { - inner: reqwest::Version::HTTP_09, - }, - ) - .build_associated::()? - .docs(docstring! { - /// The `HTTP/0.9` version. - /// - /// # Examples - /// - /// ```rune,no_run - /// use http::Version; - /// - /// let version = Version::HTTP_09; - /// ``` - })?; - - module - .constant( - "HTTP_10", - Version { - inner: reqwest::Version::HTTP_10, - }, - ) - .build_associated::()? - .docs(docstring! { - /// The `HTTP/1.0` version. - /// - /// # Examples - /// - /// ```rune,no_run - /// use http::Version; - /// - /// let version = Version::HTTP_10; - /// ``` - })?; - - module - .constant( - "HTTP_11", - Version { - inner: reqwest::Version::HTTP_11, - }, - ) - .build_associated::()? - .docs(docstring! { - /// The `HTTP/1.1` version. - /// - /// # Examples - /// - /// ```rune,no_run - /// use http::Version; - /// - /// let version = Version::HTTP_11; - /// ``` - })?; - - module - .constant( - "HTTP_2", - Version { - inner: reqwest::Version::HTTP_2, - }, - ) - .build_associated::()? - .docs(docstring! { - /// The `HTTP/2.0` version. - /// - /// # Examples - /// - /// ```rune,no_run - /// use http::Version; - /// - /// let version = Version::HTTP_2; - /// ``` - })?; - - module - .constant( - "HTTP_3", - Version { - inner: reqwest::Version::HTTP_3, - }, - ) - .build_associated::()? - .docs(docstring! { - /// The `HTTP/3.0` version. - /// - /// # Examples - /// - /// ```rune,no_run - /// use http::Version; - /// - /// let version = Version::HTTP_3; - /// ``` - })?; - - module.ty::()?; - module.function_meta(Error::display_fmt__meta)?; - Ok(module) + let mut m = Module::from_meta(self::module__meta)?; + + m.function_meta(get)?; + + m.ty::()?; + m.function_meta(Client::new__meta)?; + m.function_meta(Client::get__meta)?; + m.function_meta(Client::post__meta)?; + m.function_meta(Client::put__meta)?; + m.function_meta(Client::delete__meta)?; + m.function_meta(Client::head__meta)?; + + m.ty::()?; + m.function_meta(Response::text__meta)?; + m.function_meta(Response::json__meta)?; + m.function_meta(Response::bytes__meta)?; + m.function_meta(Response::status__meta)?; + m.function_meta(Response::version__meta)?; + m.function_meta(Response::content_length__meta)?; + + m.ty::()?; + m.function_meta(RequestBuilder::send__meta)?; + m.function_meta(RequestBuilder::header__meta)?; + m.function_meta(RequestBuilder::basic_auth__meta)?; + m.function_meta(RequestBuilder::bearer_auth__meta)?; + m.function_meta(RequestBuilder::fetch_mode_no_cors__meta)?; + m.function_meta(RequestBuilder::body_bytes__meta)?; + + m.ty::()?; + m.function_meta(StatusCode::as_u16__meta)?; + m.function_meta(StatusCode::as_str__meta)?; + m.function_meta(StatusCode::canonical_reason__meta)?; + m.function_meta(StatusCode::is_informational__meta)?; + m.function_meta(StatusCode::is_success__meta)?; + m.function_meta(StatusCode::is_redirection__meta)?; + m.function_meta(StatusCode::is_client_error__meta)?; + m.function_meta(StatusCode::is_server_error__meta)?; + m.function_meta(StatusCode::partial_eq__meta)?; + m.implement_trait::(item!(::std::cmp::PartialEq))?; + m.function_meta(StatusCode::eq__meta)?; + m.implement_trait::(item!(::std::cmp::Eq))?; + m.function_meta(StatusCode::partial_cmp__meta)?; + m.implement_trait::(item!(::std::cmp::PartialOrd))?; + m.function_meta(StatusCode::cmp__meta)?; + m.implement_trait::(item!(::std::cmp::Ord))?; + m.function_meta(StatusCode::hash__meta)?; + m.function_meta(StatusCode::debug_fmt__meta)?; + m.function_meta(StatusCode::display_fmt__meta)?; + + m.constant( + "CONTINUE", + StatusCode { + inner: reqwest::StatusCode::CONTINUE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Continue + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::CONTINUE; + /// ``` + })?; + + m.constant( + "SWITCHING_PROTOCOLS", + StatusCode { + inner: reqwest::StatusCode::SWITCHING_PROTOCOLS, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Switching Protocols + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::SWITCHING_PROTOCOLS; + /// ``` + })?; + + m.constant( + "PROCESSING", + StatusCode { + inner: reqwest::StatusCode::PROCESSING, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Processing + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PROCESSING; + /// ``` + })?; + + m.constant( + "OK", + StatusCode { + inner: reqwest::StatusCode::OK, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: OK + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::OK; + /// ``` + })?; + + m.constant( + "CREATED", + StatusCode { + inner: reqwest::StatusCode::CREATED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Created + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::CREATED; + /// ``` + })?; + + m.constant( + "ACCEPTED", + StatusCode { + inner: reqwest::StatusCode::ACCEPTED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Accepted + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::ACCEPTED; + /// ``` + })?; + + m.constant( + "NON_AUTHORITATIVE_INFORMATION", + StatusCode { + inner: reqwest::StatusCode::NON_AUTHORITATIVE_INFORMATION, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Non Authoritative Information + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NON_AUTHORITATIVE_INFORMATION; + /// ``` + })?; + + m.constant( + "NO_CONTENT", + StatusCode { + inner: reqwest::StatusCode::NO_CONTENT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: No Content + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NO_CONTENT; + /// ``` + })?; + + m.constant( + "RESET_CONTENT", + StatusCode { + inner: reqwest::StatusCode::RESET_CONTENT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Reset Content + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::RESET_CONTENT; + /// ``` + })?; + + m.constant( + "PARTIAL_CONTENT", + StatusCode { + inner: reqwest::StatusCode::PARTIAL_CONTENT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Partial Content + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PARTIAL_CONTENT; + /// ``` + })?; + + m.constant( + "MULTI_STATUS", + StatusCode { + inner: reqwest::StatusCode::MULTI_STATUS, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Multi-Status + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::MULTI_STATUS; + /// ``` + })?; + + m.constant( + "ALREADY_REPORTED", + StatusCode { + inner: reqwest::StatusCode::ALREADY_REPORTED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Already Reported + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::ALREADY_REPORTED; + /// ``` + })?; + + m.constant( + "IM_USED", + StatusCode { + inner: reqwest::StatusCode::IM_USED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: IM Used + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::IM_USED; + /// ``` + })?; + + m.constant( + "MULTIPLE_CHOICES", + StatusCode { + inner: reqwest::StatusCode::MULTIPLE_CHOICES, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Multiple Choices + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::MULTIPLE_CHOICES; + /// ``` + })?; + + m.constant( + "MOVED_PERMANENTLY", + StatusCode { + inner: reqwest::StatusCode::MOVED_PERMANENTLY, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Moved Permanently + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::MOVED_PERMANENTLY; + /// ``` + })?; + + m.constant( + "FOUND", + StatusCode { + inner: reqwest::StatusCode::FOUND, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Found + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::FOUND; + /// ``` + })?; + + m.constant( + "SEE_OTHER", + StatusCode { + inner: reqwest::StatusCode::SEE_OTHER, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: See Other + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::SEE_OTHER; + /// ``` + })?; + + m.constant( + "NOT_MODIFIED", + StatusCode { + inner: reqwest::StatusCode::NOT_MODIFIED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Not Modified + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NOT_MODIFIED; + /// ``` + })?; + + m.constant( + "USE_PROXY", + StatusCode { + inner: reqwest::StatusCode::USE_PROXY, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Use Proxy + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::USE_PROXY; + /// ``` + })?; + + m.constant( + "TEMPORARY_REDIRECT", + StatusCode { + inner: reqwest::StatusCode::TEMPORARY_REDIRECT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Temporary Redirect + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::TEMPORARY_REDIRECT; + /// ``` + })?; + + m.constant( + "PERMANENT_REDIRECT", + StatusCode { + inner: reqwest::StatusCode::PERMANENT_REDIRECT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Permanent Redirect + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PERMANENT_REDIRECT; + /// ``` + })?; + + m.constant( + "BAD_REQUEST", + StatusCode { + inner: reqwest::StatusCode::BAD_REQUEST, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Bad Request + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::BAD_REQUEST; + /// ``` + })?; + + m.constant( + "UNAUTHORIZED", + StatusCode { + inner: reqwest::StatusCode::UNAUTHORIZED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Unauthorized + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::UNAUTHORIZED; + /// ``` + })?; + + m.constant( + "PAYMENT_REQUIRED", + StatusCode { + inner: reqwest::StatusCode::PAYMENT_REQUIRED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Payment Required + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PAYMENT_REQUIRED; + /// ``` + })?; + + m.constant( + "FORBIDDEN", + StatusCode { + inner: reqwest::StatusCode::FORBIDDEN, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Forbidden + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::FORBIDDEN; + /// ``` + })?; + + m.constant( + "NOT_FOUND", + StatusCode { + inner: reqwest::StatusCode::NOT_FOUND, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Not Found + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NOT_FOUND; + /// ``` + })?; + + m.constant( + "METHOD_NOT_ALLOWED", + StatusCode { + inner: reqwest::StatusCode::METHOD_NOT_ALLOWED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Method Not Allowed + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::METHOD_NOT_ALLOWED; + /// ``` + })?; + + m.constant( + "NOT_ACCEPTABLE", + StatusCode { + inner: reqwest::StatusCode::NOT_ACCEPTABLE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Not Acceptable + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NOT_ACCEPTABLE; + /// ``` + })?; + + m.constant( + "PROXY_AUTHENTICATION_REQUIRED", + StatusCode { + inner: reqwest::StatusCode::PROXY_AUTHENTICATION_REQUIRED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Proxy Authentication Required + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PROXY_AUTHENTICATION_REQUIRED; + /// ``` + })?; + + m.constant( + "REQUEST_TIMEOUT", + StatusCode { + inner: reqwest::StatusCode::REQUEST_TIMEOUT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Request Timeout + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::REQUEST_TIMEOUT; + /// ``` + })?; + + m.constant( + "CONFLICT", + StatusCode { + inner: reqwest::StatusCode::CONFLICT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Conflict + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::CONFLICT; + /// ``` + })?; + + m.constant( + "GONE", + StatusCode { + inner: reqwest::StatusCode::GONE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Gone + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::GONE; + /// ``` + })?; + + m.constant( + "LENGTH_REQUIRED", + StatusCode { + inner: reqwest::StatusCode::LENGTH_REQUIRED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Length Required + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::LENGTH_REQUIRED; + /// ``` + })?; + + m.constant( + "PRECONDITION_FAILED", + StatusCode { + inner: reqwest::StatusCode::PRECONDITION_FAILED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Precondition Failed + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PRECONDITION_FAILED; + /// ``` + })?; + + m.constant( + "PAYLOAD_TOO_LARGE", + StatusCode { + inner: reqwest::StatusCode::PAYLOAD_TOO_LARGE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Payload Too Large + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PAYLOAD_TOO_LARGE; + /// ``` + })?; + + m.constant( + "URI_TOO_LONG", + StatusCode { + inner: reqwest::StatusCode::URI_TOO_LONG, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: URI Too Long + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::URI_TOO_LONG; + /// ``` + })?; + + m.constant( + "UNSUPPORTED_MEDIA_TYPE", + StatusCode { + inner: reqwest::StatusCode::UNSUPPORTED_MEDIA_TYPE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Unsupported Media Type + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::UNSUPPORTED_MEDIA_TYPE; + /// ``` + })?; + + m.constant( + "RANGE_NOT_SATISFIABLE", + StatusCode { + inner: reqwest::StatusCode::RANGE_NOT_SATISFIABLE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Range Not Satisfiable + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::RANGE_NOT_SATISFIABLE; + /// ``` + })?; + + m.constant( + "EXPECTATION_FAILED", + StatusCode { + inner: reqwest::StatusCode::EXPECTATION_FAILED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Expectation Failed + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::EXPECTATION_FAILED; + /// ``` + })?; + + m.constant( + "IM_A_TEAPOT", + StatusCode { + inner: reqwest::StatusCode::IM_A_TEAPOT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: I'm a teapot + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::IM_A_TEAPOT; + /// ``` + })?; + + m.constant( + "MISDIRECTED_REQUEST", + StatusCode { + inner: reqwest::StatusCode::MISDIRECTED_REQUEST, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Misdirected Request + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::MISDIRECTED_REQUEST; + /// ``` + })?; + + m.constant( + "UNPROCESSABLE_ENTITY", + StatusCode { + inner: reqwest::StatusCode::UNPROCESSABLE_ENTITY, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Unprocessable Entity + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::UNPROCESSABLE_ENTITY; + /// ``` + })?; + + m.constant( + "LOCKED", + StatusCode { + inner: reqwest::StatusCode::LOCKED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Locked + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::LOCKED; + /// ``` + })?; + + m.constant( + "FAILED_DEPENDENCY", + StatusCode { + inner: reqwest::StatusCode::FAILED_DEPENDENCY, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Failed Dependency + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::FAILED_DEPENDENCY; + /// ``` + })?; + + m.constant( + "UPGRADE_REQUIRED", + StatusCode { + inner: reqwest::StatusCode::UPGRADE_REQUIRED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Upgrade Required + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::UPGRADE_REQUIRED; + /// ``` + })?; + + m.constant( + "PRECONDITION_REQUIRED", + StatusCode { + inner: reqwest::StatusCode::PRECONDITION_REQUIRED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Precondition Required + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::PRECONDITION_REQUIRED; + /// ``` + })?; + + m.constant( + "TOO_MANY_REQUESTS", + StatusCode { + inner: reqwest::StatusCode::TOO_MANY_REQUESTS, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Too Many Requests + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::TOO_MANY_REQUESTS; + /// ``` + })?; + + m.constant( + "REQUEST_HEADER_FIELDS_TOO_LARGE", + StatusCode { + inner: reqwest::StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Request Header Fields Too Large + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE; + /// ``` + })?; + + m.constant( + "UNAVAILABLE_FOR_LEGAL_REASONS", + StatusCode { + inner: reqwest::StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Unavailable For Legal Reasons + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS; + /// ``` + })?; + + m.constant( + "INTERNAL_SERVER_ERROR", + StatusCode { + inner: reqwest::StatusCode::INTERNAL_SERVER_ERROR, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Internal Server Error + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::INTERNAL_SERVER_ERROR; + /// ``` + })?; + + m.constant( + "NOT_IMPLEMENTED", + StatusCode { + inner: reqwest::StatusCode::NOT_IMPLEMENTED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Not Implemented + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NOT_IMPLEMENTED; + /// ``` + })?; + + m.constant( + "BAD_GATEWAY", + StatusCode { + inner: reqwest::StatusCode::BAD_GATEWAY, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Bad Gateway + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::BAD_GATEWAY; + /// ``` + })?; + + m.constant( + "SERVICE_UNAVAILABLE", + StatusCode { + inner: reqwest::StatusCode::SERVICE_UNAVAILABLE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Service Unavailable + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::SERVICE_UNAVAILABLE; + /// ``` + })?; + + m.constant( + "GATEWAY_TIMEOUT", + StatusCode { + inner: reqwest::StatusCode::GATEWAY_TIMEOUT, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Gateway Timeout + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::GATEWAY_TIMEOUT; + /// ``` + })?; + + m.constant( + "HTTP_VERSION_NOT_SUPPORTED", + StatusCode { + inner: reqwest::StatusCode::HTTP_VERSION_NOT_SUPPORTED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: HTTP Version Not Supported + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::HTTP_VERSION_NOT_SUPPORTED; + /// ``` + })?; + + m.constant( + "VARIANT_ALSO_NEGOTIATES", + StatusCode { + inner: reqwest::StatusCode::VARIANT_ALSO_NEGOTIATES, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Variant Also Negotiates + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::VARIANT_ALSO_NEGOTIATES; + /// ``` + })?; + + m.constant( + "INSUFFICIENT_STORAGE", + StatusCode { + inner: reqwest::StatusCode::INSUFFICIENT_STORAGE, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Insufficient Storage + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::INSUFFICIENT_STORAGE; + /// ``` + })?; + + m.constant( + "LOOP_DETECTED", + StatusCode { + inner: reqwest::StatusCode::LOOP_DETECTED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Loop Detected + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::LOOP_DETECTED; + /// ``` + })?; + + m.constant( + "NOT_EXTENDED", + StatusCode { + inner: reqwest::StatusCode::NOT_EXTENDED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Not Extended + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NOT_EXTENDED; + /// ``` + })?; + + m.constant( + "NETWORK_AUTHENTICATION_REQUIRED", + StatusCode { + inner: reqwest::StatusCode::NETWORK_AUTHENTICATION_REQUIRED, + }, + ) + .build_associated::()? + .docs(docstring! { + /// Status Code: Network Authentication Required + /// + /// # Examples + /// + /// ```rune + /// use http::StatusCode; + /// + /// let status_code = StatusCode::NETWORK_AUTHENTICATION_REQUIRED; + /// ``` + })?; + + m.ty::()?; + m.function_meta(Version::partial_eq__meta)?; + m.implement_trait::(item!(::std::cmp::PartialEq))?; + m.function_meta(Version::eq__meta)?; + m.implement_trait::(item!(::std::cmp::Eq))?; + m.function_meta(Version::partial_cmp__meta)?; + m.implement_trait::(item!(::std::cmp::PartialOrd))?; + m.function_meta(Version::cmp__meta)?; + m.implement_trait::(item!(::std::cmp::Ord))?; + m.function_meta(Version::hash__meta)?; + m.function_meta(Version::debug_fmt__meta)?; + + m.constant( + "HTTP_09", + Version { + inner: reqwest::Version::HTTP_09, + }, + ) + .build_associated::()? + .docs(docstring! { + /// The `HTTP/0.9` version. + /// + /// # Examples + /// + /// ```rune,no_run + /// use http::Version; + /// + /// let version = Version::HTTP_09; + /// ``` + })?; + + m.constant( + "HTTP_10", + Version { + inner: reqwest::Version::HTTP_10, + }, + ) + .build_associated::()? + .docs(docstring! { + /// The `HTTP/1.0` version. + /// + /// # Examples + /// + /// ```rune,no_run + /// use http::Version; + /// + /// let version = Version::HTTP_10; + /// ``` + })?; + + m.constant( + "HTTP_11", + Version { + inner: reqwest::Version::HTTP_11, + }, + ) + .build_associated::()? + .docs(docstring! { + /// The `HTTP/1.1` version. + /// + /// # Examples + /// + /// ```rune,no_run + /// use http::Version; + /// + /// let version = Version::HTTP_11; + /// ``` + })?; + + m.constant( + "HTTP_2", + Version { + inner: reqwest::Version::HTTP_2, + }, + ) + .build_associated::()? + .docs(docstring! { + /// The `HTTP/2.0` version. + /// + /// # Examples + /// + /// ```rune,no_run + /// use http::Version; + /// + /// let version = Version::HTTP_2; + /// ``` + })?; + + m.constant( + "HTTP_3", + Version { + inner: reqwest::Version::HTTP_3, + }, + ) + .build_associated::()? + .docs(docstring! { + /// The `HTTP/3.0` version. + /// + /// # Examples + /// + /// ```rune,no_run + /// use http::Version; + /// + /// let version = Version::HTTP_3; + /// ``` + })?; + + m.ty::()?; + m.function_meta(Error::display_fmt__meta)?; + Ok(m) } /// An error returned by methods in the `http` module. @@ -1441,6 +1377,7 @@ pub struct Error { } impl From for Error { + #[inline] fn from(inner: reqwest::Error) -> Self { Self { inner } } @@ -1449,8 +1386,8 @@ impl From for Error { impl Error { /// Write a display representation the error. #[rune::function(keep, instance, protocol = DISPLAY_FMT)] - fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.inner) + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) } } @@ -1481,12 +1418,12 @@ impl Response { /// /// let response = response.text().await?; /// ``` - #[rune::function(keep, vm_result)] - async fn text(self) -> Result { - let text = self.response.text().await?; + #[rune::function(keep)] + async fn text(self) -> alloc::Result> { + let text = nested_try!(self.response.text().await); // NB: We simply take ownership of the string here, raising an error in // case we reach a memory limit. - Ok(String::try_from(text).vm?) + Ok(Ok(String::try_from(text)?)) } /// Get the response as a Rune value decoded from JSON. @@ -1517,16 +1454,16 @@ impl Response { /// /// let response = response.bytes().await?; /// ``` - #[rune::function(keep, vm_result)] - async fn bytes(mut self) -> Result { + #[rune::function(keep)] + async fn bytes(mut self) -> alloc::Result> { let len = self.response.content_length().unwrap_or(0) as usize; - let mut bytes = Vec::try_with_capacity(len).vm?; + let mut bytes = Vec::try_with_capacity(len)?; - while let Some(chunk) = self.response.chunk().await? { - bytes.try_extend_from_slice(chunk.as_ref()).vm?; + while let Some(chunk) = nested_try!(self.response.chunk().await) { + bytes.try_extend_from_slice(chunk.as_ref())?; } - Ok(Bytes::from_vec(bytes)) + Ok(Ok(Bytes::from_vec(bytes))) } /// Get the status code of the response. @@ -1603,10 +1540,10 @@ impl StatusCode { /// let status = StatusCode::OK; /// assert_eq!(status.as_str(), "200"); /// ``` - #[rune::function(keep, instance, vm_result)] + #[rune::function(keep, instance)] #[inline] - fn as_str(&self) -> String { - self.inner.as_str().try_to_owned().vm? + fn as_str(&self) -> alloc::Result { + self.inner.as_str().try_to_owned() } /// Get the standardised `reason-phrase` for this status code. @@ -1801,8 +1738,8 @@ impl StatusCode { /// println!("{not_found:?}"); /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } /// Write a display representation of the status code. @@ -1817,8 +1754,8 @@ impl StatusCode { /// println!("{not_found}"); /// ``` #[rune::function(keep, instance, protocol = DISPLAY_FMT)] - fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{}", self.inner) + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) } } @@ -1984,8 +1921,8 @@ impl Version { /// println!("{:?}", http2); /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } } diff --git a/crates/rune-modules/src/json.rs b/crates/rune-modules/src/json.rs index 816f8cbf2..7861688a4 100644 --- a/crates/rune-modules/src/json.rs +++ b/crates/rune-modules/src/json.rs @@ -30,9 +30,9 @@ //! ``` use rune::alloc::fmt::TryWrite; -use rune::alloc::{String, Vec}; -use rune::runtime::{Bytes, Formatter, Value, VmResult}; -use rune::{vm_write, Any, ContextError, Module}; +use rune::alloc::{self, String, Vec}; +use rune::runtime::{Bytes, Formatter, Value}; +use rune::{nested_try, Any, ContextError, Module}; #[rune::module(::json)] /// Module for processing JSON. @@ -45,15 +45,15 @@ use rune::{vm_write, Any, ContextError, Module}; /// assert_eq!(object, #{"number": 42, "string": "Hello World"}); /// ``` pub fn module(_stdio: bool) -> Result { - let mut module = Module::from_meta(self::module_meta)?; - module.ty::()?; - module.function_meta(Error::display)?; - module.function_meta(Error::debug)?; - module.function_meta(from_bytes)?; - module.function_meta(from_string)?; - module.function_meta(to_string)?; - module.function_meta(to_bytes)?; - Ok(module) + let mut m = Module::from_meta(self::module__meta)?; + m.ty::()?; + m.function_meta(Error::display)?; + m.function_meta(Error::debug)?; + m.function_meta(from_bytes)?; + m.function_meta(from_string)?; + m.function_meta(to_string)?; + m.function_meta(to_bytes)?; + Ok(m) } #[derive(Any)] @@ -65,13 +65,13 @@ struct Error { impl Error { #[rune::function(protocol = DISPLAY_FMT)] - pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.error) + pub(crate) fn display(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.error) } #[rune::function(protocol = DEBUG_FMT)] - pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.error) + pub(crate) fn debug(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.error) } } @@ -116,9 +116,11 @@ fn from_string(string: &str) -> Result { /// let object = json::from_string(json::to_string(object)?)?; /// assert_eq!(object, #{"number": 42, "string": "Hello World"}); /// ``` -#[rune::function(vm_result)] -fn to_string(value: Value) -> Result { - Ok(String::try_from(serde_json::to_string(&value)?).vm?) +#[rune::function] +fn to_string(value: Value) -> alloc::Result> { + Ok(Ok(String::try_from(nested_try!(serde_json::to_string( + &value + )))?)) } /// Convert any value to json bytes. @@ -130,9 +132,9 @@ fn to_string(value: Value) -> Result { /// let object = json::from_bytes(json::to_bytes(object)?)?; /// assert_eq!(object, #{"number": 42, "string": "Hello World"}); /// ``` -#[rune::function(vm_result)] -fn to_bytes(value: Value) -> Result { - Ok(Bytes::from_vec( - Vec::try_from(serde_json::to_vec(&value)?).vm?, - )) +#[rune::function] +fn to_bytes(value: Value) -> alloc::Result> { + Ok(Ok(Bytes::from_vec(Vec::try_from(nested_try!( + serde_json::to_vec(&value) + ))?))) } diff --git a/crates/rune-modules/src/lib.rs b/crates/rune-modules/src/lib.rs index 0d1b7f8e1..acf4e3c4d 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 @@ -87,7 +87,6 @@ macro_rules! entry { let mut context = rune::Context::with_config(stdio)?; $( - #[allow(deprecated)] #[cfg(feature = $name)] { context.install(self::$ident::module(stdio)?)?; @@ -126,9 +125,6 @@ pub mod rand; #[cfg(feature = "signal")] pub mod signal; -#[cfg(feature = "test")] -pub mod test; - #[cfg(feature = "time")] pub mod time; @@ -143,7 +139,6 @@ entry! { {process, "process"}, {rand, "rand"}, {signal, "signal"}, - {test, "test"}, {time, "time"}, {toml, "toml", ser, de}, } diff --git a/crates/rune-modules/src/process.rs b/crates/rune-modules/src/process.rs index 3a9939878..def328ad1 100644 --- a/crates/rune-modules/src/process.rs +++ b/crates/rune-modules/src/process.rs @@ -34,9 +34,9 @@ use rune::alloc::clone::TryClone; use rune::alloc::fmt::TryWrite; -use rune::alloc::Vec; -use rune::runtime::{Bytes, Formatter, Mut, Value, VmResult}; -use rune::{vm_try, vm_write, Any, ContextError, Module}; +use rune::alloc::{self, Vec}; +use rune::runtime::{Bytes, Formatter, Mut, Value, VmError}; +use rune::{nested_try, Any, ContextError, Module}; use std::io; use tokio::process; @@ -54,60 +54,60 @@ use tokio::process; /// [Tokio]: https://tokio.rs #[rune::module(::process)] pub fn module(_stdio: bool) -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; - module.ty::()?; - module.function_meta(Command::new__meta)?; - module.function_meta(Command::arg__meta)?; - module.function_meta(Command::args__meta)?; - module.function_meta(Command::debug_fmt__meta)?; + m.ty::()?; + m.function_meta(Command::new__meta)?; + m.function_meta(Command::arg__meta)?; + m.function_meta(Command::args__meta)?; + m.function_meta(Command::debug_fmt__meta)?; #[cfg(unix)] - module.function_meta(Command::arg0__meta)?; - module.function_meta(Command::stdin__meta)?; - module.function_meta(Command::stdout__meta)?; - module.function_meta(Command::stderr__meta)?; - module.function_meta(Command::kill_on_drop__meta)?; - module.function_meta(Command::spawn__meta)?; - - module.ty::()?; - module.function_meta(Child::debug_fmt__meta)?; - module.function_meta(Child::stdin__meta)?; - module.function_meta(Child::stdout__meta)?; - module.function_meta(Child::stderr__meta)?; - module.function_meta(Child::id__meta)?; - module.function_meta(Child::start_kill__meta)?; - module.function_meta(Child::kill__meta)?; - module.function_meta(Child::wait__meta)?; - module.function_meta(Child::wait_with_output__meta)?; - - module.ty::()?; - module.function_meta(ExitStatus::code__meta)?; - module.function_meta(ExitStatus::success__meta)?; - module.function_meta(ExitStatus::display_fmt__meta)?; - module.function_meta(ExitStatus::debug_fmt__meta)?; - - module.ty::()?; - module.function_meta(Output::debug_fmt__meta)?; - - module.ty::()?; - module.function_meta(Stdio::null__meta)?; - module.function_meta(Stdio::inherit__meta)?; - module.function_meta(Stdio::piped__meta)?; - module.function_meta(Stdio::debug_fmt__meta)?; - - module.ty::()?; - module.function_meta(ChildStdin::debug_fmt__meta)?; - module.function_meta(ChildStdin::try_into_stdio__meta)?; - - module.ty::()?; - module.function_meta(ChildStdout::debug_fmt__meta)?; - module.function_meta(ChildStdout::try_into_stdio__meta)?; - - module.ty::()?; - module.function_meta(ChildStderr::debug_fmt__meta)?; - module.function_meta(ChildStderr::try_into_stdio__meta)?; - - Ok(module) + m.function_meta(Command::arg0__meta)?; + m.function_meta(Command::stdin__meta)?; + m.function_meta(Command::stdout__meta)?; + m.function_meta(Command::stderr__meta)?; + m.function_meta(Command::kill_on_drop__meta)?; + m.function_meta(Command::spawn__meta)?; + + m.ty::()?; + m.function_meta(Child::debug_fmt__meta)?; + m.function_meta(Child::stdin__meta)?; + m.function_meta(Child::stdout__meta)?; + m.function_meta(Child::stderr__meta)?; + m.function_meta(Child::id__meta)?; + m.function_meta(Child::start_kill__meta)?; + m.function_meta(Child::kill__meta)?; + m.function_meta(Child::wait__meta)?; + m.function_meta(Child::wait_with_output__meta)?; + + m.ty::()?; + m.function_meta(ExitStatus::code__meta)?; + m.function_meta(ExitStatus::success__meta)?; + m.function_meta(ExitStatus::display_fmt__meta)?; + m.function_meta(ExitStatus::debug_fmt__meta)?; + + m.ty::()?; + m.function_meta(Output::debug_fmt__meta)?; + + m.ty::()?; + m.function_meta(Stdio::null__meta)?; + m.function_meta(Stdio::inherit__meta)?; + m.function_meta(Stdio::piped__meta)?; + m.function_meta(Stdio::debug_fmt__meta)?; + + m.ty::()?; + m.function_meta(ChildStdin::debug_fmt__meta)?; + m.function_meta(ChildStdin::try_into_stdio__meta)?; + + m.ty::()?; + m.function_meta(ChildStdout::debug_fmt__meta)?; + m.function_meta(ChildStdout::try_into_stdio__meta)?; + + m.ty::()?; + m.function_meta(ChildStderr::debug_fmt__meta)?; + m.function_meta(ChildStderr::try_into_stdio__meta)?; + + Ok(m) } /// This structure mimics the API of [`std::process::Command`] found in the @@ -227,12 +227,12 @@ impl Command { /// let output = command.output().await?; /// ``` #[rune::function(keep, instance)] - fn args(&mut self, args: &[Value]) -> VmResult<()> { + fn args(&mut self, args: &[Value]) -> Result<(), VmError> { for arg in args { - self.inner.arg(&*vm_try!(arg.borrow_string_ref())); + self.inner.arg(&*arg.borrow_string_ref()?); } - VmResult::Ok(()) + Ok(()) } /// Sets executable argument. @@ -425,8 +425,8 @@ impl Command { } #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{self:?}") + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{self:?}") } } @@ -603,22 +603,22 @@ impl Child { /// order to capture the output into this `Output` it is necessary to create /// new pipes between parent and child. Use `stdout(Stdio::piped())` or /// `stderr(Stdio::piped())`, respectively, when creating a `Command`. - #[rune::function(keep, vm_result, instance)] - async fn wait_with_output(self) -> io::Result { - let output = self.inner.wait_with_output().await?; + #[rune::function(keep, instance)] + async fn wait_with_output(self) -> alloc::Result> { + let output = nested_try!(self.inner.wait_with_output().await); - Ok(Output { + Ok(Ok(Output { status: ExitStatus { inner: output.status, }, - stdout: Value::new(Bytes::from_vec(Vec::try_from(output.stdout).vm?)).vm?, - stderr: Value::new(Bytes::from_vec(Vec::try_from(output.stderr).vm?)).vm?, - }) + stdout: Value::new(Bytes::from_vec(Vec::try_from(output.stdout)?))?, + stderr: Value::new(Bytes::from_vec(Vec::try_from(output.stderr)?))?, + })) } #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } } @@ -645,8 +645,8 @@ struct Output { impl Output { #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{self:?}") + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{self:?}") } } @@ -714,13 +714,13 @@ impl ExitStatus { } #[rune::function(keep, protocol = DISPLAY_FMT)] - fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.inner) + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) } #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } } @@ -757,8 +757,8 @@ impl Stdio { } #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } } @@ -785,8 +785,8 @@ macro_rules! stdio_stream { } #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } } }; diff --git a/crates/rune-modules/src/rand.rs b/crates/rune-modules/src/rand.rs deleted file mode 100644 index 7b1e78631..000000000 --- a/crates/rune-modules/src/rand.rs +++ /dev/null @@ -1,170 +0,0 @@ -#![allow(dead_code)] -//! The native `rand` module for the [Rune Language]. -//! -//! [Rune Language]: https://rune-rs.github.io -//! -//! ## Usage -//! -//! Add the following to your `Cargo.toml`: -//! -//! ```toml -//! rune-modules = { version = "0.14.0", features = ["rand"] } -//! ``` -//! -//! Install it into your context: -//! -//! ```rust -//! let mut context = rune::Context::with_default_modules()?; -//! context.install(rune_modules::rand::module(true)?)?; -//! # Ok::<_, rune::support::Error>(()) -//! ``` -//! -//! Use it in Rune: -//! -//! ```rust,ignore -//! fn main() { -//! let rng = rand::WyRand::new(); -//! let rand_int = rng.int(); -//! println(`Random int: {rand_int}`); -//! let rand_int_range = rng.int_range(-100, 100); -//! println(`Random int between -100 and 100: {rand_int_range}`); -//! } -//! ``` - -use nanorand::Rng; -use rune::{Any, ContextError, Module}; - -/// Construct the `rand` module. -pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("rand")?; - - module.ty::()?; - module - .function("new", WyRand::new) - .build_associated::()?; - module - .function("new_seed", WyRand::new_seed) - .build_associated::()?; - module.associated_function("int", WyRand::int)?; - module.associated_function("int_range", WyRand::int_range)?; - - module.ty::()?; - module - .function("new", Pcg64::new) - .build_associated::()?; - module - .function("new_seed", Pcg64::new_seed) - .build_associated::()?; - module.associated_function("int", Pcg64::int)?; - module.associated_function("int_range", Pcg64::int_range)?; - - module.function("int", int).build()?; - module.function("int_range", int_range).build()?; - Ok(module) -} - -#[derive(Any)] -#[rune(item = ::rand)] -struct WyRand { - inner: nanorand::WyRand, -} - -impl WyRand { - /// Create a new RNG instance. - fn new() -> Self { - Self { - inner: nanorand::WyRand::new(), - } - } - - /// Create a new RNG instance, using a custom seed. - fn new_seed(seed: i64) -> Self { - Self { - inner: nanorand::WyRand::new_seed(seed as u64), - } - } - - /// Generate a random integer - 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) -> i64 { - self.inner.generate_range(0..(upper - lower) as u64) as i64 + lower - } -} - -#[derive(Any)] -#[rune(item = ::rand)] -struct Pcg64 { - inner: nanorand::Pcg64, -} - -impl Pcg64 { - /// Create a new RNG instance. - fn new() -> Self { - Self { - inner: nanorand::Pcg64::new(), - } - } - - /// Create a new RNG instance, using a custom seed. - fn new_seed(seed: i64) -> Self { - Self { - inner: nanorand::Pcg64::new_seed(seed as u128), - } - } - - /// Generate a random integer - 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) -> i64 { - self.inner.generate_range(0..(upper - lower) as u64) as i64 + lower - } -} - -fn int() -> rune::support::Result { - Ok(nanorand::WyRand::new().generate::() as i64) -} - -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)] -mod tests { - use super::{int, int_range}; - - #[test] - fn test_range_is_exclusive() { - for _ in 0..100 { - assert_eq!(int_range(0, 1).unwrap(), 0); - } - } - - #[test] - fn test_range_can_be_negative() { - for _ in 0..100 { - assert_eq!(int_range(-2, -1).unwrap(), -2); - } - } - - #[test] - fn test_int_is_properly_signed() { - let mut any_negative = false; - let mut any_positive = false; - - for _ in 0..100 { - let v: i64 = int().unwrap(); - any_negative = any_negative || v < 0; - any_positive = any_positive || v > 0; - } - - assert!(any_positive); - assert!(any_negative); - } -} diff --git a/crates/rune-modules/src/rand/error.rs b/crates/rune-modules/src/rand/error.rs new file mode 100644 index 000000000..e67fec9ad --- /dev/null +++ b/crates/rune-modules/src/rand/error.rs @@ -0,0 +1,26 @@ +use rune::alloc; +use rune::alloc::fmt::TryWrite; +use rune::runtime::Formatter; +use rune::Any; + +/// An error returned by methods in the `rand` module. +#[derive(Debug, Any)] +#[rune(item = ::rand)] +pub(super) struct Error { + pub(super) inner: getrandom::Error, +} + +impl From for Error { + #[inline] + fn from(inner: getrandom::Error) -> Self { + Self { inner } + } +} + +impl Error { + /// Write a display representation the error. + #[rune::function(instance, protocol = DISPLAY_FMT)] + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) + } +} diff --git a/crates/rune-modules/src/rand/macros.rs b/crates/rune-modules/src/rand/macros.rs new file mode 100644 index 000000000..00fbe2138 --- /dev/null +++ b/crates/rune-modules/src/rand/macros.rs @@ -0,0 +1,283 @@ +#[cfg(any(feature = "small_rng", feature = "std_rng"))] +macro_rules! seedable_rng { + ($m:ident, $ty:ident) => {{ + use rune::nested_try; + use rune::runtime::{TypeHash, Value, VmError}; + + $m.function_meta(from_rng)?; + $m.function_meta(try_from_rng)?; + #[cfg(feature = "os_rng")] + $m.function_meta(from_os_rng)?; + #[cfg(feature = "os_rng")] + $m.function_meta(try_from_os_rng)?; + $m.function_meta(from_seed)?; + $m.function_meta(seed_from_u64)?; + + /// Create a new PRNG seeded from an infallible `Rng`. + /// + /// This may be useful when needing to rapidly seed many PRNGs from a master + /// PRNG, and to allow forking of PRNGs. It may be considered deterministic. + /// + /// The master PRNG should be at least as high quality as the child PRNGs. + /// When seeding non-cryptographic child PRNGs, we recommend using a + /// different algorithm for the master PRNG (ideally a CSPRNG) to avoid + /// correlations between the child PRNGs. If this is not possible (e.g. + /// forking using small non-crypto PRNGs) ensure that your PRNG has a good + /// mixing function on the output or consider use of a hash function with + /// `from_seed`. + /// + /// Note that seeding `XorShiftRng` from another `XorShiftRng` provides an + /// extreme example of what can go wrong: the new PRNG will be a clone + /// of the parent. + /// + /// PRNG implementations are allowed to assume that a good RNG is provided + /// for seeding, and that it is cryptographically secure when appropriate. + /// As of `rand` 0.7 / `rand_core` 0.5, implementations overriding this + /// method should ensure the implementation satisfies reproducibility + /// (in prior versions this was not required). + /// + /// [`rand`]: self + #[rune::function(free, path = $ty::from_rng)] + fn from_rng(rng: Value) -> Result<$ty, VmError> { + match rng.type_hash() { + #[cfg(feature = "small_rng")] + crate::rand::SmallRng::HASH => { + let mut rng = rng.borrow_mut::()?; + + let inner = match rand::SeedableRng::try_from_rng(&mut rng.inner) { + Ok(inner) => inner, + Err(error) => return Err(VmError::panic(error)), + }; + + Ok($ty { inner }) + } + #[cfg(feature = "std_rng")] + crate::rand::StdRng::HASH => { + let mut rng = rng.borrow_mut::()?; + + let inner = match rand::SeedableRng::try_from_rng(&mut rng.inner) { + Ok(inner) => inner, + Err(error) => return Err(VmError::panic(error)), + }; + + Ok($ty { inner }) + } + #[cfg(feature = "thread_rng")] + crate::rand::ThreadRng::HASH => { + let mut rng = rng.borrow_mut::()?; + let inner = + rand::SeedableRng::try_from_rng(&mut rng.inner).map_err(VmError::panic)?; + Ok($ty { inner }) + } + #[cfg(feature = "os_rng")] + crate::rand::OsRng::HASH => { + let mut rng = rng.borrow_mut::()?; + let inner = + rand::SeedableRng::try_from_rng(&mut rng.inner).map_err(VmError::panic)?; + Ok($ty { inner }) + } + _ => Err(VmError::panic("expected an rng source")), + } + } + + /// Create a new PRNG seeded from a potentially fallible `Rng`. + /// + /// See [`from_rng`][$ty::from_rng] docs for more information. + #[rune::function(free, path = $ty::try_from_rng)] + fn try_from_rng(rng: Value) -> Result, VmError> { + match rng.type_hash() { + #[cfg(feature = "small_rng")] + crate::rand::SmallRng::HASH => { + let mut rng = rng.borrow_mut::()?; + let inner = nested_try!(rand::SeedableRng::try_from_rng(&mut rng.inner)); + Ok(Ok($ty { inner })) + } + #[cfg(feature = "std_rng")] + crate::rand::StdRng::HASH => { + let mut rng = rng.borrow_mut::()?; + let inner = nested_try!(rand::SeedableRng::try_from_rng(&mut rng.inner)); + Ok(Ok($ty { inner })) + } + #[cfg(feature = "thread_rng")] + crate::rand::ThreadRng::HASH => { + let mut rng = rng.borrow_mut::()?; + let inner = nested_try!(rand::SeedableRng::try_from_rng(&mut rng.inner)); + Ok(Ok($ty { inner })) + } + #[cfg(feature = "os_rng")] + crate::rand::OsRng::HASH => { + let mut rng = rng.borrow_mut::()?; + let inner = nested_try!(rand::SeedableRng::try_from_rng(&mut rng.inner)); + Ok(Ok($ty { inner })) + } + _ => Err(VmError::panic("expected an rng source")), + } + } + + /// Creates a new instance of the RNG seeded via [`getrandom`]. + /// + /// This method is the recommended way to construct non-deterministic PRNGs + /// since it is convenient and secure. + /// + /// Note that this method may panic on (extremely unlikely) [`getrandom`] + /// errors. If it's not desirable, use the [`try_from_os_rng`] method + /// instead. + /// + /// # Panics + /// + /// If [`getrandom`] is unable to provide secure entropy this method will + /// panic. + /// + /// [`getrandom`]: https://docs.rs/getrandom + /// [`try_from_os_rng`]: StdRng::try_from_os_rng + #[rune::function(free, path = $ty::from_os_rng)] + #[cfg(feature = "os_rng")] + fn from_os_rng() -> Result<$ty, VmError> { + let inner = rand::SeedableRng::try_from_os_rng().map_err(VmError::panic)?; + Ok($ty { inner }) + } + + /// Creates a new instance of the RNG seeded via [`getrandom`] without + /// unwrapping potential [`getrandom`] errors. + /// + /// [`getrandom`]: https://docs.rs/getrandom + #[rune::function(free, path = $ty::try_from_os_rng)] + #[cfg(feature = "os_rng")] + fn try_from_os_rng() -> Result<$ty, Error> { + let inner = rand::SeedableRng::try_from_os_rng()?; + Ok($ty { inner }) + } + + /// Create a new PRNG using the given seed. + /// + /// PRNG implementations are allowed to assume that bits in the seed are + /// well distributed. That means usually that the number of one and zero + /// bits are roughly equal, and values like 0, 1 and (size - 1) are + /// unlikely. Note that many non-cryptographic PRNGs will show poor quality + /// output if this is not adhered to. If you wish to seed from simple + /// numbers, use [`seed_from_u64`] instead. + /// + /// All PRNG implementations should be reproducible unless otherwise noted: + /// given a fixed `seed`, the same sequence of output should be produced on + /// all runs, library versions and architectures (e.g. check endianness). + /// Any "value-breaking" changes to the generator should require bumping at + /// least the minor version and documentation of the change. + /// + /// It is not required that this function yield the same state as a + /// reference implementation of the PRNG given equivalent seed; if necessary + /// another constructor replicating behaviour from a reference + /// implementation can be added. + /// + /// PRNG implementations should make sure `from_seed` never panics. In the + /// case that some special values (like an all zero seed) are not viable + /// seeds it is preferable to map these to alternative constant value(s), + /// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad + /// seed"). This is assuming only a small number of values must be rejected. + /// + /// [`seed_from_u64`]: SmallRng::seed_from_u64 + #[rune::function(free, path = $ty::from_seed)] + fn from_seed(seed: [u8; 32]) -> $ty { + $ty { + inner: rand::SeedableRng::from_seed(seed), + } + } + + /// Create a new PRNG using a `u64` seed. + /// + /// This is a convenience-wrapper around `from_seed` to allow construction + /// of any `SeedableRng` from a simple `u64` value. It is designed such that + /// low Hamming Weight numbers like 0 and 1 can be used and should still + /// result in good, independent seeds to the PRNG which is returned. + /// + /// This **is not suitable for cryptography**, as should be clear given that + /// the input size is only 64 bits. + /// + /// Implementations for PRNGs *may* provide their own implementations of + /// this function, but the default implementation should be good enough for + /// all purposes. *Changing* the implementation of this function should be + /// considered a value-breaking change. + #[rune::function(free, path = $ty::seed_from_u64)] + fn seed_from_u64(state: u64) -> $ty { + $ty { + inner: rand::SeedableRng::seed_from_u64(state), + } + } + }}; +} + +#[cfg(any(feature = "small_rng", feature = "std_rng", feature = "thread_rng"))] +macro_rules! random { + ($m:ident, $ty:ty, $example:expr, $(($name:ident, $out:ty)),* $(,)?) => { + $( + #[doc = concat!(" Return a random `", stringify!($out), "` value via a standard uniform distribution.")] + /// + /// # Example + /// + /// ```rune + #[doc = concat!(" use rand::", stringify!($ty), ";")] + /// + #[doc = concat!(" let rng = ", $example, ";")] + #[doc = concat!(" let x = rng.random::<", stringify!($out), ">();")] + /// println!("{x}"); + /// ``` + #[rune::function(instance, path = random<$out>)] + fn $name(this: &mut $ty) -> $out { + rand::Rng::random(&mut this.inner) + } + + $m.function_meta($name)?; + )* + } +} + +#[cfg(any(feature = "small_rng", feature = "std_rng", feature = "thread_rng"))] +macro_rules! random_ranges { + ($m:ident, $ty:ty, $example:expr, $(($name:ident, $out:ty, $as:path, $range:expr)),* $(,)?) => { + $( + { + use rune::runtime::{Range, RangeInclusive, TypeHash, Value, VmError}; + + #[doc = concat!(" Return a random `", stringify!($out), "` value via a standard uniform constrained with a range.")] + /// + /// # Example + /// + /// ```rune + #[doc = concat!(" use rand::", stringify!($ty), ";")] + /// + #[doc = concat!(" let rng = ", $example, ";")] + #[doc = concat!(" let x = rng.random_range::<", stringify!($out), ">(", stringify!($range), ");")] + /// println!("{x}"); + /// ``` + #[rune::function(instance, path = random_range<$out>)] + fn $name(this: &mut $ty, range: Value) -> Result<$out, VmError> { + let value = match range.as_any() { + Some(value) => match value.type_hash() { + RangeInclusive::HASH => { + let range = value.borrow_ref::()?; + let start = $as(&range.start)?; + let end = $as(&range.end)?; + rand::Rng::random_range(&mut this.inner, start..=end) + } + Range::HASH => { + let range = value.borrow_ref::()?; + let start = $as(&range.start)?; + let end = $as(&range.end)?; + rand::Rng::random_range(&mut this.inner, start..end) + } + _ => { + return Err(VmError::panic("unsupported range")); + } + }, + _ => { + return Err(VmError::panic("unsupported range")); + } + }; + + Ok(value) + } + + $m.function_meta($name)?; + } + )* + } +} diff --git a/crates/rune-modules/src/rand/mod.rs b/crates/rune-modules/src/rand/mod.rs new file mode 100644 index 000000000..673eaadba --- /dev/null +++ b/crates/rune-modules/src/rand/mod.rs @@ -0,0 +1,140 @@ +#![allow(dead_code)] +//! The native `rand` module for the [Rune Language]. +//! +//! [Rune Language]: https://rune-rs.github.io +//! +//! ## Usage +//! +//! Add the following to your `Cargo.toml`: +//! +//! ```toml +//! rune-modules = { version = "0.14.0", features = ["rand"] } +//! ``` +//! +//! Install it into your context: +//! +//! ```rust +//! let mut context = rune::Context::with_default_modules()?; +//! context.install(rune_modules::rand::module(true)?)?; +//! # Ok::<_, rune::support::Error>(()) +//! ``` +//! +//! Use it in Rune: +//! +//! ```rust,ignore +//! fn main() { +//! let rng = rand::StdRng::try_from_os_rng()?; +//! let rand_int = rng.random::(); +//! println(`Random int: {rand_int}`); +//! let rand_int_range = rng.random_range::(-100..100); +//! println(`Random int between -100 and 100: {rand_int_range}`); +//! } +//! ``` + +#[macro_use] +mod macros; + +#[cfg(all(any(feature = "small_rng", feature = "std_rng"), feature = "os_rng"))] +mod error; +#[cfg(all(any(feature = "small_rng", feature = "std_rng"), feature = "os_rng"))] +use self::error::Error; + +#[cfg(feature = "os_rng")] +mod os_rng; +#[cfg(feature = "os_rng")] +use self::os_rng::OsRng; + +#[cfg(any(feature = "thread_rng", feature = "os_rng"))] +mod os_error; +#[cfg(any(feature = "thread_rng", feature = "os_rng"))] +use self::os_error::OsError; + +#[cfg(any(feature = "small_rng", feature = "std_rng"))] +mod try_from_rng_error; +#[cfg(any(feature = "small_rng", feature = "std_rng"))] +use self::try_from_rng_error::TryFromRngError; + +#[cfg(feature = "small_rng")] +mod small_rng; +#[cfg(feature = "small_rng")] +use self::small_rng::SmallRng; + +#[cfg(feature = "std_rng")] +mod std_rng; +#[cfg(feature = "std_rng")] +use self::std_rng::StdRng; + +#[cfg(feature = "thread_rng")] +mod thread_rng; +#[cfg(feature = "thread_rng")] +use self::thread_rng::{rng, ThreadRng}; + +use rune::{ContextError, Module}; + +/// Construct the `rand` module. +#[rune::module(::rand)] +pub fn module(_stdio: bool) -> Result { + #[allow(unused_mut)] + let mut m = Module::from_meta(module__meta)?; + + #[cfg(all(any(feature = "small_rng", feature = "std_rng"), feature = "os_rng"))] + { + m.ty::()?; + m.function_meta(Error::display_fmt)?; + } + + #[cfg(any(feature = "thread_rng", feature = "os_rng"))] + { + m.ty::()?; + m.function_meta(OsError::display_fmt)?; + } + + #[cfg(any(feature = "small_rng", feature = "std_rng", feature = "thread_rng"))] + macro_rules! call_random { + ($ty:ty, $example:expr) => { + random! { + m, $ty, $example, + (random_u64, u64), + (random_i64, i64), + (random_char, char), + (random_bool, bool), + }; + + random_ranges! { + m, $ty, $example, + (random_range_u64, u64, Value::as_integer::, 0..100), + (random_range_i64, i64, Value::as_integer::, -100..100), + (random_range_char, char, Value::as_char, 'a'..'z'), + }; + }; + } + + #[cfg(feature = "os_rng")] + { + m.ty::()?; + } + + #[cfg(feature = "small_rng")] + { + m.ty::()?; + call_random!(SmallRng, "SmallRng::try_from_os_rng()?"); + seedable_rng!(m, SmallRng); + } + + #[cfg(feature = "std_rng")] + { + m.ty::()?; + call_random!(StdRng, "StdRng::try_from_os_rng()?"); + seedable_rng!(m, StdRng); + } + + #[cfg(feature = "thread_rng")] + { + m.ty::()?; + m.function_meta(ThreadRng::reseed)?; + m.function_meta(rng)?; + call_random!(ThreadRng, "rand::rng()"); + } + + Ok(m) +} diff --git a/crates/rune-modules/src/rand/os_error.rs b/crates/rune-modules/src/rand/os_error.rs new file mode 100644 index 000000000..50d899ce7 --- /dev/null +++ b/crates/rune-modules/src/rand/os_error.rs @@ -0,0 +1,26 @@ +use rune::alloc; +use rune::alloc::fmt::TryWrite; +use rune::runtime::Formatter; +use rune::Any; + +/// An os error returned by methods in the `rand` module. +#[derive(Debug, Any)] +#[rune(item = ::rand)] +pub(super) struct OsError { + pub(super) inner: rand::rand_core::OsError, +} + +impl From for OsError { + #[inline] + fn from(inner: rand::rand_core::OsError) -> Self { + Self { inner } + } +} + +impl OsError { + /// Write a display representation the error. + #[rune::function(instance, protocol = DISPLAY_FMT)] + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) + } +} diff --git a/crates/rune-modules/src/rand/os_rng.rs b/crates/rune-modules/src/rand/os_rng.rs new file mode 100644 index 000000000..0765ce974 --- /dev/null +++ b/crates/rune-modules/src/rand/os_rng.rs @@ -0,0 +1,49 @@ +use rune::Any; + +/// An interface over the operating-system's random data source +/// +/// This is a zero-sized struct. It can be freely constructed with just `OsRng`. +/// +/// The implementation is provided by the [getrandom] crate. Refer to +/// [getrandom] documentation for details. +/// +/// This struct is available as `rand_core::OsRng` and as `rand::rngs::OsRng`. +/// In both cases, this requires the crate feature `os_rng` or `std` (enabled by +/// default in `rand` but not in `rand_core`). +/// +/// # Blocking and error handling +/// +/// It is possible that when used during early boot the first call to `OsRng` +/// will block until the system's RNG is initialised. It is also possible +/// (though highly unlikely) for `OsRng` to fail on some platforms, most likely +/// due to system mis-configuration. +/// +/// After the first successful call, it is highly unlikely that failures or +/// significant delays will occur (although performance should be expected to be +/// much slower than a user-space +/// [PRNG](https://rust-random.github.io/book/guide-gen.html#pseudo-random-number-generators)). +/// +/// # Usage example +/// +/// ```rune +/// use rand::{SmallRng, OsRng}; +/// +/// let rng = SmallRng::try_from_rng(OsRng)?; +/// let v = rng.random::(); +/// ``` +/// +/// [getrandom]: https://crates.io/crates/getrandom +#[derive(Any)] +#[rune(item = ::rand, empty, constructor = OsRng::new)] +pub(super) struct OsRng { + pub(super) inner: rand::rngs::OsRng, +} + +impl OsRng { + #[inline] + pub(super) fn new() -> Self { + Self { + inner: rand::rngs::OsRng, + } + } +} diff --git a/crates/rune-modules/src/rand/small_rng.rs b/crates/rune-modules/src/rand/small_rng.rs new file mode 100644 index 000000000..8b304906a --- /dev/null +++ b/crates/rune-modules/src/rand/small_rng.rs @@ -0,0 +1,70 @@ +use rune::Any; + +/// A small-state, fast, non-crypto, non-portable PRNG +/// +/// This is the "standard small" RNG, a generator with the following properties: +/// +/// - Non-[portable]: any future library version may replace the algorithm and +/// results may be platform-dependent. (For a small portable generator, use +/// the [rand_pcg] or [rand_xoshiro] crate.) +/// - Non-cryptographic: output is easy to predict (insecure) +/// - [Quality]: statistically good quality +/// - Fast: the RNG is fast for both bulk generation and single values, with +/// consistent cost of method calls +/// - Fast initialization +/// - Small state: little memory usage (current state size is 16-32 bytes +/// depending on platform) +/// +/// The current algorithm is `Xoshiro256PlusPlus` on 64-bit platforms and +/// `Xoshiro128PlusPlus` on 32-bit platforms. Both are also implemented by the +/// [rand_xoshiro] crate. +/// +/// ## Seeding (construction) +/// +/// This generator implements the [`SeedableRng`] trait. All methods are +/// suitable for seeding, but note that, even with a fixed seed, output is not +/// [portable]. Some suggestions: +/// +/// To automatically seed with a unique seed, use [`SmallRng::from_rng`]: +/// +/// ```rune +/// use rand::SmallRng; +/// +/// let rng = rand::rng(); +/// let rng = SmallRng::from_rng(rng); +/// ``` +/// or [`SmallRng::from_os_rng`]: +/// ```rune +/// use rand::SmallRng; +/// +/// let rng = SmallRng::from_os_rng(); +/// ``` +/// +/// To use a deterministic integral seed, use `seed_from_u64`. This uses a +/// hash function internally to yield a (typically) good seed from any +/// input. +/// +/// ```rune +/// use rand::SmallRng; +/// +/// let rng = SmallRng::seed_from_u64(1); +/// ``` +/// +/// To seed deterministically from text or other input, use [`rand_seeder`]. +/// +/// See also [Seeding RNGs] in the book. +/// +/// [portable]: https://rust-random.github.io/book/crate-reprod.html +/// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html +/// [Quality]: https://rust-random.github.io/book/guide-rngs.html#quality +/// [`StdRng`]: crate::rngs::StdRng +/// [rand_pcg]: https://crates.io/crates/rand_pcg +/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro +/// [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html +/// [`rand_seeder`]: https://docs.rs/rand_seeder/latest/rand_seeder/ +#[derive(Any)] +#[rune(item = ::rand)] +#[cfg(feature = "small_rng")] +pub(super) struct SmallRng { + pub(super) inner: rand::rngs::SmallRng, +} diff --git a/crates/rune-modules/src/rand/std_rng.rs b/crates/rune-modules/src/rand/std_rng.rs new file mode 100644 index 000000000..b06eb6307 --- /dev/null +++ b/crates/rune-modules/src/rand/std_rng.rs @@ -0,0 +1,55 @@ +use rune::Any; + +/// A strong, fast (amortized), non-portable RNG +/// +/// This is the "standard" RNG, a generator with the following properties: +/// +/// - Non-[portable]: any future library version may replace the algorithm and +/// results may be platform-dependent. (For a portable version, use the +/// [rand_chacha] crate directly.) +/// - [CSPRNG]: statistically good quality of randomness and [unpredictable] +/// - Fast ([amortized](https://en.wikipedia.org/wiki/Amortized_analysis)): the +/// RNG is fast for bulk generation, but the cost of method calls is not +/// consistent due to usage of an output buffer. +/// +/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please +/// see this relevant [rand issue] for the discussion. This may change as new +/// evidence of cipher security and performance becomes available. +/// +/// ## Seeding (construction) +/// +/// This generator implements the [`SeedableRng`] trait. Any method may be used, +/// but note that `seed_from_u64` is not suitable for usage where security is +/// important. Also note that, even with a fixed seed, output is not [portable]. +/// +/// Using a fresh seed **direct from the OS** is the most secure option: +/// +/// ```rune +/// use rand::StdRng; +/// +/// let rng = StdRng::try_from_os_rng()?; +/// ``` +/// +/// Seeding via [`rand::rng()`](crate::rng()) may be faster: +/// +/// ```rune +/// use rand::StdRng; +/// +/// let rng = rand::rng(); +/// let rng = StdRng::from_rng(rng); +/// ``` +/// +/// Any [`SeedableRng`] method may be used, but note that `seed_from_u64` is not +/// suitable where security is required. See also [Seeding RNGs] in the book. +/// +/// [portable]: https://rust-random.github.io/book/crate-reprod.html +/// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html +/// [unpredictable]: https://rust-random.github.io/book/guide-rngs.html#security +/// [CSPRNG]: https://rust-random.github.io/book/guide-gen.html#cryptographically-secure-pseudo-random-number-generator +/// [rand_chacha]: https://crates.io/crates/rand_chacha +/// [rand issue]: https://github.com/rust-random/rand/issues/932 +#[derive(Any)] +#[rune(item = ::rand)] +pub(super) struct StdRng { + pub(super) inner: rand::rngs::StdRng, +} diff --git a/crates/rune-modules/src/rand/thread_rng.rs b/crates/rune-modules/src/rand/thread_rng.rs new file mode 100644 index 000000000..34aa3c63f --- /dev/null +++ b/crates/rune-modules/src/rand/thread_rng.rs @@ -0,0 +1,96 @@ +use rune::Any; + +use super::OsError; + +/// Access a fast, pre-initialized generator +/// +/// This is a handle to the local [`ThreadRng`]. +/// +/// # Example +/// +/// ```rune +/// // Using a local binding avoids an initialization-check on each usage: +/// let rng = rand::rng(); +/// +/// println!("True or false: {}", rng.random::()); +/// println!("A simulated die roll: {}", rng.random_range::(1..=6)); +/// ``` +/// +/// # Security +/// +/// Refer to [`ThreadRng#Security`]. +#[rune::function] +#[cfg(feature = "thread_rng")] +fn rng() -> ThreadRng { + ThreadRng { inner: rand::rng() } +} + +/// A reference to the thread-local generator +/// +/// This type is a reference to a lazily-initialized thread-local generator. An +/// instance can be obtained via [`rand::rng()`][crate::rng()] or via +/// [`ThreadRng::default()`]. The handle cannot be passed between threads (is +/// not `Send` or `Sync`). +/// +/// # Security +/// +/// Security must be considered relative to a threat model and validation +/// requirements. The Rand project can provide no guarantee of fitness for +/// purpose. The design criteria for `ThreadRng` are as follows: +/// +/// - Automatic seeding via [`OsRng`] and periodically thereafter (see +/// ([`ReseedingRng`] documentation). Limitation: there is no automatic +/// reseeding on process fork (see [below](#fork)). +/// - A rigorusly analyzed, unpredictable (cryptographic) pseudo-random +/// generator (see [the book on +/// security](https://rust-random.github.io/book/guide-rngs.html#security)). +/// The currently selected algorithm is ChaCha (12-rounds). See also +/// [`StdRng`] documentation. +/// - Not to leak internal state through [`Debug`] or serialization +/// implementations. +/// - No further protections exist to in-memory state. In particular, the +/// implementation is not required to zero memory on exit (of the process or +/// thread). (This may change in the future.) +/// - Be fast enough for general-purpose usage. Note in particular that +/// `ThreadRng` is designed to be a "fast, reasonably secure generator" (where +/// "reasonably secure" implies the above criteria). +/// +/// We leave it to the user to determine whether this generator meets their +/// security requirements. For an alternative, see [`OsRng`]. +/// +/// # Fork +/// +/// `ThreadRng` is not automatically reseeded on fork. It is recommended to +/// explicitly call [`ThreadRng::reseed`] immediately after a fork, for example: +/// +/// ```ignore +/// fn do_fork() { +/// let pid = unsafe { libc::fork() }; +/// if pid == 0 { +/// // Reseed ThreadRng in child processes: +/// rand::rng().reseed(); +/// } +/// } +/// ``` +/// +/// Methods on `ThreadRng` are not reentrant-safe and thus should not be called +/// from an interrupt (e.g. a fork handler) unless it can be guaranteed that no +/// other method on the same `ThreadRng` is currently executing. +/// +/// [`ReseedingRng`]: crate::rngs::ReseedingRng +/// [`StdRng`]: crate::rngs::StdRng +#[derive(Any)] +#[rune(item = ::rand)] +pub(super) struct ThreadRng { + pub(super) inner: rand::rngs::ThreadRng, +} + +impl ThreadRng { + /// Immediately reseed the generator + /// + /// This discards any remaining random data in the cache. + #[rune::function] + pub(super) fn reseed(&mut self) -> Result<(), OsError> { + Ok(self.inner.reseed()?) + } +} diff --git a/crates/rune-modules/src/rand/try_from_rng_error.rs b/crates/rune-modules/src/rand/try_from_rng_error.rs new file mode 100644 index 000000000..a3ffd826e --- /dev/null +++ b/crates/rune-modules/src/rand/try_from_rng_error.rs @@ -0,0 +1,64 @@ +use core::convert::Infallible; +use core::fmt; + +use rune::alloc; +use rune::alloc::fmt::TryWrite; +use rune::runtime::Formatter; +use rune::Any; + +/// An error returned by fallible `try_from_rng` methods. +#[derive(Any)] +#[rune(item = ::rand)] +pub struct TryFromRngError { + kind: TryFromRngErrorKind, +} + +impl TryFromRngError { + /// Write a display representation the error. + #[rune::function(instance, protocol = DISPLAY_FMT)] + fn display_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.kind) + } +} + +#[cfg(feature = "os_rng")] +impl From for TryFromRngError { + #[inline] + fn from(inner: rand::rand_core::OsError) -> Self { + Self { + kind: TryFromRngErrorKind::OsError(inner), + } + } +} + +impl From for TryFromRngError { + #[inline] + fn from(inner: Infallible) -> Self { + match inner {} + } +} + +impl fmt::Debug for TryFromRngError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.kind.fmt(f) + } +} + +#[derive(Debug)] +enum TryFromRngErrorKind { + #[cfg(feature = "os_rng")] + OsError(rand::rand_core::OsError), +} + +impl fmt::Display for TryFromRngErrorKind { + #[inline] + fn fmt(&self, #[allow(unused)] f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + #[cfg(feature = "os_rng")] + TryFromRngErrorKind::OsError(ref inner) => { + write!(f, "{inner}") + } + } + } +} diff --git a/crates/rune-modules/src/signal.rs b/crates/rune-modules/src/signal.rs index 9816be0dd..f9a26c2e6 100644 --- a/crates/rune-modules/src/signal.rs +++ b/crates/rune-modules/src/signal.rs @@ -44,9 +44,9 @@ use rune::{ContextError, Module}; /// [Tokio]: https://tokio.rs #[rune::module(::signal)] pub fn module(_stdio: bool) -> Result { - let mut module = Module::from_meta(self::module_meta)?; - module.function_meta(ctrl_c)?; - Ok(module) + let mut m = Module::from_meta(self::module__meta)?; + m.function_meta(ctrl_c)?; + Ok(m) } /// Completes when a "ctrl-c" notification is sent to the process. diff --git a/crates/rune-modules/src/test.rs b/crates/rune-modules/src/test.rs deleted file mode 100644 index 30fb16493..000000000 --- a/crates/rune-modules/src/test.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! `std::test` module for the [Rune Language]. -//! -//! [Rune Language]: https://rune-rs.github.io -//! -//! Note: **this has been deprecated**, all functions in this module have been -//! moved into the [`rune` crate][rune::modules]. - -use rune::{ContextError, Module}; - -/// Construct the supplemental `std::test` module. -#[deprecated = "all functions in this module have been included in the rune crate, see https://github.com/rune-rs/rune/issues/456"] -pub fn module(_stdio: bool) -> Result { - rune::modules::test::module() -} diff --git a/crates/rune-modules/src/time.rs b/crates/rune-modules/src/time.rs index 81de3e943..104c99cdb 100644 --- a/crates/rune-modules/src/time.rs +++ b/crates/rune-modules/src/time.rs @@ -32,9 +32,10 @@ use core::cmp::Ordering; use core::hash::Hash; +use rune::alloc; use rune::alloc::fmt::TryWrite; -use rune::runtime::{Formatter, Hasher, Mut, VmResult}; -use rune::{docstring, item, vm_panic, Any, ContextError, Module, ToConstValue}; +use rune::runtime::{Formatter, Hasher, Mut, VmError}; +use rune::{docstring, item, Any, ContextError, Module, ToConstValue}; const NANOS_PER_SEC: u32 = 1_000_000_000; @@ -385,12 +386,12 @@ impl Duration { /// let five_seconds = Duration::new(5, 0); /// ``` #[rune::function(keep, path = Self::new)] - pub fn new(secs: u64, nanos: u32) -> VmResult { + pub fn new(secs: u64, nanos: u32) -> Result { if nanos >= NANOS_PER_SEC && secs.checked_add((nanos / NANOS_PER_SEC) as u64).is_none() { - vm_panic!("overflow in Duration::new"); + return Err(VmError::panic("overflow in Duration::new")); } - VmResult::Ok(Self { + Ok(Self { inner: tokio::time::Duration::new(secs, nanos), }) } @@ -656,10 +657,10 @@ impl Duration { /// let duration = Duration::from_secs_f64(0.0); /// ``` #[rune::function(keep, path = Self::from_secs_f64)] - pub fn from_secs_f64(secs: f64) -> VmResult { + pub fn from_secs_f64(secs: f64) -> Result { match tokio::time::Duration::try_from_secs_f64(secs) { - Ok(duration) => VmResult::Ok(Self { inner: duration }), - Err(e) => vm_panic!(e), + Ok(duration) => Ok(Self { inner: duration }), + Err(e) => Err(VmError::panic(e)), } } @@ -677,12 +678,12 @@ impl Duration { /// ``` #[rune::function(keep, instance, protocol = ADD)] #[inline] - fn add(&self, rhs: &Duration) -> VmResult { + fn add(&self, rhs: &Duration) -> Result { let Some(inner) = self.inner.checked_add(rhs.inner) else { - vm_panic!("overflow when adding durations") + return Err(VmError::panic("overflow when adding durations")); }; - VmResult::Ok(Self { inner }) + Ok(Self { inner }) } /// Add a duration to this instant and return a new instant. @@ -700,13 +701,13 @@ impl Duration { /// ``` #[rune::function(keep, instance, protocol = ADD_ASSIGN)] #[inline] - fn add_assign(&mut self, rhs: &Duration) -> VmResult<()> { + fn add_assign(&mut self, rhs: &Duration) -> Result<(), VmError> { let Some(inner) = self.inner.checked_add(rhs.inner) else { - vm_panic!("overflow when adding duration to instant") + return Err(VmError::panic("overflow when adding duration to instant")); }; self.inner = inner; - VmResult::Ok(()) + Ok(()) } /// Test two durations for partial equality. @@ -842,8 +843,8 @@ impl Duration { /// println!("{second:?}"); /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } /// Clone the current duration. @@ -1129,12 +1130,12 @@ impl Instant { /// ``` #[rune::function(keep, instance, protocol = ADD)] #[inline] - fn add(&self, rhs: &Duration) -> VmResult { + fn add(&self, rhs: &Duration) -> Result { let Some(inner) = self.inner.checked_add(rhs.inner) else { - vm_panic!("overflow when adding duration to instant") + return Err(VmError::panic("overflow when adding duration to instant")); }; - VmResult::Ok(Self { inner }) + Ok(Self { inner }) } /// Add a duration to this instant and return a new instant. @@ -1153,13 +1154,13 @@ impl Instant { /// ``` #[rune::function(keep, instance, protocol = ADD_ASSIGN)] #[inline] - fn add_assign(&mut self, rhs: &Duration) -> VmResult<()> { + fn add_assign(&mut self, rhs: &Duration) -> Result<(), VmError> { let Some(inner) = self.inner.checked_add(rhs.inner) else { - vm_panic!("overflow when adding duration to instant") + return Err(VmError::panic("overflow when adding duration to instant")); }; self.inner = inner; - VmResult::Ok(()) + Ok(()) } /// Test two instants for partial equality. @@ -1291,8 +1292,8 @@ impl Instant { /// println!("{now:?}"); /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{:?}", self.inner) + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } /// Clone the current instant. diff --git a/crates/rune-modules/src/toml.rs b/crates/rune-modules/src/toml.rs index c297bffb6..9eefe8e22 100644 --- a/crates/rune-modules/src/toml.rs +++ b/crates/rune-modules/src/toml.rs @@ -29,9 +29,9 @@ //! } //! ``` -use rune::alloc::String; +use rune::alloc::{self, String}; use rune::runtime::{Bytes, Value}; -use rune::{ContextError, Module}; +use rune::{nested_try, ContextError, Module, VmError}; /// Construct the `toml` module. pub fn module(_stdio: bool) -> Result { @@ -46,9 +46,10 @@ pub fn module(_stdio: bool) -> Result { pub mod de { //! Deserializer types for the toml module. + use rune::alloc; use rune::alloc::fmt::TryWrite; - use rune::runtime::{Formatter, VmResult}; - use rune::{vm_write, Any, ContextError, Module}; + use rune::runtime::Formatter; + use rune::{Any, ContextError, Module}; pub fn module(_stdio: bool) -> Result { let mut module = Module::with_crate_item("toml", ["de"])?; @@ -66,13 +67,13 @@ pub mod de { impl Error { #[rune::function(protocol = DISPLAY_FMT)] - pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.error) + pub(crate) fn display(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.error) } #[rune::function(protocol = DEBUG_FMT)] - pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.error) + pub(crate) fn debug(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.error) } } @@ -86,9 +87,10 @@ pub mod de { pub mod ser { //! Serializer types for the toml module. + use rune::alloc; use rune::alloc::fmt::TryWrite; - use rune::runtime::{Formatter, VmResult}; - use rune::{vm_write, Any, ContextError, Module}; + use rune::runtime::Formatter; + use rune::{Any, ContextError, Module}; pub fn module(_stdio: bool) -> Result { let mut module = Module::with_crate_item("toml", ["ser"])?; @@ -106,13 +108,13 @@ pub mod ser { impl Error { #[rune::function(protocol = DISPLAY_FMT)] - pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.error) + pub(crate) fn display(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.error) } #[rune::function(protocol = DEBUG_FMT)] - pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.error) + pub(crate) fn debug(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.error) } } @@ -124,16 +126,16 @@ pub mod ser { } /// Convert bytes of TOML into a rune value. -#[rune::function(vm_result)] -fn from_bytes(bytes: &[u8]) -> Result { +#[rune::function] +fn from_bytes(bytes: &[u8]) -> Result, VmError> { let bytes = match std::str::from_utf8(bytes) { Ok(bytes) => bytes, - Err(error) => return Err(rune::to_value(error).vm?), + Err(error) => return Ok(Err(rune::to_value(error)?)), }; match toml::from_str(bytes).map_err(de::Error::from) { - Ok(value) => Ok(value), - Err(error) => Err(rune::to_value(error).vm?), + Ok(value) => Ok(Ok(value)), + Err(error) => Ok(Err(rune::to_value(error)?)), } } @@ -144,14 +146,14 @@ fn from_string(string: &str) -> Result { } /// Convert any value to a toml string. -#[rune::function(vm_result)] -fn to_string(value: Value) -> Result { - Ok(String::try_from(toml::to_string(&value)?).vm?) +#[rune::function] +fn to_string(value: Value) -> alloc::Result> { + Ok(Ok(String::try_from(nested_try!(toml::to_string(&value)))?)) } /// Convert any value to toml bytes. -#[rune::function(vm_result)] -fn to_bytes(value: Value) -> Result { - let string = String::try_from(toml::to_string(&value)?).vm?; - Ok(Bytes::from_vec(string.into_bytes())) +#[rune::function] +fn to_bytes(value: Value) -> alloc::Result> { + let string = String::try_from(nested_try!(toml::to_string(&value)))?; + Ok(Ok(Bytes::from_vec(string.into_bytes()))) } diff --git a/crates/rune-shim/Cargo.toml b/crates/rune-shim/Cargo.toml deleted file mode 100644 index 0dfe508fb..000000000 --- a/crates/rune-shim/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "rune-shim" -edition = "2021" -publish = false -description = """ -Improves how long it takes to run doc tests by shimming out rune which would otherwise have to be compiled for every test case. -""" - -[features] -core = ["rune-core"] -alloc = ["rune-alloc"] - -[dependencies] -rune-alloc = { path = "../rune-alloc", optional = true, features = ["std"] } -rune-core = { path = "../rune-core", optional = true, features = ["std"] } - -anyhow = "1.0.71" diff --git a/crates/rune-shim/src/lib.rs b/crates/rune-shim/src/lib.rs deleted file mode 100644 index a4a279a69..000000000 --- a/crates/rune-shim/src/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! This crate is only used to build documentation for the `rune-core` crate. - -#[cfg(feature = "rune-alloc")] -pub use rune_alloc as alloc; - -#[cfg(feature = "rune-core")] -pub mod item { - #[doc(inline)] - pub use rune_core::item::{Component, ComponentRef, IntoComponent, Item, ItemBuf}; -} - -#[cfg(feature = "rune-core")] -pub mod hash { - #[doc(inline)] - pub use rune_core::hash::{ParametersBuilder, TooManyParameters}; -} - -pub mod support { - pub use anyhow::Error; - pub use anyhow::Result; -} - -#[cfg(feature = "rune-core")] -pub mod runtime { - use rune_core::hash::Hash; - - pub trait TypeHash { - const HASH: Hash; - } - - impl TypeHash for String { - const HASH: Hash = Hash::new(1); - } - - impl TypeHash for i64 { - const HASH: Hash = Hash::new(2); - } -} - -#[cfg(feature = "rune-core")] -pub use self::runtime::TypeHash; - -#[cfg(feature = "rune-core")] -pub use rune_core::item::{Item, ItemBuf}; diff --git a/crates/rune-tracing-macros/Cargo.toml b/crates/rune-tracing-macros/Cargo.toml index b6a46e4b8..b5e926313 100644 --- a/crates/rune-tracing-macros/Cargo.toml +++ b/crates/rune-tracing-macros/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-tracing-macros" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "Macros for tracing the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-tracing-macros/src/lib.rs b/crates/rune-tracing-macros/src/lib.rs index 348b98cdf..86e3895b5 100644 --- a/crates/rune-tracing-macros/src/lib.rs +++ b/crates/rune-tracing-macros/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-tracing/Cargo.toml b/crates/rune-tracing/Cargo.toml index 3134713ab..0411666fd 100644 --- a/crates/rune-tracing/Cargo.toml +++ b/crates/rune-tracing/Cargo.toml @@ -3,7 +3,7 @@ name = "rune-tracing" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "Rune tracing shims for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" diff --git a/crates/rune-tracing/src/lib.rs b/crates/rune-tracing/src/lib.rs index 27fc111f3..3f2a2adcf 100644 --- a/crates/rune-tracing/src/lib.rs +++ b/crates/rune-tracing/src/lib.rs @@ -5,7 +5,7 @@ //! docs.rs //! chat on discord //!
-//! Minimum support: Rust 1.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 diff --git a/crates/rune-wasm/Cargo.toml b/crates/rune-wasm/Cargo.toml index af3e1d0a0..55ef1ee96 100644 --- a/crates/rune-wasm/Cargo.toml +++ b/crates/rune-wasm/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "rune-wasm" -version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "A WASM module for the Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -12,6 +11,7 @@ repository = "https://github.com/rune-rs/rune" license = "MIT OR Apache-2.0" keywords = ["language", "scripting", "scripting-language"] categories = ["parser-implementations"] +publish = false [dependencies] rune = { version = "0.14.0", path = "../rune", features = ["capture-io"] } diff --git a/crates/rune-wasm/src/lib.rs b/crates/rune-wasm/src/lib.rs index 4c79ea5b5..f417b4f6e 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 @@ -37,7 +37,7 @@ use rune::ast::Spanned; use rune::compile::LinkerError; use rune::diagnostics::{Diagnostic, FatalDiagnosticKind}; use rune::modules::capture_io::CaptureIo; -use rune::runtime::{budget, VmResult}; +use rune::runtime::budget; use rune::{Context, ContextError, Options}; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -307,8 +307,8 @@ async fn inner_compile( let future = budget::with(budget, execution.async_complete()); let output = match future.await { - VmResult::Ok(output) => output, - VmResult::Err(error) => { + Ok(output) => output, + Err(error) => { let vm = execution.vm(); let (unit, ip) = match error.first_location() { diff --git a/crates/rune-wasm/src/time.rs b/crates/rune-wasm/src/time.rs index 5414f0f9f..d9f5eee96 100644 --- a/crates/rune-wasm/src/time.rs +++ b/crates/rune-wasm/src/time.rs @@ -1,6 +1,5 @@ use js_sys::Promise; -use rune::runtime::VmResult; -use rune::{Any, ContextError, Module}; +use rune::{Any, ContextError, Module, VmError}; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::JsFuture; @@ -11,13 +10,12 @@ extern "C" { /// The wasm 'time' module. pub fn module() -> Result { - let mut module = Module::with_crate("time")?; - module.ty::()?; - module - .function("from_secs", Duration::from_secs) + let mut m = Module::with_crate("time")?; + m.ty::()?; + m.function("from_secs", Duration::from_secs) .build_associated::()?; - module.function("sleep", sleep).build()?; - Ok(module) + m.function("sleep", sleep).build()?; + Ok(m) } #[derive(Any)] @@ -30,13 +28,13 @@ impl Duration { } } -async fn sleep(duration: Duration) -> VmResult<()> { +async fn sleep(duration: Duration) -> Result<(), VmError> { let promise = js_sleep(duration.0); let js_fut = JsFuture::from(promise); if js_fut.await.is_err() { - return VmResult::panic("Sleep errored"); + return Err(VmError::panic("Sleep errored")); } - VmResult::Ok(()) + Ok(()) } diff --git a/crates/rune/Cargo.toml b/crates/rune/Cargo.toml index 557a6155c..bc958a4e6 100644 --- a/crates/rune/Cargo.toml +++ b/crates/rune/Cargo.toml @@ -3,7 +3,7 @@ name = "rune" version = "0.14.0" authors = ["John-John Tedro "] edition = "2021" -rust-version = "1.81" +rust-version = "1.87" description = "The Rune Language, an embeddable dynamic programming language for Rust." documentation = "https://docs.rs/rune" readme = "README.md" @@ -17,25 +17,27 @@ categories = ["parser-implementations"] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(rune_nightly, rune_docsrs, rune_byte_code)'] } [features] -default = ["emit", "std"] +default = ["emit", "std", "anyhow"] tracing = ["tracing/enabled"] -emit = ["std", "codespan-reporting"] +emit = ["std", "anyhow", "codespan-reporting"] bench = [] -workspace = ["std", "toml", "semver", "relative-path", "serde-hashkey", "linked-hash-map"] -doc = ["std", "rust-embed", "handlebars", "pulldown-cmark", "pulldown-cmark-escape", "syntect", "sha2", "base64", "rune-core/doc", "relative-path"] -cli = ["std", "emit", "doc", "bincode", "tracing-subscriber", "clap", "webbrowser", "capture-io", "disable-io", "languageserver", "fmt", "similar", "rand"] -languageserver = ["std", "lsp", "ropey", "percent-encoding", "url", "serde_json", "tokio", "workspace", "doc", "fmt"] -byte-code = ["alloc", "musli/storage"] +workspace = ["std", "anyhow", "toml", "semver", "relative-path", "serde-hashkey", "linked-hash-map"] +doc = ["std", "anyhow", "rust-embed", "handlebars", "pulldown-cmark", "pulldown-cmark-escape", "syntect", "sha2", "base64", "rune-core/doc", "relative-path"] +cli = ["std", "anyhow", "emit", "doc", "tracing-subscriber", "clap", "webbrowser", "capture-io", "disable-io", "languageserver", "fmt", "similar", "rand", "musli/storage"] +languageserver = ["std", "anyhow", "lsp", "ropey", "percent-encoding", "url", "serde_json", "tokio", "workspace", "doc", "fmt"] +byte-code = ["alloc", "musli/storage", "musli/std", "rune-alloc/std"] capture-io = ["alloc", "parking_lot"] disable-io = ["alloc"] -fmt = ["alloc"] -std = ["alloc", "num/std", "serde/std", "rune-core/std", "rune-alloc/std", "musli/std", "musli/std", "once_cell/std", "anyhow/std", "syntree/std"] -alloc = ["anyhow", "rune-alloc/alloc", "rune-core/alloc", "once_cell/alloc", "serde/alloc"] +fmt = ["alloc", "anyhow"] +std = ["alloc", "num/std", "serde/std", "rune-core/std", "rune-alloc/std", "musli?/std", "once_cell/std", "anyhow?/std", "syntree/std"] +alloc = ["rune-alloc/alloc", "rune-core/alloc", "once_cell/alloc", "serde?/alloc"] +musli = ["dep:musli", "rune-core/musli", "rune-alloc/musli"] +serde = ["dep:serde", "rune-alloc/serde", "relative-path?/serde"] [dependencies] rune-macros = { version = "=0.14.0", path = "../rune-macros" } -rune-core = { version = "=0.14.0", path = "../rune-core", features = ["musli"] } -rune-alloc = { version = "0.14.0", path = "../rune-alloc", features = ["serde"], default-features = false } +rune-core = { version = "=0.14.0", path = "../rune-core", features = [] } +rune-alloc = { version = "0.14.0", path = "../rune-alloc", features = [], default-features = false } tracing = { package = "rune-tracing", version = "0.14.0", path = "../rune-tracing" } syntree = { version = "0.18.0", default-features = false, features = ["alloc"] } @@ -45,22 +47,21 @@ itoa = "1.0.6" num = { version = "0.4.0", default-features = false, features = ["alloc"] } pin-project = "1.1.0" ryu = "1.0.13" -serde = { version = "1.0.163", default-features = false, features = ["derive", "rc"] } -musli = { version = "0.0.124", default-features = false, features = ["alloc"] } +serde = { version = "1.0.163", default-features = false, optional = true, features = ["derive", "rc"] } +musli = { version = "0.0.131", default-features = false, optional = true, features = ["alloc"] } once_cell = { version = "1.18.0", default-features = false, features = ["critical-section"] } anyhow = { version = "1.0.71", default-features = false, optional = true } -bincode = { version = "1.3.3", optional = true } clap = { version = "4.2.7", features = ["derive"], optional = true } codespan-reporting = { version = "0.11.1", optional = true } handlebars = { version = "6.0.0", optional = true } pulldown-cmark = { version = "0.12.2", optional = true } pulldown-cmark-escape = { version = "0.11.0", optional = true } -relative-path = { version = "1.8.0", optional = true, features = ["serde"] } +relative-path = { version = "2.0.1", optional = true, features = ["serde"] } rust-embed = { version = "6.8.1", optional = true } semver = { version = "1.0.17", optional = true, features = ["serde"] } serde-hashkey = { version = "0.4.5", optional = true } -syntect = { version = "5.0.0", optional = true } +syntect = { version = "5.2.0", optional = true, default-features = false, features = ["default-fancy"] } tokio = { version = "1.28.1", features = ["rt-multi-thread", "fs", "macros", "sync", "io-std", "io-util"], optional = true } toml = { version = "0.8.19", optional = true, features = ["parse"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"], optional = true } @@ -75,8 +76,7 @@ linked-hash-map = { version = "0.5.6", optional = true } similar = { version = "2.2.1", optional = true, features = ["inline", "bytes"] } sha2 = { version = "0.10.6", optional = true } base64 = { version = "0.22.0", optional = true } -rand = { version = "0.8.5", optional = true } -memchr = "2.7.4" +rand = { version = "0.9.1", optional = true } unicode-ident = "1.0.12" [dev-dependencies] diff --git a/crates/rune/src/any.rs b/crates/rune/src/any.rs index 5b44b2fc4..500ef851e 100644 --- a/crates/rune/src/any.rs +++ b/crates/rune/src/any.rs @@ -3,77 +3,25 @@ use core::any; use crate::compile::Named; use crate::runtime::{AnyTypeInfo, TypeHash}; -/// Macro to mark a value as external, which will implement all the appropriate -/// traits. -/// -/// This is required to support the external type as a type argument in a -/// registered function. -/// -/// ## `#[rune(item = )]` -/// -/// Specify the item prefix which contains this time. -/// -/// This is required in order to calculate the correct type hash, if this is -/// omitted and the item is defined in a nested module the type hash won't match -/// the expected path hash. -/// -/// ``` -/// use rune::Any; -/// -/// #[derive(Any)] -/// #[rune(item = ::process)] -/// struct Process { -/// /* .. */ -/// } -/// -/// fn install() -> Result { -/// let mut module = rune::Module::with_crate("process")?; -/// module.ty::()?; -/// Ok(module) -/// } -/// ``` +/// The trait implemented for types which can be used inside of Rune. /// -/// ## `#[rune(name = )]` attribute +/// This can only be implemented correctly through the [`Any`] derive. +/// Implementing it manually is not supported. /// -/// The name of a type defaults to its identifiers, so `struct Foo {}` would be -/// given the name `Foo`. -/// -/// This can be overrided with the `#[rune(name = )]` attribute: -/// -/// ``` -/// use rune::Any; -/// -/// #[derive(Any)] -/// #[rune(name = Bar)] -/// struct Foo { -/// } -/// -/// fn install() -> Result { -/// let mut module = rune::Module::new(); -/// module.ty::()?; -/// Ok(module) -/// } -/// ``` -pub use rune_macros::Any; - -/// Derive for types which can be used inside of Rune. -/// -/// Rune only supports two types, *built-in* types [`String`] and *external* +/// Rune only supports two types, *built-in* types like [`i64`] and *external* /// types which derive `Any`. Before they can be used they must be registered in /// [`Context::install`] through a [`Module`]. /// /// This is typically used in combination with declarative macros to register -/// functions and macros, such as: -/// -/// * [`#[rune::function]`] -/// * [`#[rune::macro_]`] +/// functions and macros, such as [`rune::function`]. /// /// [`AnyObj`]: crate::runtime::AnyObj /// [`Context::install`]: crate::Context::install /// [`Module`]: crate::Module /// [`String`]: std::string::String -/// [`#[rune::function]`]: macro@crate::function -/// [`#[rune::macro_]`]: crate::macro_ +/// [`rune::function`]: macro@crate::function +/// [`rune::macro_`]: macro@crate::macro_ +/// [`Any`]: derive@crate::Any /// /// # Examples /// @@ -132,5 +80,352 @@ pub trait Any: TypeHash + Named + any::Any { /// Note that you are *not* supposed to implement this directly. Make use of the /// [`Any`] derive instead. /// -/// [`Any`]: derive@Any +/// [`Any`]: derive@crate::Any pub trait AnyMarker: Any {} + +/// Macro to mark a value as external, which will implement all the appropriate +/// traits. +/// +/// This is required to support the external type as a type argument in a +/// registered function. +/// +///
+/// +/// ## Container attributes +/// +///
+/// +/// ### `#[rune(item = )]` +/// +/// Specify the item prefix which contains this time. +/// +/// This is required in order to calculate the correct type hash, if this is +/// omitted and the item is defined in a nested module the type hash won't match +/// the expected path hash. +/// +/// ``` +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// #[rune(item = ::process)] +/// struct Process { +/// /* .. */ +/// } +/// +/// let mut m = Module::with_crate("process")?; +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +///
+/// +/// ### `#[rune(name = )]` attribute +/// +/// The name of a type defaults to its identifiers, so `struct Foo {}` would be +/// given the name `Foo`. +/// +/// This can be overrided with the `#[rune(name = )]` attribute: +/// +/// ``` +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// #[rune(name = Bar)] +/// struct Foo { +/// } +/// +/// let mut m = Module::new(); +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +///
+/// +/// ### `#[rune(empty)]`, `#[rune(unnamed())]` +/// +/// This attribute controls how the metadata of fields are handled in the type. +/// +/// By default fields are registered depending on the type of structure or enum +/// being registered. This prevents the metadata from being further customized +/// through methods such as [`TypeMut::make_empty_struct`] since that would +/// result in duplicate metadata being registered. +/// +/// To avoid this behavior, the `#[rune(fields)]` attribute can be used which +/// suppressed any field metadata from being generated for `none` or customized +/// like `empty`. If set to `none` then it leaves the field metadata free to be +/// configured manually during [`Module::ty`] setup. +/// +/// Registering a type like this allows it to be used like an empty struct like +/// `let v = Struct;` despite having fields: +/// +/// ``` +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// #[rune(empty, constructor = Struct::new)] +/// struct Struct { +/// field: u32, +/// } +/// +/// impl Struct { +/// fn new() -> Self { +/// Self { field: 42 } +/// } +/// } +/// +/// let mut m = Module::new(); +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +/// Support for an unnamed struct: +/// +/// ``` +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// #[rune(unnamed(2), constructor = Struct::new)] +/// struct Struct { +/// a: u32, +/// b: u32, +/// } +/// +/// impl Struct { +/// fn new(a: u32, b: u32) -> Self { +/// Self { a, b } +/// } +/// } +/// +/// let mut m = Module::new(); +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +/// +///
+/// +/// ### `#[rune(constructor)]` +/// +/// This allows for specifying that a type has a rune-visible constructor, and +/// which method should be called to construct the value. +/// +/// A constructor in this instance means supporting expressions such as: +/// +/// * `Struct { field: 42 }` for named structs. +/// * `Struct(42)` for unnamed structs. +/// * `Struct` for empty structs. +/// +/// By default the attribute will generate a constructor out of every field +/// which is marked with `#[rune(get)]`. The remaining fields must then +/// implement [`Default`]. +/// +/// ``` +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// #[rune(constructor)] +/// struct Struct { +/// #[rune(get)] +/// a: u32, +/// b: u32, +/// } +/// +/// let mut m = Module::new(); +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +/// For fine-grained control over the constructor, `#[rune(constructor = +/// )]` can be used. +/// +/// ``` +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// #[rune(empty, constructor = Struct::new)] +/// struct Struct { +/// field: u32, +/// } +/// +/// impl Struct { +/// fn new() -> Self { +/// Self { field: 42 } +/// } +/// } +/// +/// let mut m = Module::new(); +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +/// ## Field attributes +/// +///
+/// +/// ### Field functions +/// +/// Field functions are special operations which operate on fields. These are +/// distinct from associated functions, because they are invoked by using the +/// operation associated with the kind of the field function. +/// +/// The most common forms of fields functions are *getters* and *setters*, which +/// are defined through the [`Protocol::GET`] and [`Protocol::SET`] protocols. +/// +/// The `Any` derive can also generate default implementations of these through +/// various `#[rune(...)]` attributes: +/// +/// ```rust +/// use rune::{Any, Module}; +/// +/// #[derive(Any)] +/// struct Struct { +/// #[rune(get, set, add_assign, copy)] +/// number: i64, +/// #[rune(get, set)] +/// string: String, +/// } +/// +/// let mut m = Module::new(); +/// m.ty::()?; +/// # Ok::<_, rune::ContextError>(()) +/// ``` +/// +/// Once registered, this allows `External` to be used like this in Rune: +/// +/// ```rune +/// pub fn main(external) { +/// external.number = external.number + 1; +/// external.number += 1; +/// external.string = `${external.string} World`; +/// } +/// ``` +/// +/// The full list of available field functions and their corresponding +/// attributes are: +/// +/// | Protocol | Attribute | | +/// |-|-|-| +/// | [`Protocol::GET`] | `#[rune(get)]` | For getters, like `external.field`. | +/// | [`Protocol::SET`] | `#[rune(set)]` | For setters, like `external.field = 42`. | +/// | [`Protocol::ADD_ASSIGN`] | `#[rune(add_assign)]` | The `+=` operation. | +/// | [`Protocol::SUB_ASSIGN`] | `#[rune(sub_assign)]` | The `-=` operation. | +/// | [`Protocol::MUL_ASSIGN`] | `#[rune(mul_assign)]` | The `*=` operation. | +/// | [`Protocol::DIV_ASSIGN`] | `#[rune(div_assign)]` | The `/=` operation. | +/// | [`Protocol::BIT_AND_ASSIGN`] | `#[rune(bit_and_assign)]` | The `&=` operation. | +/// | [`Protocol::BIT_OR_ASSIGN`] | `#[rune(bit_or_assign)]` | The bitwise or operation. | +/// | [`Protocol::BIT_XOR_ASSIGN`] | `#[rune(bit_xor_assign)]` | The `^=` operation. | +/// | [`Protocol::SHL_ASSIGN`] | `#[rune(shl_assign)]` | The `<<=` operation. | +/// | [`Protocol::SHR_ASSIGN`] | `#[rune(shr_assign)]` | The `>>=` operation. | +/// | [`Protocol::REM_ASSIGN`] | `#[rune(rem_assign)]` | The `%=` operation. | +/// +/// The manual way to register these functions is to use the new +/// `Module::field_function` function. This clearly showcases that there's no +/// relationship between the field used and the function registered: +/// +/// ```rust +/// use rune::{Any, Module}; +/// use rune::runtime::Protocol; +/// +/// #[derive(Any)] +/// struct External { +/// } +/// +/// impl External { +/// fn field_get(&self) -> String { +/// String::from("Hello World") +/// } +/// } +/// +/// let mut module = Module::new(); +/// module.field_function(&Protocol::GET, "field", External::field_get)?; +/// # Ok::<_, rune::support::Error>(()) +/// ``` +/// +/// Would allow for this in Rune: +/// +/// ```rune +/// pub fn main(external) { +/// println!("{}", external.field); +/// } +/// ``` +/// +/// ### Customizing how fields are cloned with `#[rune(get)]` +/// +/// In order to return a value through `#[rune(get)]`, the value has to be +/// cloned. +/// +/// By default, this is done through the [`TryClone` trait], but its behavior +/// can be customized through the following attributes: +/// +///
+/// +/// ### `#[rune(copy)]` +/// +/// This indicates that the field is `Copy`. +/// +///
+/// +/// ### `#[rune(clone)]` +/// +/// This indicates that the field should use `std::clone::Clone` to clone the +/// value. Note that this effecitvely means that the memory the value uses +/// during cloning is *not* tracked and should be avoided in favor of using +/// [`rune::alloc`] and the [`TryClone` trait] without good reason. +/// +///
+/// +/// ### `#[rune(clone_with = )]` +/// +/// This specified a custom method that should be used to clone the value. +/// +/// ```rust +/// use rune::Any; +/// +/// use std::sync::Arc; +/// +/// #[derive(Any)] +/// struct External { +/// #[rune(get, clone_with = Inner::clone)] +/// field: Inner, +/// } +/// +/// #[derive(Any, Clone)] +/// struct Inner { +/// name: Arc, +/// } +/// ``` +/// +///
+/// +/// ### `#[rune(try_clone_with = )]` +/// +/// This specified a custom method that should be used to clone the value. +/// +/// ```rust +/// use rune::Any; +/// use rune::alloc::prelude::*; +/// +/// #[derive(Any)] +/// struct External { +/// #[rune(get, try_clone_with = String::try_clone)] +/// field: String, +/// } +/// ``` +/// +/// [`Module::ty`]: crate::Module::ty +/// [`Protocol::ADD_ASSIGN`]: crate::runtime::Protocol::ADD_ASSIGN +/// [`Protocol::BIT_AND_ASSIGN`]: crate::runtime::Protocol::BIT_AND_ASSIGN +/// [`Protocol::BIT_OR_ASSIGN`]: crate::runtime::Protocol::BIT_OR_ASSIGN +/// [`Protocol::BIT_XOR_ASSIGN`]: crate::runtime::Protocol::BIT_XOR_ASSIGN +/// [`Protocol::DIV_ASSIGN`]: crate::runtime::Protocol::DIV_ASSIGN +/// [`Protocol::GET`]: crate::runtime::Protocol::GET +/// [`Protocol::MUL_ASSIGN`]: crate::runtime::Protocol::MUL_ASSIGN +/// [`Protocol::REM_ASSIGN`]: crate::runtime::Protocol::REM_ASSIGN +/// [`Protocol::SET`]: crate::runtime::Protocol::SET +/// [`Protocol::SHL_ASSIGN`]: crate::runtime::Protocol::SHL_ASSIGN +/// [`Protocol::SHR_ASSIGN`]: crate::runtime::Protocol::SHR_ASSIGN +/// [`Protocol::SUB_ASSIGN`]: crate::runtime::Protocol::SUB_ASSIGN +/// [`rune::alloc`]: crate::alloc +/// [`TryClone` trait]: crate::alloc::clone::TryClone +/// [`TypeMut::make_empty_struct`]: crate::module::TypeMut::make_empty_struct +pub use rune_macros::Any; diff --git a/crates/rune/src/ast/local.rs b/crates/rune/src/ast/local.rs index 0cbf198b3..e44f489f4 100644 --- a/crates/rune/src/ast/local.rs +++ b/crates/rune/src/ast/local.rs @@ -27,7 +27,7 @@ pub struct Local { /// The equality keyword. pub eq: T![=], /// The expression the binding is assigned to. - #[rune(parse_with = "parse_expr")] + #[rune(parse_with = parse_expr)] pub expr: ast::Expr, /// Trailing semicolon of the local. pub semi: T![;], diff --git a/crates/rune/src/ast/span.rs b/crates/rune/src/ast/span.rs index d578431be..ceca9d25a 100644 --- a/crates/rune/src/ast/span.rs +++ b/crates/rune/src/ast/span.rs @@ -2,12 +2,16 @@ use core::cmp; use core::fmt; use core::ops; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate::ast::prelude::*; /// A span corresponding to a range in the source file being parsed. #[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] #[try_clone(copy)] pub struct Span { /// The start of the span in bytes. @@ -168,7 +172,9 @@ impl Span { } } +#[cfg(feature = "serde")] impl Serialize for Span { + #[inline] fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, @@ -177,7 +183,9 @@ impl Serialize for Span { } } +#[cfg(feature = "serde")] impl<'de> Deserialize<'de> for Span { + #[inline] fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -200,11 +208,10 @@ impl fmt::Debug for Span { } /// A single index in a [Span], like the start or ending index. -#[derive( - Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, -)] +#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] -#[serde(transparent)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Encode, Decode), musli(transparent))] #[try_clone(copy)] pub struct ByteIndex(#[doc(hidden)] pub u32); diff --git a/crates/rune/src/ast/spanned.rs b/crates/rune/src/ast/spanned.rs index aba6aacec..5d170f136 100644 --- a/crates/rune/src/ast/spanned.rs +++ b/crates/rune/src/ast/spanned.rs @@ -2,12 +2,12 @@ use crate::alloc; use crate::ast::Span; use crate::parse::NonZeroId; -/// Helper derive to implement [`Spanned`]. -pub use rune_macros::Spanned; - /// Helper derive to implement [`OptionSpanned`]. pub use rune_macros::OptionSpanned; +/// Helper derive to implement [`Spanned`]. +pub use rune_macros::Spanned; + /// Defer building a span from a function. pub(crate) fn from_fn(function: F) -> FromFn { FromFn { function } @@ -61,20 +61,11 @@ impl Spanned for Span { } } -#[cfg(feature = "alloc")] -impl Spanned for ::rust_alloc::boxed::Box -where - T: Spanned, -{ - fn span(&self) -> Span { - Spanned::span(&**self) - } -} - impl Spanned for alloc::Box where T: Spanned, { + #[inline] fn span(&self) -> Span { Spanned::span(&**self) } @@ -134,25 +125,17 @@ impl OptionSpanned for Option where T: Spanned, { + #[inline] fn option_span(&self) -> Option { Some(self.as_ref()?.span()) } } -#[cfg(feature = "alloc")] -impl OptionSpanned for ::rust_alloc::boxed::Box -where - T: OptionSpanned, -{ - fn option_span(&self) -> Option { - OptionSpanned::option_span(&**self) - } -} - impl OptionSpanned for alloc::Box where T: OptionSpanned, { + #[inline] fn option_span(&self) -> Option { OptionSpanned::option_span(&**self) } diff --git a/crates/rune/src/build.rs b/crates/rune/src/build.rs index ce7f5293d..786bbfefc 100644 --- a/crates/rune/src/build.rs +++ b/crates/rune/src/build.rs @@ -25,6 +25,7 @@ pub struct BuildError { } impl From for BuildError { + #[inline] fn from(error: ParseOptionError) -> Self { Self { kind: BuildErrorKind::ParseOptionError(error), @@ -33,6 +34,7 @@ impl From for BuildError { } impl From for BuildError { + #[inline] fn from(error: alloc::Error) -> Self { Self { kind: BuildErrorKind::Alloc(error), diff --git a/crates/rune/src/cli/benches.rs b/crates/rune/src/cli/benches.rs index 7ff0ea206..24bab35b4 100644 --- a/crates/rune/src/cli/benches.rs +++ b/crates/rune/src/cli/benches.rs @@ -160,7 +160,7 @@ fn bench_fn(io: &mut Io<'_>, item: &dyn fmt::Display, args: &Flags, f: &Function let mut warmup = 0; let elapsed = loop { - let value = f.call::(()).into_result()?; + let value = f.call::(())?; drop(hint::black_box(value)); warmup += 1; @@ -195,7 +195,7 @@ fn bench_fn(io: &mut Io<'_>, item: &dyn fmt::Display, args: &Flags, f: &Function } let start = Instant::now(); - let value = f.call::(()).into_result()?; + let value = f.call::(())?; let duration = Instant::now().duration_since(start); collected.try_push(duration.as_nanos() as i128)?; drop(hint::black_box(value)); diff --git a/crates/rune/src/cli/doc.rs b/crates/rune/src/cli/doc.rs index 2165aab98..f8579841d 100644 --- a/crates/rune/src/cli/doc.rs +++ b/crates/rune/src/cli/doc.rs @@ -97,7 +97,7 @@ where let mut options = options.clone(); if e.is_argument() { - options.function_body = true; + options.script = true; } let item = naming.item(&e)?; diff --git a/crates/rune/src/cli/loader.rs b/crates/rune/src/cli/loader.rs index 05c849423..137b1c8b4 100644 --- a/crates/rune/src/cli/loader.rs +++ b/crates/rune/src/cli/loader.rs @@ -38,9 +38,9 @@ pub(super) fn load( // TODO: how do we deal with tests discovery for bytecode loading let maybe_unit = if use_cache { - let f = fs::File::open(&bytecode_path)?; + let f = fs::read(&bytecode_path)?; - match bincode::deserialize_from::<_, Unit>(f) { + match musli::storage::from_slice::(&f[..]) { Ok(unit) => { tracing::trace!("Using cache: {}", bytecode_path.display()); Some(Arc::new(unit)) @@ -86,7 +86,7 @@ pub(super) fn load( if options.bytecode { tracing::trace!("serializing cache: {}", bytecode_path.display()); let f = fs::File::create(&bytecode_path)?; - bincode::serialize_into(f, &unit)?; + musli::storage::to_writer(f, &unit)?; } (Arc::new(unit), functions.into_functions()) diff --git a/crates/rune/src/cli/mod.rs b/crates/rune/src/cli/mod.rs index 58a974d1b..fa6619173 100644 --- a/crates/rune/src/cli/mod.rs +++ b/crates/rune/src/cli/mod.rs @@ -921,7 +921,7 @@ where let mut options = options.clone(); if e.is_argument() { - options.function_body = true; + options.script = true; } match check::run(io, entry, c, &f.command, &f.shared, &options, e.path())? { @@ -957,7 +957,7 @@ where let mut options = options.clone(); if e.is_argument() { - options.function_body = true; + options.script = true; } let capture_io = crate::modules::capture_io::CaptureIo::new(); @@ -996,7 +996,7 @@ where let mut options = options.clone(); if e.is_argument() { - options.function_body = true; + options.script = true; } let load = loader::load( @@ -1029,9 +1029,10 @@ where use rand::prelude::*; if args.random { + let mut rand = rand::rng(); + for _ in 0..args.count.unwrap_or(1) { - let mut rand = rand::thread_rng(); - writeln!(io.stdout, "{}", Hash::new(rand.gen::()))?; + writeln!(io.stdout, "{}", Hash::new(rand.random::()))?; } } diff --git a/crates/rune/src/cli/run.rs b/crates/rune/src/cli/run.rs index ee1f1573f..8dfba307d 100644 --- a/crates/rune/src/cli/run.rs +++ b/crates/rune/src/cli/run.rs @@ -6,7 +6,7 @@ use std::time::Instant; use anyhow::{anyhow, Result}; use crate::cli::{AssetKind, CommandBase, Config, ExitCode, Io, SharedFlags}; -use crate::runtime::{UnitStorage, VmError, VmExecution, VmResult}; +use crate::runtime::{UnitStorage, VmError, VmExecution, VmOutcome}; use crate::{Context, Hash, Sources, Unit, Value, Vm}; mod cli { @@ -112,6 +112,10 @@ impl CommandBase for Flags { if self.trace_limit.is_some() { self.trace = true; } + + if self.trace { + self.dump_return = true; + } } fn paths(&self) -> &[PathBuf] { @@ -257,17 +261,17 @@ pub(super) async fn run( ) .await { - Ok(value) => VmResult::Ok(value), + Ok(value) => Ok(value), Err(TraceError::Io(io)) => return Err(io.into()), - Err(TraceError::VmError(vm)) => VmResult::Err(vm), + Err(TraceError::VmError(vm)) => Err(vm), Err(TraceError::Limited) => return Err(anyhow!("Trace limit reached")), } } else { - execution.async_complete().await + execution.resume().await.and_then(VmOutcome::into_complete) }; let errored = match result { - VmResult::Ok(result) => { + Ok(result) => { if c.verbose || args.time || args.dump_return { let duration = Instant::now().saturating_duration_since(last); @@ -278,7 +282,7 @@ pub(super) async fn run( None } - VmResult::Err(error) => { + Err(error) => { if c.verbose || args.time || args.dump_return { let duration = Instant::now().saturating_duration_since(last); @@ -365,13 +369,18 @@ where T: AsRef + AsMut, { let mut current_frame_len = execution.vm().call_frames().len(); - let mut result = VmResult::Ok(None); + let mut result = None; + let mut yielded = None; while limit > 0 { let vm = execution.vm(); let ip = vm.ip(); let mut o = io.stdout.lock(); + if let Some(value) = yielded.take() { + vm.with(|| writeln!(o, "yield: {value:?}"))?; + } + if let Some((hash, signature)) = vm.unit().debug_info().and_then(|d| d.function_at(ip)) { writeln!(o, "fn {} ({}):", signature, hash)?; } @@ -441,25 +450,22 @@ where } } - match result { - VmResult::Ok(result) => { - if let Some(result) = result { - return Ok(result); - } - } - VmResult::Err(error) => { - return Err(TraceError::VmError(error)); - } + if let Some(value) = result { + return Ok(value); } - result = execution.async_step().await; - - result = match result { - VmResult::Err(error) => { + match execution.resume().with_budget(1).await { + Ok(VmOutcome::Complete(value)) => { + result = Some(value); + } + Ok(VmOutcome::Yielded(value)) => { + yielded = Some(value); + } + Ok(VmOutcome::Limited) => {} + Err(error) => { return Err(TraceError::VmError(error)); } - result => result, - }; + } limit = limit.wrapping_sub(1); } diff --git a/crates/rune/src/cli/tests.rs b/crates/rune/src/cli/tests.rs index 5beba8d63..f684c28a2 100644 --- a/crates/rune/src/cli/tests.rs +++ b/crates/rune/src/cli/tests.rs @@ -18,7 +18,7 @@ use crate::cli::{ use crate::compile::FileSourceLoader; use crate::doc::{TestKind, TestParams}; use crate::modules::capture_io::CaptureIo; -use crate::runtime::{Repr, Value, Vm, VmError, VmResult}; +use crate::runtime::{Repr, Value, Vm, VmError, VmOutcome}; use crate::{Diagnostics, Hash, Item, ItemBuf, Source, Sources, TypeHash, Unit}; mod cli { @@ -146,7 +146,7 @@ where let mut options = options.clone(); if e.is_argument() { - options.function_body = true; + options.script = true; } let item = naming.item(&e)?; @@ -439,7 +439,7 @@ fn populate_doc_tests( let mut source_loader = FileSourceLoader::new(); let mut options = options.clone(); - options.function_body = true; + options.script = true; let unit = crate::prepare(&mut sources) .with_context(context) @@ -527,14 +527,14 @@ impl TestCase { async fn execute(&mut self, vm: &mut Vm, capture_io: &CaptureIo) -> Result<()> { let result = match vm.execute(self.hash, ()) { - Ok(mut execution) => execution.async_complete().await, - Err(err) => VmResult::Err(err), + Ok(mut execution) => execution.resume().await.and_then(VmOutcome::into_complete), + Err(err) => Err(err), }; capture_io.drain_into(&mut self.output)?; self.outcome = match result { - VmResult::Ok(v) => match v.as_ref() { + Ok(v) => match v.as_ref() { Repr::Any(value) => match value.type_hash() { Result::::HASH => { let result = value.borrow_ref::>()?; @@ -556,7 +556,7 @@ impl TestCase { }, _ => Outcome::Ok, }, - VmResult::Err(e) => Outcome::Panic(e), + Err(e) => Outcome::Panic(e), }; if self.params.should_panic { diff --git a/crates/rune/src/compile/assembly.rs b/crates/rune/src/compile/assembly.rs index 4c844fec1..8799a15fa 100644 --- a/crates/rune/src/compile/assembly.rs +++ b/crates/rune/src/compile/assembly.rs @@ -8,7 +8,8 @@ use crate::alloc::prelude::*; use crate::alloc::{hash_map, HashMap}; use crate::ast::{Span, Spanned}; use crate::compile::{self, Location}; -use crate::runtime::{Inst, InstAddress, Label, Output}; +use crate::runtime::inst; +use crate::runtime::{Address, Label, Output}; use crate::{Hash, SourceId}; #[derive(Debug, TryClone)] @@ -17,20 +18,20 @@ pub(crate) enum AssemblyInst { label: Label, }, JumpIf { - addr: InstAddress, + addr: Address, label: Label, }, JumpIfNot { - addr: InstAddress, + addr: Address, label: Label, }, IterNext { - addr: InstAddress, + addr: Address, label: Label, out: Output, }, Raw { - raw: Inst, + raw: inst::Kind, }, } @@ -105,7 +106,7 @@ impl Assembly { /// Add a conditional jump to the given label. pub(crate) fn jump_if( &mut self, - addr: InstAddress, + addr: Address, label: &Label, span: &dyn Spanned, ) -> compile::Result<()> { @@ -123,7 +124,7 @@ impl Assembly { /// Add jump-if-not instruction to a label. pub(crate) fn jump_if_not( &mut self, - addr: InstAddress, + addr: Address, label: &Label, span: &dyn Spanned, ) -> compile::Result<()> { @@ -141,7 +142,7 @@ impl Assembly { /// Add an instruction that advanced an iterator. pub(crate) fn iter_next( &mut self, - addr: InstAddress, + addr: Address, label: &Label, span: &dyn Spanned, out: Output, @@ -159,7 +160,7 @@ impl Assembly { } /// Push a raw instruction. - pub(crate) fn push(&mut self, raw: Inst, span: &dyn Spanned) -> compile::Result<()> { + pub(crate) fn push(&mut self, raw: inst::Kind, span: &dyn Spanned) -> compile::Result<()> { self.inner_push(AssemblyInst::Raw { raw }, span)?; Ok(()) } @@ -167,7 +168,7 @@ impl Assembly { /// Push a raw instruction. pub(crate) fn push_with_comment( &mut self, - raw: Inst, + raw: inst::Kind, span: &dyn Spanned, comment: &dyn fmt::Display, ) -> compile::Result<()> { @@ -185,7 +186,7 @@ impl Assembly { fn inner_push(&mut self, inst: AssemblyInst, span: &dyn Spanned) -> compile::Result<()> { if let AssemblyInst::Raw { - raw: Inst::Call { hash, .. }, + raw: inst::Kind::Call { hash, .. }, } = &inst { self.required_functions diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index 71c371633..d7fde759a 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -1,6 +1,6 @@ use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc::prelude::*; @@ -20,8 +20,8 @@ use crate::module::{ TypeSpecification, }; use crate::runtime::{ - AnyTypeInfo, ConstConstruct, ConstContext, ConstValue, FunctionHandler, InstAddress, Memory, - Output, Protocol, Rtti, RttiKind, RuntimeContext, TypeCheck, TypeInfo, VmResult, + Address, AnyTypeInfo, ConstConstruct, ConstContext, ConstValue, FunctionHandler, Memory, + Output, Protocol, Rtti, RttiKind, RuntimeContext, TypeCheck, TypeInfo, VmError, }; use crate::{Hash, Item, ItemBuf}; @@ -68,10 +68,7 @@ impl TraitContext<'_> { /// Find the given protocol function for the current type. /// /// This requires that the function is defined. - pub fn find( - &mut self, - protocol: &'static Protocol, - ) -> Result, ContextError> { + pub fn find(&mut self, protocol: &'static Protocol) -> Result { let name = protocol.to_instance()?; let hash = name @@ -101,10 +98,7 @@ impl TraitContext<'_> { /// Try to find the given associated function. /// /// This does not require that the function is defined. - pub fn try_find( - &self, - name: impl ToInstance, - ) -> Result>, ContextError> { + pub fn try_find(&self, name: impl ToInstance) -> Result, ContextError> { let name = name.to_instance()?; let hash = name @@ -120,7 +114,7 @@ impl TraitContext<'_> { &mut self, protocol: &'static Protocol, function: F, - ) -> Result, ContextError> + ) -> Result where F: Function, { @@ -142,13 +136,15 @@ impl TraitContext<'_> { &mut self, name: impl ToInstance, handler: F, - ) -> Result, ContextError> + ) -> Result where F: Function, { - self.raw_function(name, move |memory, addr, len, out| { - handler.fn_call(memory, addr, len, out) - }) + let handler = FunctionHandler::new(move |memory, addr, len, out| { + handler.call(memory, addr, len, out) + })?; + self.function_handler(name, &handler)?; + Ok(handler) } /// Define a new associated raw function for the current type. @@ -156,11 +152,14 @@ impl TraitContext<'_> { &mut self, name: impl ToInstance, handler: F, - ) -> Result, ContextError> + ) -> Result where - F: 'static + Fn(&mut dyn Memory, InstAddress, usize, Output) -> VmResult<()> + Send + Sync, + F: 'static + + Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError> + + Send + + Sync, { - let handler: Arc = Arc::new(handler); + let handler = FunctionHandler::new(handler)?; self.function_handler(name, &handler)?; Ok(handler) } @@ -170,7 +169,7 @@ impl TraitContext<'_> { fn function_handler( &mut self, name: impl ToInstance, - handler: &Arc, + handler: &FunctionHandler, ) -> Result<(), ContextError> { let name = name.to_instance()?; self.function_inner(name, handler) @@ -179,7 +178,7 @@ impl TraitContext<'_> { fn function_inner( &mut self, name: AssociatedName, - handler: &Arc, + handler: &FunctionHandler, ) -> Result<(), ContextError> { let function = ModuleFunction { handler: handler.clone(), @@ -284,7 +283,7 @@ pub struct Context { /// Store item to hash mapping. item_to_hash: HashMap>, /// Registered native function handlers. - functions: hash::Map>, + functions: hash::Map, /// Registered deprecation mesages for native functions. deprecations: hash::Map, /// Information on associated types. @@ -349,11 +348,8 @@ impl Context { this.install(crate::modules::bytes::module()?)?; this.install(crate::modules::collections::module()?)?; - #[cfg(feature = "alloc")] this.install(crate::modules::collections::hash_map::module()?)?; - #[cfg(feature = "alloc")] this.install(crate::modules::collections::hash_set::module()?)?; - #[cfg(feature = "alloc")] this.install(crate::modules::collections::vec_deque::module()?)?; this.install(crate::modules::char::module()?)?; @@ -554,7 +550,7 @@ impl Context { } /// Lookup the given native function handler in the context. - pub(crate) fn lookup_function(&self, hash: Hash) -> Option<&Arc> { + pub(crate) fn lookup_function(&self, hash: Hash) -> Option<&FunctionHandler> { self.functions.get(&hash) } @@ -733,7 +729,15 @@ impl Context { return_type: meta::DocType::new(ty.hash), }; - self.insert_native_fn(&ty.type_info, ty.hash, c, None)?; + if c.args != fields.len() { + return Err(ContextError::ConstructorArgumentsMismatch { + type_info: ty.type_info.try_clone()?, + expected: fields.len(), + actual: c.args, + }); + } + + self.insert_native_fn(&ty.type_info, ty.hash, &c.handler, None)?; Some(signature) } None => None, @@ -801,7 +805,21 @@ impl Context { return_type: meta::DocType::new(ty.hash), }; - self.insert_native_fn(&item, hash, c, variant.deprecated.as_deref())?; + if c.args != fields.len() { + return Err(ContextError::VariantConstructorArgumentsMismatch { + type_info: ty.type_info.try_clone()?, + name: variant.name, + expected: fields.len(), + actual: c.args, + }); + } + + self.insert_native_fn( + &item, + hash, + &c.handler, + variant.deprecated.as_deref(), + )?; Some(signature) } else { None @@ -1177,7 +1195,7 @@ impl Context { &mut self, display: &dyn fmt::Display, hash: Hash, - handler: &Arc, + handler: &FunctionHandler, deprecation: Option<&str>, ) -> Result<(), ContextError> { if self.functions.contains_key(&hash) { diff --git a/crates/rune/src/compile/context_error.rs b/crates/rune/src/compile/context_error.rs index 05d918de4..9e5258e82 100644 --- a/crates/rune/src/compile/context_error.rs +++ b/crates/rune/src/compile/context_error.rs @@ -125,6 +125,17 @@ pub enum ContextError { type_info: TypeInfo, name: &'static str, }, + ConstructorArgumentsMismatch { + type_info: TypeInfo, + expected: usize, + actual: usize, + }, + VariantConstructorArgumentsMismatch { + type_info: TypeInfo, + name: &'static str, + expected: usize, + actual: usize, + }, ConflictingConstConstruct { type_info: TypeInfo, hash: Hash, @@ -337,6 +348,27 @@ impl fmt::Display for ContextError { "Constructor for variant `{name}` for `{type_info}` already exists" )?; } + ContextError::ConstructorArgumentsMismatch { + type_info, + expected, + actual, + } => { + write!( + f, + "Constructor for `{type_info}` has {actual} arguments but expected {expected}" + )?; + } + ContextError::VariantConstructorArgumentsMismatch { + type_info, + name, + expected, + actual, + } => { + write!( + f, + "Constructor for variant `{name}` for `{type_info}` has {actual} arguments but expected {expected}" + )?; + } ContextError::ConflictingConstConstruct { type_info, hash } => { write!( f, diff --git a/crates/rune/src/compile/error.rs b/crates/rune/src/compile/error.rs index b6690f894..ca1291e97 100644 --- a/crates/rune/src/compile/error.rs +++ b/crates/rune/src/compile/error.rs @@ -145,6 +145,7 @@ impl From for ErrorKind { } } +#[cfg(feature = "anyhow")] impl From for ErrorKind { #[inline] fn from(error: anyhow::Error) -> Self { @@ -245,9 +246,14 @@ impl Error { #[derive(Debug)] #[non_exhaustive] pub(crate) enum ErrorKind { + #[cfg(feature = "anyhow")] Custom { error: anyhow::Error, }, + #[cfg(not(feature = "anyhow"))] + Custom { + error: String, + }, AllocError { error: alloc::Error, }, @@ -611,6 +617,8 @@ pub(crate) enum ErrorKind { } impl ErrorKind { + #[inline] + #[cfg(feature = "anyhow")] pub(crate) fn msg(message: M) -> Self where M: fmt::Display + fmt::Debug + Send + Sync + 'static, @@ -619,11 +627,24 @@ impl ErrorKind { error: anyhow::Error::msg(message), } } + + #[inline] + #[cfg(not(feature = "anyhow"))] + pub(crate) fn msg(message: M) -> Self + where + M: fmt::Display + fmt::Debug + Send + Sync + 'static, + { + match crate::alloc::fmt::try_format(format_args!("{message}")) { + Ok(string) => Self::Custom { error: string }, + Err(error) => Self::AllocError { error }, + } + } } impl core::error::Error for ErrorKind { fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { + #[cfg(feature = "anyhow")] ErrorKind::Custom { error } => Some(error.as_ref()), ErrorKind::IrError(source) => Some(source), ErrorKind::MetaError(source) => Some(source), @@ -1226,11 +1247,19 @@ impl fmt::Display for ParameterizedItem<'_> { return self.0.fmt(f); }; - let base = it.as_item(); + let mut first = false; - let [ty_param, item_param] = self.1; + for c in it { + if first { + write!(f, "::{c}")?; + } else { + write!(f, "{c}")?; + } + + first = true; + } - write!(f, "{base}")?; + let [ty_param, item_param] = self.1; if let Some(ty_param) = ty_param { write!(f, "::{ty}<{ty_param}>")?; @@ -1457,7 +1486,7 @@ pub struct ImportStep { /// A meta error. #[derive(Debug)] pub struct MetaError { - kind: ::rust_alloc::boxed::Box, + kind: rust_alloc::boxed::Box, } impl MetaError { @@ -1467,7 +1496,7 @@ impl MetaError { MetaErrorKind: From, { Self { - kind: ::rust_alloc::boxed::Box::new(kind.into()), + kind: rust_alloc::boxed::Box::new(kind.into()), } } } diff --git a/crates/rune/src/compile/options.rs b/crates/rune/src/compile/options.rs index cf9b0ba32..61150055b 100644 --- a/crates/rune/src/compile/options.rs +++ b/crates/rune/src/compile/options.rs @@ -1,6 +1,8 @@ use core::fmt; -use ::rust_alloc::boxed::Box; +use rust_alloc::boxed::Box; + +use crate::docstring; /// Error raised when trying to parse an invalid option. #[derive(Debug, Clone)] @@ -53,10 +55,10 @@ impl FmtOptions { match head { "error-recovery" => { - self.error_recovery = tail.map_or(true, |s| s == "true"); + self.error_recovery = tail.is_none_or(|s| s == "true"); } "force-newline" => { - self.force_newline = tail.map_or(true, |s| s == "true"); + self.force_newline = tail.is_none_or(|s| s == "true"); } _ => { return Err(ParseOptionError { @@ -107,11 +109,11 @@ pub struct Options { pub(crate) macros: bool, /// Support bytecode caching. pub(crate) bytecode: bool, - /// Build sources as function bodies. + /// Build sources as scripts. /// /// The function to run will be named 0, which can be constructed with /// `Hash::EMPTY`. - pub(crate) function_body: bool, + pub(crate) script: bool, /// When running tests, include std tests. pub(crate) test_std: bool, /// Enable lowering optimizations. @@ -134,7 +136,7 @@ impl Options { debug_info: true, macros: true, bytecode: false, - function_body: false, + script: false, test_std: false, lowering: 0, print_tree: false, @@ -334,25 +336,25 @@ impl Options { match head { "memoize-instance-fn" => { - self.memoize_instance_fn = tail.map_or(true, |s| s == "true"); + self.memoize_instance_fn = tail.is_none_or(|s| s == "true"); } "debug-info" => { - self.debug_info = tail.map_or(true, |s| s == "true"); + self.debug_info = tail.is_none_or(|s| s == "true"); } "link-checks" => { - self.link_checks = tail.map_or(true, |s| s == "true"); + self.link_checks = tail.is_none_or(|s| s == "true"); } "macros" => { - self.macros = tail.map_or(true, |s| s == "true"); + self.macros = tail.is_none_or(|s| s == "true"); } "bytecode" => { - self.bytecode = tail.map_or(true, |s| s == "true"); + self.bytecode = tail.is_none_or(|s| s == "true"); } "function-body" => { - self.function_body = tail.map_or(true, |s| s == "true"); + self.script = tail.is_none_or(|s| s == "true"); } "test-std" => { - self.test_std = tail.map_or(true, |s| s == "true"); + self.test_std = tail.is_none_or(|s| s == "true"); } "lowering" => { self.lowering = match tail { @@ -367,10 +369,10 @@ impl Options { }; } "print-tree" if cfg!(feature = "std") => { - self.print_tree = tail.map_or(true, |s| s == "true"); + self.print_tree = tail.is_none_or(|s| s == "true"); } "v2" => { - self.v2 = tail.map_or(true, |s| s == "true"); + self.v2 = tail.is_none_or(|s| s == "true"); } "max-macro-depth" => { let Some(Ok(number)) = tail.map(str::parse) else { @@ -412,11 +414,13 @@ impl Options { } /// Enable the test configuration flag. + #[inline] pub fn test(&mut self, _enabled: bool) { // ignored } /// Set if debug info is enabled or not. Defaults to `true`. + #[inline] pub fn debug_info(&mut self, enabled: bool) { self.debug_info = enabled; } @@ -424,29 +428,34 @@ impl Options { /// Set if link checks are enabled or not. Defaults to `true`. This will /// cause compilation to fail if an instruction references a function which /// does not exist. + #[inline] pub fn link_checks(&mut self, enabled: bool) { self.link_checks = enabled; } /// Set if macros are enabled or not. Defaults to `false`. + #[inline] pub fn macros(&mut self, enabled: bool) { self.macros = enabled; } /// Set if bytecode caching is enabled or not. Defaults to `false`. + #[inline] pub fn bytecode(&mut self, enabled: bool) { self.bytecode = enabled; } /// Memoize the instance function in a loop. Defaults to `false`. + #[inline] pub fn memoize_instance_fn(&mut self, enabled: bool) { self.memoize_instance_fn = enabled; } /// Whether to build sources as scripts where the source is executed like a /// function body. + #[inline] pub fn script(&mut self, enabled: bool) { - self.function_body = enabled; + self.script = enabled; } } diff --git a/crates/rune/src/compile/unit_builder.rs b/crates/rune/src/compile/unit_builder.rs index e0883ad1c..e039879c4 100644 --- a/crates/rune/src/compile/unit_builder.rs +++ b/crates/rune/src/compile/unit_builder.rs @@ -5,7 +5,7 @@ use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; @@ -16,9 +16,10 @@ use crate::compile::{self, Assembly, AssemblyInst, ErrorKind, Location, Pool, Wi use crate::hash; use crate::query::QueryInner; use crate::runtime::debug::{DebugArgs, DebugSignature}; +use crate::runtime::inst; use crate::runtime::unit::UnitEncoder; use crate::runtime::{ - Call, ConstValue, DebugInfo, DebugInst, Inst, InstAddress, Label, Protocol, Rtti, RttiKind, + Address, Call, ConstValue, DebugInfo, DebugInst, Inst, Label, Protocol, Rtti, RttiKind, StaticString, Unit, UnitFn, }; use crate::{Context, Diagnostics, Hash, Item, SourceId}; @@ -73,9 +74,9 @@ pub(crate) struct UnitBuilder { /// Used to detect duplicates in the collection of static object keys. static_object_keys_rev: HashMap, /// A static string. - drop_sets: Vec>, + drop_sets: Vec>, /// Reverse lookup for drop sets. - drop_sets_rev: HashMap, usize>, + drop_sets_rev: HashMap, usize>, /// Runtime type information for types. rtti: hash::Map>, /// The current label count. @@ -820,7 +821,7 @@ impl UnitBuilder { self.label_count = assembly.label_count; storage - .encode(Inst::Allocate { size }) + .encode(Inst::new(inst::Kind::Allocate { size })) .with_span(location.span)?; let base = storage.extend_offsets(assembly.labels.len())?; @@ -870,34 +871,36 @@ impl UnitBuilder { AssemblyInst::Jump { label } => { write!(comment, "label:{}", label)?; let jump = build_label(label)?; - storage.encode(Inst::Jump { jump }).with_span(span)?; + storage + .encode(Inst::new(inst::Kind::Jump { jump })) + .with_span(span)?; } AssemblyInst::JumpIf { addr, label } => { write!(comment, "label:{}", label)?; let jump = build_label(label)?; storage - .encode(Inst::JumpIf { cond: addr, jump }) + .encode(Inst::new(inst::Kind::JumpIf { cond: addr, jump })) .with_span(span)?; } AssemblyInst::JumpIfNot { addr, label } => { write!(comment, "label:{}", label)?; let jump = build_label(label)?; storage - .encode(Inst::JumpIfNot { cond: addr, jump }) + .encode(Inst::new(inst::Kind::JumpIfNot { cond: addr, jump })) .with_span(span)?; } AssemblyInst::IterNext { addr, label, out } => { write!(comment, "label:{}", label)?; let jump = build_label(label)?; storage - .encode(Inst::IterNext { addr, jump, out }) + .encode(Inst::new(inst::Kind::IterNext { addr, jump, out })) .with_span(span)?; } AssemblyInst::Raw { raw } => { // Optimization to avoid performing lookups for recursive // function calls. - let inst = match raw { - inst @ Inst::Call { + let kind = match raw { + inst @ inst::Kind::Call { hash, addr, args, @@ -906,7 +909,7 @@ impl UnitBuilder { if let Some(UnitFn::Offset { offset, call, .. }) = self.functions.get(&hash) { - Inst::CallOffset { + inst::Kind::CallOffset { offset: *offset, call: *call, addr, @@ -917,10 +920,10 @@ impl UnitBuilder { inst } } - inst => inst, + kind => kind, }; - storage.encode(inst).with_span(span)?; + storage.encode(Inst::new(kind)).with_span(span)?; } } @@ -951,12 +954,12 @@ impl UnitBuilder { /// A set of addresses that should be dropped. pub(crate) struct DropSet<'a> { builder: &'a mut UnitBuilder, - addresses: Vec, + addresses: Vec

, } impl DropSet<'_> { /// Construct a new drop set. - pub(crate) fn push(&mut self, addr: InstAddress) -> alloc::Result<()> { + pub(crate) fn push(&mut self, addr: Address) -> alloc::Result<()> { self.addresses.try_push(addr) } diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index af0dd1339..3d9848fc3 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -11,10 +11,11 @@ use crate::compile::ir; use crate::compile::{self, Assembly, ErrorKind, ItemId, ModId, Options, WithSpan}; use crate::hir; use crate::query::{ConstFn, Query, Used}; +use crate::runtime::inst; use crate::runtime::{ - ConstValue, ConstValueKind, Inline, Inst, InstAddress, InstArithmeticOp, InstBitwiseOp, InstOp, - InstRange, InstShiftOp, InstTarget, InstValue, InstVariant, Label, Output, PanicReason, - Protocol, TypeCheck, + ConstValue, ConstValueKind, Inline, InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, + InstShiftOp, InstTarget, InstValue, InstVariant, Label, Output, PanicReason, Protocol, + TypeCheck, }; use crate::shared::FixedVec; use crate::{Hash, SourceId}; @@ -67,7 +68,7 @@ pub(crate) struct Ctxt<'a, 'hir, 'arena> { /// Work buffer for select branches. pub(crate) select_branches: Vec<(Label, &'hir hir::ExprSelectBranch<'hir>)>, /// Values to drop. - pub(crate) drop: Vec, + pub(crate) drop: Vec, } impl<'hir> Ctxt<'_, 'hir, '_> { @@ -83,7 +84,7 @@ impl<'hir> Ctxt<'_, 'hir, '_> { } if let Some(set) = drop_set.finish()? { - self.asm.push(Inst::Drop { set }, span)?; + self.asm.push(inst::Kind::Drop { set }, span)?; } Ok(()) @@ -247,7 +248,7 @@ pub(crate) fn fn_from_item_fn<'hir>( let mut needs = Any::ignore(&hir.body); if block_without_scope(cx, &hir.body, &mut needs)?.converging() { - cx.asm.push(Inst::ReturnUnit, hir)?; + cx.asm.push(inst::Kind::ReturnUnit, hir)?; } } @@ -286,7 +287,7 @@ pub(crate) fn expr_closure_secondary<'hir>( if !hir.captures.is_empty() { cx.asm.push( - Inst::Environment { + inst::Kind::Environment { addr: environment.addr(), count: hir.captures.len(), out: environment.addr().output(), @@ -362,7 +363,7 @@ fn return_<'a, 'hir, T>( converge!(asm(cx, hir, &mut needs)?, free(needs)); cx.asm.push( - Inst::Return { + inst::Kind::Return { addr: needs.addr()?.addr(), }, span, @@ -391,7 +392,7 @@ where cx.asm.jump(&match_label, span)?; cx.asm.label(&false_label)?; cx.asm.push( - Inst::Panic { + inst::Kind::Panic { reason: PanicReason::UnmatchedPattern, }, span, @@ -605,9 +606,9 @@ fn pat_lit<'a, 'hir>( fn pat_lit_inst( cx: &mut Ctxt<'_, '_, '_>, hir: &hir::Expr<'_>, - addr: InstAddress, - cond: InstAddress, -) -> compile::Result> { + addr: inst::Address, + cond: inst::Address, +) -> compile::Result> { let hir::ExprKind::Lit(lit) = hir.kind else { return Ok(None); }; @@ -615,20 +616,20 @@ fn pat_lit_inst( let out = cond.output(); let inst = match lit { - hir::Lit::Char(value) => Inst::EqChar { addr, value, out }, - hir::Lit::Str(string) => Inst::EqString { + hir::Lit::Char(value) => inst::Kind::EqChar { addr, value, out }, + hir::Lit::Str(string) => inst::Kind::EqString { addr, slot: cx.q.unit.new_static_string(hir, string)?, out, }, - hir::Lit::ByteStr(bytes) => Inst::EqBytes { + hir::Lit::ByteStr(bytes) => inst::Kind::EqBytes { addr, slot: cx.q.unit.new_static_bytes(hir, bytes)?, out, }, - hir::Lit::Unsigned(value) => Inst::EqUnsigned { addr, value, out }, - hir::Lit::Signed(value) => Inst::EqSigned { addr, value, out }, - hir::Lit::Bool(value) => Inst::EqBool { addr, value, out }, + hir::Lit::Unsigned(value) => inst::Kind::EqUnsigned { addr, value, out }, + hir::Lit::Signed(value) => inst::Kind::EqSigned { addr, value, out }, + hir::Lit::Bool(value) => inst::Kind::EqBool { addr, value, out }, _ => return Ok(None), }; @@ -719,7 +720,7 @@ fn pat_sequence<'a, 'hir>( } ) { cx.asm.push( - Inst::IsUnit { + inst::Kind::IsUnit { addr: addr.addr(), out: cond.output(), }, @@ -735,7 +736,7 @@ fn pat_sequence<'a, 'hir>( for (index, p) in hir.items.iter().enumerate() { let mut load = |cx: &mut Ctxt<'a, 'hir, '_>, needs: &mut dyn Needs<'a, 'hir>| { cx.asm.push( - Inst::TupleIndexGetAt { + inst::Kind::TupleIndexGetAt { addr: addr.addr(), index, out: needs.alloc_output()?, @@ -757,10 +758,14 @@ fn pat_sequence<'a, 'hir>( Ok(Asm::new(span, Pattern::Refutable)) } -fn pat_sequence_kind_to_inst(kind: hir::PatSequenceKind, addr: InstAddress, out: Output) -> Inst { +fn pat_sequence_kind_to_inst( + kind: hir::PatSequenceKind, + addr: inst::Address, + out: Output, +) -> inst::Kind { match kind { - hir::PatSequenceKind::Type { hash } => Inst::MatchType { hash, addr, out }, - hir::PatSequenceKind::BuiltInVariant { type_check } => Inst::MatchBuiltIn { + hir::PatSequenceKind::Type { hash } => inst::Kind::MatchType { hash, addr, out }, + hir::PatSequenceKind::BuiltInVariant { type_check } => inst::Kind::MatchBuiltIn { type_check, addr, out, @@ -768,7 +773,7 @@ fn pat_sequence_kind_to_inst(kind: hir::PatSequenceKind, addr: InstAddress, out: hir::PatSequenceKind::Variant { enum_hash, variant_hash, - } => Inst::MatchVariant { + } => inst::Kind::MatchVariant { enum_hash, variant_hash, addr, @@ -778,7 +783,7 @@ fn pat_sequence_kind_to_inst(kind: hir::PatSequenceKind, addr: InstAddress, out: type_check, count, is_open, - } => Inst::MatchSequence { + } => inst::Kind::MatchSequence { type_check, len: count, exact: !is_open, @@ -814,12 +819,12 @@ fn pat_object<'a, 'hir>( } let inst = match hir.kind { - hir::PatSequenceKind::Type { hash } => Inst::MatchType { + hir::PatSequenceKind::Type { hash } => inst::Kind::MatchType { hash, addr: addr.addr(), out: cond.output(), }, - hir::PatSequenceKind::BuiltInVariant { type_check } => Inst::MatchBuiltIn { + hir::PatSequenceKind::BuiltInVariant { type_check } => inst::Kind::MatchBuiltIn { type_check, addr: addr.addr(), out: cond.output(), @@ -827,7 +832,7 @@ fn pat_object<'a, 'hir>( hir::PatSequenceKind::Variant { enum_hash, variant_hash, - } => Inst::MatchVariant { + } => inst::Kind::MatchVariant { enum_hash, variant_hash, addr: addr.addr(), @@ -838,7 +843,7 @@ fn pat_object<'a, 'hir>( cx.q.unit .new_static_object_keys_iter(span, hir.bindings.iter().map(|b| b.key()))?; - Inst::MatchObject { + inst::Kind::MatchObject { slot: keys, exact: !is_open, addr: addr.addr(), @@ -859,7 +864,7 @@ fn pat_object<'a, 'hir>( let mut load = move |cx: &mut Ctxt<'a, 'hir, '_>, needs: &mut dyn Needs<'a, 'hir>| { cx.asm.push( - Inst::ObjectIndexGetAt { + inst::Kind::ObjectIndexGetAt { addr: addr.addr(), slot, out: needs.alloc_output()?, @@ -883,7 +888,7 @@ fn pat_object<'a, 'hir>( }; cx.asm.push( - Inst::ObjectIndexGetAt { + inst::Kind::ObjectIndexGetAt { addr: addr.addr(), slot, out: binding.output()?, @@ -972,7 +977,7 @@ fn block_without_scope<'a, 'hir>( diverge = Some(e); } } else if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), hir)?; + cx.asm.push(inst::Kind::unit(out), hir)?; } cx.contexts @@ -1009,7 +1014,7 @@ fn builtin_format<'a, 'hir>( if let Some(addr) = needs.try_alloc_addr()? { cx.asm.push( - Inst::Format { + inst::Kind::Format { addr: addr.addr(), spec, out: addr.output(), @@ -1042,7 +1047,7 @@ fn builtin_template<'a, 'hir>( size_hint += s.len(); let slot = cx.q.unit.new_static_string(span, s)?; cx.asm.push( - Inst::String { + inst::Kind::String { slot, out: addr.output(), }, @@ -1067,7 +1072,7 @@ fn builtin_template<'a, 'hir>( if converge { cx.asm.push( - Inst::StringConcat { + inst::Kind::StringConcat { addr: linear.addr(), len: hir.exprs.len(), size_hint, @@ -1111,47 +1116,47 @@ fn const_<'a, 'hir>( )); } Inline::Unit => { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } Inline::Char(v) => { - cx.asm.push(Inst::char(v, out), span)?; + cx.asm.push(inst::Kind::char(v, out), span)?; } Inline::Signed(v) => { - cx.asm.push(Inst::signed(v, out), span)?; + cx.asm.push(inst::Kind::signed(v, out), span)?; } Inline::Unsigned(v) => { - cx.asm.push(Inst::unsigned(v, out), span)?; + cx.asm.push(inst::Kind::unsigned(v, out), span)?; } Inline::Float(v) => { - cx.asm.push(Inst::float(v, out), span)?; + cx.asm.push(inst::Kind::float(v, out), span)?; } Inline::Bool(v) => { - cx.asm.push(Inst::bool(v, out), span)?; + cx.asm.push(inst::Kind::bool(v, out), span)?; } Inline::Type(v) => { - cx.asm.push(Inst::ty(v, out), span)?; + cx.asm.push(inst::Kind::ty(v, out), span)?; } Inline::Ordering(v) => { - cx.asm.push(Inst::ordering(v, out), span)?; + cx.asm.push(inst::Kind::ordering(v, out), span)?; } Inline::Hash(v) => { - cx.asm.push(Inst::hash(v, out), span)?; + cx.asm.push(inst::Kind::hash(v, out), span)?; } }, ConstValueKind::String(ref s) => { let slot = cx.q.unit.new_static_string(span, s)?; - cx.asm.push(Inst::String { slot, out }, span)?; + cx.asm.push(inst::Kind::String { slot, out }, span)?; } ConstValueKind::Bytes(ref b) => { let slot = cx.q.unit.new_static_bytes(span, b)?; - cx.asm.push(Inst::Bytes { slot, out }, span)?; + cx.asm.push(inst::Kind::Bytes { slot, out }, span)?; } ConstValueKind::Option(ref option) => match option { Some(value) => { const_(cx, value, span, addr)?; cx.asm.push( - Inst::Variant { + inst::Kind::Variant { variant: InstVariant::Some, addr: addr.addr(), out, @@ -1161,7 +1166,7 @@ fn const_<'a, 'hir>( } None => { cx.asm.push( - Inst::Variant { + inst::Kind::Variant { variant: InstVariant::None, addr: addr.addr(), out, @@ -1178,7 +1183,7 @@ fn const_<'a, 'hir>( } cx.asm.push( - Inst::Vec { + inst::Kind::Vec { addr: linear.addr(), count: vec.len(), out, @@ -1196,7 +1201,7 @@ fn const_<'a, 'hir>( } cx.asm.push( - Inst::Tuple { + inst::Kind::Tuple { addr: linear.addr(), count: tuple.len(), out, @@ -1221,7 +1226,7 @@ fn const_<'a, 'hir>( .new_static_object_keys_iter(span, entries.iter().map(|e| e.0))?; cx.asm.push( - Inst::Object { + inst::Kind::Object { addr: linear.addr(), slot, out, @@ -1239,7 +1244,7 @@ fn const_<'a, 'hir>( } cx.asm.push( - Inst::ConstConstruct { + inst::Kind::ConstConstruct { addr: linear.addr(), hash, count: values.len(), @@ -1271,7 +1276,7 @@ fn expr<'a, 'hir>( hir::ExprKind::Type(ty) => { if let Some(out) = needs.try_alloc_output()? { cx.asm.push( - Inst::Store { + inst::Kind::Store { value: InstValue::Type(ty), out, }, @@ -1283,7 +1288,7 @@ fn expr<'a, 'hir>( } hir::ExprKind::Fn(hash) => { if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::LoadFn { hash, out }, span)?; + cx.asm.push(inst::Kind::LoadFn { hash, out }, span)?; } Asm::new(span, ()) @@ -1364,7 +1369,7 @@ fn expr_assign<'a, 'hir>( let slot = cx.q.unit.new_static_string(span, ident)?; cx.asm.push( - Inst::ObjectIndexSet { + inst::Kind::ObjectIndexSet { target: target.addr(), slot, value: value.addr(), @@ -1376,7 +1381,7 @@ fn expr_assign<'a, 'hir>( hir::ExprField::Index(index) => { if let Some([target, value]) = asm.into_converging() { cx.asm.push( - Inst::TupleIndexSet { + inst::Kind::TupleIndexSet { target: target.addr(), index, value: value.addr(), @@ -1411,7 +1416,7 @@ fn expr_assign<'a, 'hir>( if let Some([target, index, value]) = asm.into_converging() { cx.asm.push( - Inst::IndexSet { + inst::Kind::IndexSet { target: target.addr(), index: index.addr(), value: value.addr(), @@ -1433,7 +1438,7 @@ fn expr_assign<'a, 'hir>( } if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } Ok(Asm::new(span, ())) @@ -1451,7 +1456,7 @@ fn expr_await<'a, 'hir>( converge!(expr(cx, hir, &mut addr)?, free(addr)); cx.asm.push( - Inst::Await { + inst::Kind::Await { addr: addr.addr()?.addr(), out: needs.alloc_output()?, }, @@ -1490,127 +1495,127 @@ fn expr_binary<'a, 'hir>( let out = needs.alloc_output()?; let inst = match hir.op { - ast::BinOp::Eq(..) => Inst::Op { + ast::BinOp::Eq(..) => inst::Kind::Op { op: InstOp::Eq, a, b, out, }, - ast::BinOp::Neq(..) => Inst::Op { + ast::BinOp::Neq(..) => inst::Kind::Op { op: InstOp::Neq, a, b, out, }, - ast::BinOp::Lt(..) => Inst::Op { + ast::BinOp::Lt(..) => inst::Kind::Op { op: InstOp::Lt, a, b, out, }, - ast::BinOp::Gt(..) => Inst::Op { + ast::BinOp::Gt(..) => inst::Kind::Op { op: InstOp::Gt, a, b, out, }, - ast::BinOp::Lte(..) => Inst::Op { + ast::BinOp::Lte(..) => inst::Kind::Op { op: InstOp::Le, a, b, out, }, - ast::BinOp::Gte(..) => Inst::Op { + ast::BinOp::Gte(..) => inst::Kind::Op { op: InstOp::Ge, a, b, out, }, - ast::BinOp::As(..) => Inst::Op { + ast::BinOp::As(..) => inst::Kind::Op { op: InstOp::As, a, b, out, }, - ast::BinOp::Is(..) => Inst::Op { + ast::BinOp::Is(..) => inst::Kind::Op { op: InstOp::Is, a, b, out, }, - ast::BinOp::IsNot(..) => Inst::Op { + ast::BinOp::IsNot(..) => inst::Kind::Op { op: InstOp::IsNot, a, b, out, }, - ast::BinOp::And(..) => Inst::Op { + ast::BinOp::And(..) => inst::Kind::Op { op: InstOp::And, a, b, out, }, - ast::BinOp::Or(..) => Inst::Op { + ast::BinOp::Or(..) => inst::Kind::Op { op: InstOp::Or, a, b, out, }, - ast::BinOp::Add(..) => Inst::Arithmetic { + ast::BinOp::Add(..) => inst::Kind::Arithmetic { op: InstArithmeticOp::Add, a, b, out, }, - ast::BinOp::Sub(..) => Inst::Arithmetic { + ast::BinOp::Sub(..) => inst::Kind::Arithmetic { op: InstArithmeticOp::Sub, a, b, out, }, - ast::BinOp::Div(..) => Inst::Arithmetic { + ast::BinOp::Div(..) => inst::Kind::Arithmetic { op: InstArithmeticOp::Div, a, b, out, }, - ast::BinOp::Mul(..) => Inst::Arithmetic { + ast::BinOp::Mul(..) => inst::Kind::Arithmetic { op: InstArithmeticOp::Mul, a, b, out, }, - ast::BinOp::Rem(..) => Inst::Arithmetic { + ast::BinOp::Rem(..) => inst::Kind::Arithmetic { op: InstArithmeticOp::Rem, a, b, out, }, - ast::BinOp::BitAnd(..) => Inst::Bitwise { + ast::BinOp::BitAnd(..) => inst::Kind::Bitwise { op: InstBitwiseOp::BitAnd, a, b, out, }, - ast::BinOp::BitXor(..) => Inst::Bitwise { + ast::BinOp::BitXor(..) => inst::Kind::Bitwise { op: InstBitwiseOp::BitXor, a, b, out, }, - ast::BinOp::BitOr(..) => Inst::Bitwise { + ast::BinOp::BitOr(..) => inst::Kind::Bitwise { op: InstBitwiseOp::BitOr, a, b, out, }, - ast::BinOp::Shl(..) => Inst::Shift { + ast::BinOp::Shl(..) => inst::Kind::Shift { op: InstShiftOp::Shl, a, b, out, }, - ast::BinOp::Shr(..) => Inst::Shift { + ast::BinOp::Shr(..) => inst::Kind::Shift { op: InstShiftOp::Shr, a, b, @@ -1720,52 +1725,52 @@ fn compile_assign_binop<'a, 'hir>( }; let inst = match bin_op { - ast::BinOp::AddAssign(..) => Inst::AssignArithmetic { + ast::BinOp::AddAssign(..) => inst::Kind::AssignArithmetic { op: InstArithmeticOp::Add, target, rhs: value.addr(), }, - ast::BinOp::SubAssign(..) => Inst::AssignArithmetic { + ast::BinOp::SubAssign(..) => inst::Kind::AssignArithmetic { op: InstArithmeticOp::Sub, target, rhs: value.addr(), }, - ast::BinOp::MulAssign(..) => Inst::AssignArithmetic { + ast::BinOp::MulAssign(..) => inst::Kind::AssignArithmetic { op: InstArithmeticOp::Mul, target, rhs: value.addr(), }, - ast::BinOp::DivAssign(..) => Inst::AssignArithmetic { + ast::BinOp::DivAssign(..) => inst::Kind::AssignArithmetic { op: InstArithmeticOp::Div, target, rhs: value.addr(), }, - ast::BinOp::RemAssign(..) => Inst::AssignArithmetic { + ast::BinOp::RemAssign(..) => inst::Kind::AssignArithmetic { op: InstArithmeticOp::Rem, target, rhs: value.addr(), }, - ast::BinOp::BitAndAssign(..) => Inst::AssignBitwise { + ast::BinOp::BitAndAssign(..) => inst::Kind::AssignBitwise { op: InstBitwiseOp::BitAnd, target, rhs: value.addr(), }, - ast::BinOp::BitXorAssign(..) => Inst::AssignBitwise { + ast::BinOp::BitXorAssign(..) => inst::Kind::AssignBitwise { op: InstBitwiseOp::BitXor, target, rhs: value.addr(), }, - ast::BinOp::BitOrAssign(..) => Inst::AssignBitwise { + ast::BinOp::BitOrAssign(..) => inst::Kind::AssignBitwise { op: InstBitwiseOp::BitOr, target, rhs: value.addr(), }, - ast::BinOp::ShlAssign(..) => Inst::AssignShift { + ast::BinOp::ShlAssign(..) => inst::Kind::AssignShift { op: InstShiftOp::Shl, target, rhs: value.addr(), }, - ast::BinOp::ShrAssign(..) => Inst::AssignShift { + ast::BinOp::ShrAssign(..) => inst::Kind::AssignShift { op: InstShiftOp::Shr, target, rhs: value.addr(), @@ -1778,7 +1783,7 @@ fn compile_assign_binop<'a, 'hir>( cx.asm.push(inst, span)?; if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } value.free()?; @@ -1808,7 +1813,7 @@ fn expr_async_block<'a, 'hir>( } cx.asm.push_with_comment( - Inst::Call { + inst::Kind::Call { hash: hir.hash, addr: linear.addr(), args: hir.captures.len(), @@ -1880,7 +1885,7 @@ fn expr_break<'hir>( converge!(expr(cx, hir, &mut needs)?, free(needs)); needs.free()?; } else if let Some(out) = output { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } let mut drop_set = cx.q.unit.drop_set(); @@ -1891,7 +1896,7 @@ fn expr_break<'hir>( } if let Some(set) = drop_set.finish()? { - cx.asm.push(Inst::Drop { set }, span)?; + cx.asm.push(inst::Kind::Drop { set }, span)?; } cx.asm.jump(&break_label, span)?; @@ -1915,7 +1920,7 @@ fn expr_call<'a, 'hir>( let var = cx.scopes.get(&mut cx.q, span, name)?; cx.asm.push( - Inst::CallFn { + inst::Kind::CallFn { function: var.addr, addr: linear.addr(), args: hir.args.len(), @@ -1930,7 +1935,7 @@ fn expr_call<'a, 'hir>( let linear = converge!(exprs_2(cx, span, slice::from_ref(target), hir.args)?); cx.asm.push( - Inst::CallAssociated { + inst::Kind::CallAssociated { hash, addr: linear.addr(), args: args + 1, @@ -1945,7 +1950,7 @@ fn expr_call<'a, 'hir>( let linear = converge!(exprs(cx, span, hir.args)?); cx.asm.push( - Inst::Call { + inst::Kind::Call { hash, addr: linear.addr(), args: hir.args.len(), @@ -1962,7 +1967,7 @@ fn expr_call<'a, 'hir>( let linear = converge!(exprs(cx, span, hir.args)?, free(function)); cx.asm.push( - Inst::CallFn { + inst::Kind::CallFn { function: function.addr()?.addr(), addr: linear.addr(), args: hir.args.len(), @@ -2111,7 +2116,7 @@ fn expr_call_closure<'a, 'hir>( } cx.asm.push( - Inst::Closure { + inst::Kind::Closure { hash: hir.hash, addr: linear.addr(), count: hir.captures.len(), @@ -2172,7 +2177,7 @@ fn expr_field_access<'a, 'hir>( let var = cx.scopes.get(&mut cx.q, span, name)?; cx.asm.push_with_comment( - Inst::TupleIndexGetAt { + inst::Kind::TupleIndexGetAt { addr: var.addr, index, out: needs.alloc_output()?, @@ -2192,7 +2197,7 @@ fn expr_field_access<'a, 'hir>( match hir.expr_field { hir::ExprField::Index(index) => { cx.asm.push( - Inst::TupleIndexGetAt { + inst::Kind::TupleIndexGetAt { addr: addr.addr(), index, out: needs.alloc_output()?, @@ -2204,7 +2209,7 @@ fn expr_field_access<'a, 'hir>( let slot = cx.q.unit.new_static_string(span, field)?; cx.asm.push( - Inst::ObjectIndexGetAt { + inst::Kind::ObjectIndexGetAt { addr: addr.addr(), slot, out: needs.alloc_output()?, @@ -2248,7 +2253,7 @@ fn expr_for<'a, 'hir>( // Copy the iterator, since CallAssociated will consume it. cx.asm.push_with_comment( - Inst::Copy { + inst::Kind::Copy { addr: iter.addr(), out: into_iter.output(), }, @@ -2257,7 +2262,7 @@ fn expr_for<'a, 'hir>( )?; cx.asm.push_with_comment( - Inst::CallAssociated { + inst::Kind::CallAssociated { addr: into_iter.addr(), hash: Protocol::INTO_ITER.hash, args: 1, @@ -2272,7 +2277,7 @@ fn expr_for<'a, 'hir>( let offset = cx.scopes.alloc(&hir.iter)?.with_name("memoized next"); cx.asm.push_with_comment( - Inst::LoadInstanceFn { + inst::Kind::LoadInstanceFn { addr: into_iter.addr(), hash: Protocol::NEXT.hash, out: offset.output(), @@ -2299,7 +2304,7 @@ fn expr_for<'a, 'hir>( let into_iter_copy = cx.scopes.alloc(span)?.with_name("into_iter_copy"); cx.asm.push( - Inst::Copy { + inst::Kind::Copy { addr: into_iter.addr(), out: into_iter_copy.output(), }, @@ -2309,7 +2314,7 @@ fn expr_for<'a, 'hir>( // Use the memoized loop variable. if let Some(next_offset) = &next_offset { cx.asm.push( - Inst::CallFn { + inst::Kind::CallFn { function: next_offset.addr(), addr: into_iter_copy.addr(), args: 1, @@ -2319,7 +2324,7 @@ fn expr_for<'a, 'hir>( )?; } else { cx.asm.push_with_comment( - Inst::CallAssociated { + inst::Kind::CallAssociated { addr: into_iter_copy.addr(), hash: Protocol::NEXT.hash, args: 1, @@ -2375,13 +2380,13 @@ fn expr_for<'a, 'hir>( // the break statement is responsible for ensuring that active // iterators are dropped. if let Some(set) = drop_set.finish()? { - cx.asm.push(Inst::Drop { set }, span)?; + cx.asm.push(inst::Kind::Drop { set }, span)?; } cx.asm.label(&break_label)?; if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } if let Some(next_offset) = next_offset { @@ -2444,7 +2449,7 @@ fn expr_if<'a, 'hir>( let asm = if let Some(b) = hir.fallback { block(cx, b, needs)? } else if let Some(out) = output_addr { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; Asm::new(span, ()) } else { Asm::new(span, ()) @@ -2466,7 +2471,7 @@ fn expr_if<'a, 'hir>( if asm.converging() { if let Some(out) = output_addr { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } Asm::new(span, ()) @@ -2508,7 +2513,7 @@ fn expr_index<'a, 'hir>( .into_converging() { cx.asm.push( - Inst::IndexGet { + inst::Kind::IndexGet { index: index.addr(), target: target.addr(), out: needs.alloc_output()?, @@ -2538,7 +2543,7 @@ fn expr_let<'a, 'hir>( // If a value is needed for a let expression, it is evaluated as a unit. if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), hir)?; + cx.asm.push(inst::Kind::unit(out), hir)?; } Ok(Asm::new(hir, ())) @@ -2635,7 +2640,7 @@ fn expr_match<'a, 'hir>( if !is_irrefutable { if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } cx.asm.jump(&end_label, span)?; @@ -2677,7 +2682,7 @@ fn expr_object<'a, 'hir>( match hir.kind { hir::ExprObjectKind::Struct { hash } => { cx.asm.push( - Inst::Struct { + inst::Kind::Struct { addr: linear.addr(), hash, out: needs.alloc_output()?, @@ -2689,7 +2694,7 @@ fn expr_object<'a, 'hir>( reorder_field_assignments(cx, hir, linear.addr(), span)?; cx.asm.push( - Inst::Call { + inst::Kind::Call { hash, addr: linear.addr(), args, @@ -2705,7 +2710,7 @@ fn expr_object<'a, 'hir>( .new_static_object_keys_iter(span, hir.assignments.iter().map(|a| a.key.1))?; cx.asm.push( - Inst::Object { + inst::Kind::Object { addr: linear.addr(), slot, out: needs.alloc_output()?, @@ -2726,7 +2731,7 @@ fn expr_object<'a, 'hir>( fn reorder_field_assignments<'hir>( cx: &mut Ctxt<'_, 'hir, '_>, hir: &hir::ExprObject<'hir>, - base: InstAddress, + base: inst::Address, span: &dyn Spanned, ) -> compile::Result<()> { let mut order = Vec::try_with_capacity(hir.assignments.len())?; @@ -2763,9 +2768,9 @@ fn reorder_field_assignments<'hir>( )); }; - let a = InstAddress::new(a); - let b = InstAddress::new(b); - cx.asm.push(Inst::Swap { a, b }, span)?; + let a = inst::Address::new(a); + let b = inst::Address::new(b); + cx.asm.push(inst::Kind::Swap { a, b }, span)?; } } @@ -2852,7 +2857,7 @@ fn expr_range<'a, 'hir>( }; if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::Range { range, out }, span)?; + cx.asm.push(inst::Kind::Range { range, out }, span)?; } for var in vars.into_iter().flatten() { @@ -2872,7 +2877,7 @@ fn expr_return<'hir>( if let Some(e) = hir { converge!(return_(cx, span, e, expr)?); } else { - cx.asm.push(Inst::ReturnUnit, span)?; + cx.asm.push(inst::Kind::ReturnUnit, span)?; } Ok(Asm::diverge(span)) @@ -2907,7 +2912,7 @@ fn expr_select_inner<'a, 'hir>( cx.asm.label(&select_label)?; cx.asm.push( - Inst::Select { + inst::Kind::Select { addr: linear.addr(), len: hir.exprs.len(), value: value_addr.output(), @@ -2924,7 +2929,7 @@ fn expr_select_inner<'a, 'hir>( } else { if let Some(out) = needs.try_alloc_output()? { cx.asm.push( - Inst::Copy { + inst::Kind::Copy { addr: value_addr.addr(), out, }, @@ -2970,7 +2975,7 @@ fn expr_select_inner<'a, 'hir>( } if let Some(set) = drop_set.finish()? { - cx.asm.push(Inst::Drop { set }, span)?; + cx.asm.push(inst::Kind::Drop { set }, span)?; } value_addr.free()?; @@ -3010,7 +3015,7 @@ fn expr_try<'a, 'hir>( converge!(expr(cx, hir, &mut e)?); cx.asm.push( - Inst::Try { + inst::Kind::Try { addr: e.addr()?.addr(), out: needs.alloc_output()?, }, @@ -3038,7 +3043,7 @@ fn expr_tuple<'a, 'hir>( let [$($expr),*] = converge!(asm, free($($var),*)); cx.asm.push( - Inst::$variant { + inst::Kind::$variant { addr: [$($expr.addr(),)*], out: needs.alloc_output()?, }, @@ -3051,7 +3056,7 @@ fn expr_tuple<'a, 'hir>( match hir.items { [] => { - cx.asm.push(Inst::unit(needs.alloc_output()?), span)?; + cx.asm.push(inst::Kind::unit(needs.alloc_output()?), span)?; } [e1] => tuple!(Tuple1, v1, e1), [e1, e2] => tuple!(Tuple2, v1, e1, v2, e2), @@ -3062,7 +3067,7 @@ fn expr_tuple<'a, 'hir>( if let Some(out) = needs.try_alloc_output()? { cx.asm.push( - Inst::Tuple { + inst::Kind::Tuple { addr: linear.addr(), count: hir.items.len(), out, @@ -3095,7 +3100,7 @@ fn expr_unary<'a, 'hir>( match hir.op { ast::UnOp::Not(..) => { cx.asm.push( - Inst::Not { + inst::Kind::Not { addr: addr.addr(), out: needs.alloc_output()?, }, @@ -3104,7 +3109,7 @@ fn expr_unary<'a, 'hir>( } ast::UnOp::Neg(..) => { cx.asm.push( - Inst::Neg { + inst::Kind::Neg { addr: addr.addr(), out: needs.alloc_output()?, }, @@ -3140,7 +3145,7 @@ fn expr_vec<'a, 'hir>( if let Some(out) = needs.try_alloc_addr()? { cx.asm.push( - Inst::Vec { + inst::Kind::Vec { addr: linear.addr(), count, out: out.output(), @@ -3207,7 +3212,7 @@ fn expr_loop<'a, 'hir>( cx.asm.label(&end_label)?; if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), span)?; + cx.asm.push(inst::Kind::unit(out), span)?; } cx.asm.label(&break_label)?; @@ -3232,7 +3237,7 @@ fn expr_yield<'a, 'hir>( converge!(expr(cx, e, &mut addr)?, free(addr)); cx.asm.push( - Inst::Yield { + inst::Kind::Yield { addr: addr.addr(), out, }, @@ -3241,7 +3246,7 @@ fn expr_yield<'a, 'hir>( addr.free()?; } else { - cx.asm.push(Inst::YieldUnit { out }, span)?; + cx.asm.push(inst::Kind::YieldUnit { out }, span)?; } Ok(Asm::new(span, ())) @@ -3266,27 +3271,27 @@ fn lit<'a, 'hir>( match hir { hir::Lit::Bool(v) => { - cx.asm.push(Inst::bool(v, out), span)?; + cx.asm.push(inst::Kind::bool(v, out), span)?; } hir::Lit::Char(v) => { - cx.asm.push(Inst::char(v, out), span)?; + cx.asm.push(inst::Kind::char(v, out), span)?; } hir::Lit::Unsigned(v) => { - cx.asm.push(Inst::unsigned(v, out), span)?; + cx.asm.push(inst::Kind::unsigned(v, out), span)?; } hir::Lit::Signed(v) => { - cx.asm.push(Inst::signed(v, out), span)?; + cx.asm.push(inst::Kind::signed(v, out), span)?; } hir::Lit::Float(v) => { - cx.asm.push(Inst::float(v, out), span)?; + cx.asm.push(inst::Kind::float(v, out), span)?; } hir::Lit::Str(string) => { let slot = cx.q.unit.new_static_string(span, string)?; - cx.asm.push(Inst::String { slot, out }, span)?; + cx.asm.push(inst::Kind::String { slot, out }, span)?; } hir::Lit::ByteStr(bytes) => { let slot = cx.q.unit.new_static_bytes(span, bytes)?; - cx.asm.push(Inst::Bytes { slot, out }, span)?; + cx.asm.push(inst::Kind::Bytes { slot, out }, span)?; } }; @@ -3309,7 +3314,7 @@ fn local<'a, 'hir>( // If a value is needed for a let expression, it is evaluated as a unit. if let Some(out) = needs.try_alloc_output()? { - cx.asm.push(Inst::unit(out), hir)?; + cx.asm.push(inst::Kind::unit(out), hir)?; } Ok(Asm::new(hir, ())) diff --git a/crates/rune/src/compile/v1/breaks.rs b/crates/rune/src/compile/v1/breaks.rs index 3e2b0caa5..bd58ecbe4 100644 --- a/crates/rune/src/compile/v1/breaks.rs +++ b/crates/rune/src/compile/v1/breaks.rs @@ -3,7 +3,7 @@ use crate::alloc::prelude::*; use crate::alloc::{self, Vec}; use crate::ast::Spanned; use crate::compile::{self, ErrorKind, WithSpan}; -use crate::runtime::{InstAddress, Label, Output}; +use crate::runtime::{Address, Label, Output}; /// Loops we are inside. #[derive(TryClone)] @@ -18,7 +18,7 @@ pub(crate) struct Break<'hir> { /// The end label of the break, used for `break`. pub(crate) break_label: Label, /// Locals to drop when breaking. - pub(crate) drop: Option, + pub(crate) drop: Option
, } pub(crate) struct Breaks<'hir> { @@ -52,7 +52,7 @@ impl<'hir> Breaks<'hir> { &self, span: &dyn Spanned, expected: &str, - drop: &mut Vec, + drop: &mut Vec
, ) -> compile::Result<&Break<'hir>> { drop.clear(); self.find_label_inner(span, expected, &mut |l| drop.try_extend(l.drop)) diff --git a/crates/rune/src/compile/v1/linear.rs b/crates/rune/src/compile/v1/linear.rs index a5b685c4c..e4e7e936d 100644 --- a/crates/rune/src/compile/v1/linear.rs +++ b/crates/rune/src/compile/v1/linear.rs @@ -5,7 +5,7 @@ use core::slice; use crate::alloc::{vec, Vec}; use crate::compile; -use crate::runtime::InstAddress; +use crate::runtime::inst; use super::Address; @@ -42,10 +42,10 @@ impl<'a, 'hir> Linear<'a, 'hir> { } #[inline] - pub(super) fn addr(&self) -> InstAddress { + pub(super) fn addr(&self) -> inst::Address { match &self.addresses { Addresses::Single(address) => address.addr(), - Addresses::List(list) => list.first().map_or(InstAddress::INVALID, Address::addr), + Addresses::List(list) => list.first().map_or(inst::Address::INVALID, Address::addr), } } diff --git a/crates/rune/src/compile/v1/needs.rs b/crates/rune/src/compile/v1/needs.rs index d8389e20f..572f45fda 100644 --- a/crates/rune/src/compile/v1/needs.rs +++ b/crates/rune/src/compile/v1/needs.rs @@ -3,7 +3,8 @@ use core::mem::replace; use crate::ast::Spanned; use crate::compile; -use crate::runtime::{Inst, InstAddress, Output}; +use crate::runtime::inst; +use crate::runtime::Output; use crate::shared::{rune_diagnose, Backtrace}; use super::{Ctxt, DisplayNamed, ScopeId, Scopes}; @@ -24,7 +25,7 @@ pub(super) trait Needs<'a, 'hir> { fn assign_addr( &mut self, cx: &mut Ctxt<'_, 'hir, '_>, - from: InstAddress, + from: inst::Address, ) -> compile::Result<()>; /// Allocate an output falling back to discarding if one is not available. @@ -65,7 +66,7 @@ impl<'a, 'hir> Needs<'a, 'hir> for Any<'a, 'hir> { fn assign_addr( &mut self, cx: &mut Ctxt<'_, 'hir, '_>, - from: InstAddress, + from: inst::Address, ) -> compile::Result<()> { Any::assign_addr(self, cx, from) } @@ -106,7 +107,7 @@ impl<'a, 'hir> Needs<'a, 'hir> for Address<'a, 'hir> { fn assign_addr( &mut self, cx: &mut Ctxt<'_, 'hir, '_>, - from: InstAddress, + from: inst::Address, ) -> compile::Result<()> { Address::assign_addr(self, cx, from) } @@ -164,7 +165,7 @@ impl fmt::Display for AddressKind { pub(super) struct Address<'a, 'hir> { span: &'hir dyn Spanned, scopes: &'a Scopes<'hir>, - address: InstAddress, + address: inst::Address, kind: AddressKind, /// A diagnostical name for the address. name: Option<&'static str>, @@ -179,7 +180,7 @@ impl<'a, 'hir> Address<'a, 'hir> { pub(super) fn local( span: &'hir dyn Spanned, scopes: &'a Scopes<'hir>, - addr: InstAddress, + addr: inst::Address, ) -> Self { Self { span, @@ -197,7 +198,7 @@ impl<'a, 'hir> Address<'a, 'hir> { pub(super) fn assigned( span: &'hir dyn Spanned, scopes: &'a Scopes<'hir>, - addr: InstAddress, + addr: inst::Address, ) -> Self { Self { span, @@ -215,7 +216,7 @@ impl<'a, 'hir> Address<'a, 'hir> { pub(super) fn dangling( span: &'hir dyn Spanned, scopes: &'a Scopes<'hir>, - addr: InstAddress, + addr: inst::Address, ) -> Self { Self { span, @@ -235,7 +236,7 @@ impl<'a, 'hir> Address<'a, 'hir> { } #[inline] - pub(super) fn addr(&self) -> InstAddress { + pub(super) fn addr(&self) -> inst::Address { self.address } @@ -261,11 +262,11 @@ impl<'a, 'hir> Address<'a, 'hir> { pub(super) fn assign_addr( &self, cx: &mut Ctxt<'_, '_, '_>, - from: InstAddress, + from: inst::Address, ) -> compile::Result<()> { if from != self.address { cx.asm.push( - Inst::Copy { + inst::Kind::Copy { addr: from, out: self.address.output(), }, @@ -425,7 +426,7 @@ impl<'a, 'hir> Any<'a, 'hir> { pub(super) fn assigned( span: &'hir dyn Spanned, scopes: &'a Scopes<'hir>, - addr: InstAddress, + addr: inst::Address, ) -> Self { Self { span, @@ -457,7 +458,7 @@ impl<'a, 'hir> Any<'a, 'hir> { pub(super) fn assign_addr( &mut self, cx: &mut Ctxt<'_, 'hir, '_>, - from: InstAddress, + from: inst::Address, ) -> compile::Result<()> { match &self.kind { AnyKind::Defer { scopes, name, .. } => { diff --git a/crates/rune/src/compile/v1/scopes.rs b/crates/rune/src/compile/v1/scopes.rs index 7f54a490c..9db6139f0 100644 --- a/crates/rune/src/compile/v1/scopes.rs +++ b/crates/rune/src/compile/v1/scopes.rs @@ -7,7 +7,8 @@ use crate::ast::Spanned; use crate::compile::{self, Assembly, ErrorKind, WithSpan}; use crate::hir; use crate::query::Query; -use crate::runtime::{Inst, InstAddress, Output}; +use crate::runtime::inst; +use crate::runtime::Output; use crate::SourceId; use super::{Address, Any, DisplayNamed, Linear, Slab, Slots}; @@ -85,8 +86,8 @@ impl fmt::Debug for ScopeId { /// which they are inserted. #[derive(Default)] struct Dangling { - addresses: Vec>, - address_to_index: HashMap, + addresses: Vec>, + address_to_index: HashMap, } impl Dangling { @@ -95,7 +96,7 @@ impl Dangling { self.address_to_index.clear(); } - fn insert(&mut self, addr: InstAddress) -> alloc::Result<()> { + fn insert(&mut self, addr: inst::Address) -> alloc::Result<()> { if self.address_to_index.contains_key(&addr) { return Ok(()); } @@ -107,7 +108,7 @@ impl Dangling { Ok(()) } - fn remove(&mut self, addr: InstAddress) -> bool { + fn remove(&mut self, addr: inst::Address) -> bool { if let Some(index) = self.address_to_index.remove(&addr) { self.addresses[index] = None; true @@ -118,7 +119,7 @@ impl Dangling { /// Iterate over addresses. #[inline] - fn addresses(&self) -> impl Iterator + '_ { + fn addresses(&self) -> impl Iterator + '_ { self.addresses.iter().filter_map(|addr| *addr) } } @@ -159,7 +160,7 @@ impl<'hir> Scopes<'hir> { } /// Drain dangling addresses into a vector. - pub(crate) fn drain_dangling_into(&self, out: &mut Vec) -> alloc::Result<()> { + pub(crate) fn drain_dangling_into(&self, out: &mut Vec) -> alloc::Result<()> { let mut dangling = self.dangling.borrow_mut(); for addr in dangling.addresses.drain(..).flatten() { @@ -330,7 +331,7 @@ impl<'hir> Scopes<'hir> { return Err(compile::Error::msg(span, "Missing top scope")); }; - let addr = InstAddress::new(self.slots.borrow_mut().insert()?); + let addr = inst::Address::new(self.slots.borrow_mut().insert()?); self.size.set(self.size.get().max(addr.offset() + 1)); scope.locals.insert(addr).with_span(span)?; self.dangling.borrow_mut().remove(addr); @@ -341,7 +342,11 @@ impl<'hir> Scopes<'hir> { /// Declare an anonymous variable. #[tracing::instrument(skip(self, span))] - pub(super) fn alloc_in(&self, span: &dyn Spanned, id: ScopeId) -> compile::Result { + pub(super) fn alloc_in( + &self, + span: &dyn Spanned, + id: ScopeId, + ) -> compile::Result { let mut scopes = self.scopes.borrow_mut(); let Some(scope) = scopes.get_mut(id.index) else { @@ -361,7 +366,7 @@ impl<'hir> Scopes<'hir> { )); } - let addr = InstAddress::new(self.slots.borrow_mut().insert()?); + let addr = inst::Address::new(self.slots.borrow_mut().insert()?); scope.locals.insert(addr).with_span(span)?; self.size.set(self.size.get().max(addr.offset() + 1)); self.dangling.borrow_mut().remove(addr); @@ -388,7 +393,7 @@ impl<'hir> Scopes<'hir> { let linear = match n { 0 => Linear::empty(), 1 => { - let addr = InstAddress::new(self.slots.borrow_mut().insert()?); + let addr = inst::Address::new(self.slots.borrow_mut().insert()?); scope.locals.insert(addr).with_span(span)?; dangling.remove(addr); self.size.set(self.size.get().max(addr.offset() + 1)); @@ -399,7 +404,7 @@ impl<'hir> Scopes<'hir> { let mut addresses = Vec::try_with_capacity(n).with_span(span)?; for _ in 0..n { - let addr = InstAddress::new(slots.push().with_span(span)?); + let addr = inst::Address::new(slots.push().with_span(span)?); scope.locals.insert(addr).with_span(span)?; dangling.remove(addr); addresses.try_push(Address::dangling(span, self, addr))?; @@ -419,7 +424,7 @@ impl<'hir> Scopes<'hir> { pub(super) fn free_addr( &self, span: &dyn Spanned, - addr: InstAddress, + addr: inst::Address, name: Option<&'static str>, dangling: bool, ) -> compile::Result<()> { @@ -587,7 +592,7 @@ pub(super) struct Var<'hir> { /// The name of the variable. name: hir::Variable, /// Address where the variable is currently live. - pub(super) addr: InstAddress, + pub(super) addr: inst::Address, } impl fmt::Debug for Var<'_> { @@ -617,7 +622,7 @@ impl Var<'_> { out: Output, ) -> compile::Result<()> { asm.push_with_comment( - Inst::Copy { + inst::Kind::Copy { addr: self.addr, out, }, @@ -635,7 +640,7 @@ impl Var<'_> { out: Output, ) -> compile::Result<()> { asm.push_with_comment( - Inst::Move { + inst::Kind::Move { addr: self.addr, out, }, @@ -671,7 +676,7 @@ struct VarInner<'hir> { /// The name of the variable. name: hir::Variable, /// Offset from the current stack frame. - addr: InstAddress, + addr: inst::Address, /// Variable has been taken at the given position. moved_at: Cell>, } diff --git a/crates/rune/src/diagnostics/emit.rs b/crates/rune/src/diagnostics/emit.rs index 8b891c1d5..7a921f4f3 100644 --- a/crates/rune/src/diagnostics/emit.rs +++ b/crates/rune/src/diagnostics/emit.rs @@ -196,8 +196,8 @@ impl VmError { } } - let mut labels = ::rust_alloc::vec::Vec::new(); - let mut notes = ::rust_alloc::vec::Vec::new(); + let mut labels = rust_alloc::vec::Vec::new(); + let mut notes = rust_alloc::vec::Vec::new(); let get = |at: &VmErrorAt| -> Option<&DebugInst> { let l = self.inner.stacktrace.get(at.index())?; @@ -531,8 +531,8 @@ fn warning_diagnostics_emit( where O: WriteColor, { - let mut notes = ::rust_alloc::vec::Vec::new(); - let mut labels = ::rust_alloc::vec::Vec::new(); + let mut notes = rust_alloc::vec::Vec::new(); + let mut labels = rust_alloc::vec::Vec::new(); labels.push( d::Label::primary(this.source_id(), this.span().range()) @@ -593,8 +593,8 @@ fn runtime_warning_diagnostics_emit( where O: WriteColor, { - let mut notes = ::rust_alloc::vec::Vec::new(); - let mut labels = ::rust_alloc::vec::Vec::new(); + let mut notes = rust_alloc::vec::Vec::new(); + let mut labels = rust_alloc::vec::Vec::new(); let mut message = String::new(); match this.kind { @@ -648,8 +648,8 @@ fn fatal_diagnostics_emit( where O: WriteColor, { - let mut labels = ::rust_alloc::vec::Vec::new(); - let mut notes = ::rust_alloc::vec::Vec::new(); + let mut labels = rust_alloc::vec::Vec::new(); + let mut notes = rust_alloc::vec::Vec::new(); if let Some(span) = this.span() { labels.push( @@ -666,7 +666,7 @@ where FatalDiagnosticKind::LinkError(error) => { match error { LinkerError::MissingFunction { hash, spans } => { - let mut labels = ::rust_alloc::vec::Vec::new(); + let mut labels = rust_alloc::vec::Vec::new(); for (span, source_id) in spans { labels.push( @@ -713,8 +713,8 @@ where sources: &Sources, span: Span, kind: &ErrorKind, - labels: &mut ::rust_alloc::vec::Vec>, - notes: &mut ::rust_alloc::vec::Vec, + labels: &mut rust_alloc::vec::Vec>, + notes: &mut rust_alloc::vec::Vec, ) -> Result<(), EmitError> { match kind { ErrorKind::ImportCycle { path } => { diff --git a/crates/rune/src/diagnostics/fatal.rs b/crates/rune/src/diagnostics/fatal.rs index af4c8f3bb..074818cf1 100644 --- a/crates/rune/src/diagnostics/fatal.rs +++ b/crates/rune/src/diagnostics/fatal.rs @@ -1,6 +1,6 @@ use core::fmt; -use ::rust_alloc::boxed::Box; +use rust_alloc::boxed::Box; #[cfg(feature = "emit")] use crate::ast::{Span, Spanned}; diff --git a/crates/rune/src/diagnostics/mod.rs b/crates/rune/src/diagnostics/mod.rs index 0a95b5574..dd8d2fca8 100644 --- a/crates/rune/src/diagnostics/mod.rs +++ b/crates/rune/src/diagnostics/mod.rs @@ -41,8 +41,8 @@ pub use self::runtime_warning::RuntimeWarningDiagnostic; pub(crate) use self::runtime_warning::RuntimeWarningDiagnosticKind; mod runtime_warning; -use ::rust_alloc::boxed::Box; use rune_alloc::String; +use rust_alloc::boxed::Box; use crate::alloc::{self, Vec}; use crate::ast::Spanned; diff --git a/crates/rune/src/diagnostics/runtime_warning.rs b/crates/rune/src/diagnostics/runtime_warning.rs index 560dfa16c..f690e8ad9 100644 --- a/crates/rune/src/diagnostics/runtime_warning.rs +++ b/crates/rune/src/diagnostics/runtime_warning.rs @@ -39,12 +39,7 @@ impl fmt::Display for RuntimeWarningDiagnostic { } } -impl core::error::Error for RuntimeWarningDiagnostic { - #[inline] - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - None - } -} +impl core::error::Error for RuntimeWarningDiagnostic {} /// The kind of a [RuntimeWarningDiagnostic]. #[derive(Debug)] diff --git a/crates/rune/src/doc/build.rs b/crates/rune/src/doc/build.rs index a8345f7d5..970da7acc 100644 --- a/crates/rune/src/doc/build.rs +++ b/crates/rune/src/doc/build.rs @@ -634,7 +634,7 @@ impl<'m> Ctxt<'_, 'm> { let mut it = self .context - .meta_by_hash(hash)? + .meta_by_hash(hash.get())? .into_iter() .flat_map(|m| Some((m, into_item_kind(m)?))); @@ -642,7 +642,7 @@ impl<'m> Ctxt<'_, 'm> { let Some((meta, kind)) = it.next() else { tracing::warn!(?hash, "No link for hash"); - for _meta in self.context.meta_by_hash(hash)? { + for _meta in self.context.meta_by_hash(hash.get())? { tracing::warn!("Candidate: {:?}", _meta.kind); } @@ -721,7 +721,7 @@ impl<'m> Ctxt<'_, 'm> { while let Some(arg) = it.next() { if matches!(sig, Signature::Instance) && arg.name.is_self() { if let Some(hash) = arg.base.as_non_empty() { - self.write_link(&mut string, hash, Some("self"), &[])?; + self.write_link(&mut string, hash.get(), Some("self"), &[])?; } else { write!(string, "self")?; } diff --git a/crates/rune/src/doc/templating.rs b/crates/rune/src/doc/templating.rs index f47316d8e..482a9eaf8 100644 --- a/crates/rune/src/doc/templating.rs +++ b/crates/rune/src/doc/templating.rs @@ -1,8 +1,9 @@ +use rust_alloc::sync::Arc; + use crate::alloc::borrow::Cow; use crate::alloc::prelude::*; use crate::alloc::{self, HashMap, String}; use crate::std::sync::Mutex; -use ::rust_alloc::sync::Arc; use handlebars::{ Context, Handlebars, Helper, HelperDef, HelperResult, Output, RenderContext, Renderable, @@ -61,8 +62,8 @@ impl Templating { I: IntoIterator)>, { let mut handlebars = Handlebars::new(); - handlebars.register_helper("literal", ::rust_alloc::boxed::Box::new(literal)); - handlebars.register_helper("path", ::rust_alloc::boxed::Box::new(path(paths))); + handlebars.register_helper("literal", rust_alloc::boxed::Box::new(literal)); + handlebars.register_helper("path", rust_alloc::boxed::Box::new(path(paths))); for (name, source) in partials { handlebars.register_partial(name, source.as_ref())?; diff --git a/crates/rune/src/exported_macros.rs b/crates/rune/src/exported_macros.rs index a57fa4fdc..89463d5bd 100644 --- a/crates/rune/src/exported_macros.rs +++ b/crates/rune/src/exported_macros.rs @@ -6,12 +6,38 @@ /// [`rune::function`]: macro@crate::function /// [`VmResult`]: crate::runtime::VmResult #[macro_export] -macro_rules! vm_try { +#[doc(hidden)] +#[deprecated = "Use `?` on `VmResult` instead of this macro."] +macro_rules! __vm_try { ($expr:expr) => { - match $crate::runtime::try_result($expr) { - $crate::runtime::VmResult::Ok(value) => value, - $crate::runtime::VmResult::Err(err) => { - return $crate::runtime::VmResult::Err(err); + match $expr { + Ok(value) => value, + Err(err) => { + return Err($crate::VmError::from(err)); + } + } + }; +} + +/// Helper to perform the try operation over an inner value of a +/// `Result, U>`, this will check an error of type `Result` +/// and return it as `Ok(Err(E))` if it is. +/// +/// This is useful because functions in Rune can return different kinds of +/// errors. One is a critical error for the virtual machine, most typically +/// `VmErro`. And another is a logical error that should be returned and handled +/// by the program. +#[macro_export] +#[doc(hidden)] +macro_rules! __nested_try { + ($expr:expr) => { + match $expr { + Ok(value) => value, + Err(err) => { + return Ok(Err( + #[allow(clippy::useless_conversion)] + ::core::convert::From::from(err), + )); } } }; @@ -39,9 +65,10 @@ macro_rules! vm_try { /// } /// ``` #[macro_export] -macro_rules! vm_panic { +#[doc(hidden)] +macro_rules! __vm_panic { ($expr:expr) => {{ - return $crate::runtime::VmResult::panic($expr); + return Err($crate::runtime::VmError::panic($expr)); }}; } @@ -50,11 +77,13 @@ macro_rules! vm_panic { /// /// [`VmResult`]: crate::runtime::VmResult #[macro_export] -macro_rules! vm_write { +#[doc(hidden)] +#[deprecated = "Convert any relevant errors to `VmError` instead of using this macro using for example `write!(..)?`."] +macro_rules! __vm_write { ($($tt:tt)*) => { match core::write!($($tt)*) { - Ok(()) => $crate::runtime::VmResult::Ok(()), - Err(err) => $crate::runtime::VmResult::Err($crate::runtime::VmError::from(err)), + Ok(()) => Ok(()), + Err(err) => Err($crate::runtime::VmError::from(err)), } }; } @@ -72,8 +101,22 @@ macro_rules! vm_write { /// }; /// ``` #[macro_export] -macro_rules! docstring { +#[doc(hidden)] +macro_rules! __docstring { ($(#[doc = $doc:expr])*) => { [$($doc),*] }; } + +#[doc(inline)] +pub use __docstring as docstring; +#[doc(inline)] +pub use __nested_try as nested_try; +#[doc(inline)] +pub use __vm_panic as vm_panic; +#[doc(inline)] +#[allow(deprecated)] +pub use __vm_try as vm_try; +#[doc(inline)] +#[allow(deprecated)] +pub use __vm_write as vm_write; diff --git a/crates/rune/src/function/mod.rs b/crates/rune/src/function/mod.rs index bf0d3f1ff..9a0c0f90b 100644 --- a/crates/rune/src/function/mod.rs +++ b/crates/rune/src/function/mod.rs @@ -8,21 +8,21 @@ use crate::alloc; use crate::compile::meta; use crate::hash::Hash; use crate::runtime::{ - self, AnyTypeInfo, FromValue, InstAddress, MaybeTypeOf, Memory, Output, RuntimeError, ToReturn, - TypeHash, TypeOf, UnsafeToMut, UnsafeToRef, Value, VmErrorKind, VmResult, + self, Address, AnyTypeInfo, FromValue, IntoReturn, MaybeTypeOf, Memory, Output, RuntimeError, + TypeHash, TypeOf, UnsafeToMut, UnsafeToRef, Value, VmError, VmErrorKind, }; // Expand to function variable bindings. macro_rules! access_memory { ($count:expr, $add:expr, $memory:ident, $addr:ident, $args:ident, $($from_fn:path, $var:ident, $num:expr),* $(,)?) => { if $args != $count + $add { - return VmResult::err(VmErrorKind::BadArgumentCount { + return Err(VmError::new(VmErrorKind::BadArgumentCount { actual: $args, expected: $count + $add, - }); + })); } - let [$($var,)*] = vm_try!($memory.slice_at_mut($addr, $args)) else { + let [$($var,)*] = $memory.slice_at_mut($addr, $args)? else { unreachable!(); }; @@ -32,9 +32,9 @@ macro_rules! access_memory { let $var = match $from_fn($var) { Ok($var) => $var, Err(error) => { - return VmResult::err(error).with_error(|| VmErrorKind::BadArgument { + return Err(VmError::with_error(VmError::from(error), VmErrorKind::BadArgument { arg: $num, - }); + })); } }; )* @@ -80,13 +80,13 @@ pub trait Function: 'static + Send + Sync { /// Perform the vm call. #[doc(hidden)] - fn fn_call( + fn call( &self, memory: &mut dyn Memory, - addr: InstAddress, + addr: Address, args: usize, out: Output, - ) -> VmResult<()>; + ) -> Result<(), VmError>; } /// Trait used to provide the [`associated_function`] function. @@ -110,13 +110,13 @@ pub trait InstanceFunction: 'static + Send + Sync { /// Perform the vm call. #[doc(hidden)] - fn fn_call( + fn call( &self, memory: &mut dyn Memory, - addr: InstAddress, + addr: Address, args: usize, out: Output, - ) -> VmResult<()>; + ) -> Result<(), VmError>; } macro_rules! impl_instance_function_traits { @@ -132,8 +132,8 @@ macro_rules! impl_instance_function_traits { const ARGS: usize = >::ARGS; #[inline] - fn fn_call(&self, memory: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - Function::fn_call(self, memory, addr, args, out) + fn call(&self, memory: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { + Function::call(self, memory, addr, args, out) } } }; @@ -233,7 +233,7 @@ macro_rules! impl_function_traits { impl Function<($($place,)*), Plain> for T where T: 'static + Send + Sync + Fn($($($mut)* $ty),*) -> U, - U: ToReturn, + U: IntoReturn, $($ty: $($trait)*,)* { type Return = U; @@ -241,7 +241,7 @@ macro_rules! impl_function_traits { const ARGS: usize = $count; #[allow(clippy::drop_non_drop)] - fn fn_call(&self, memory: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + fn call(&self, memory: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { access_memory!($count, 0, memory, addr, args, $($from_fn, $var, $num,)*); // Safety: We hold a reference to memory, so we can guarantee @@ -249,17 +249,16 @@ macro_rules! impl_function_traits { let ret = self($($var.0),*); $(drop($var.1);)* - let value = vm_try!(ToReturn::to_return(ret)); - vm_try!(out.store(memory, value)); - VmResult::Ok(()) + let value = IntoReturn::into_return(ret)?; + out.store(memory, value)?; + Ok(()) } } impl Function<($($place,)*), Async> for T where T: 'static + Send + Sync + Fn($($($mut)* $ty),*) -> U, - U: 'static + Future, - U::Output: ToReturn, + U: 'static + Future, $($ty: $($trait)*,)* { type Return = U::Output; @@ -267,7 +266,7 @@ macro_rules! impl_function_traits { const ARGS: usize = $count; #[allow(clippy::drop_non_drop)] - fn fn_call(&self, memory: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + fn call(&self, memory: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { access_memory!($count, 0, memory, addr, args, $($from_fn, $var, $num,)*); let fut = self($($var.0),*); @@ -277,14 +276,13 @@ macro_rules! impl_function_traits { // used. $(drop($var.1);)* - let ret = vm_try!(runtime::Future::new(async move { - let output = fut.await; - VmResult::Ok(vm_try!(ToReturn::to_return(output))) - })); + let ret = runtime::Future::new(async move { + IntoReturn::into_return(fut.await) + })?; - let value = vm_try!(Value::try_from(ret)); - vm_try!(out.store(memory, value)); - VmResult::Ok(()) + let value = Value::try_from(ret)?; + out.store(memory, value)?; + Ok(()) } } }; diff --git a/crates/rune/src/function_meta.rs b/crates/rune/src/function_meta.rs index 1f87f518d..eed130767 100644 --- a/crates/rune/src/function_meta.rs +++ b/crates/rune/src/function_meta.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc; @@ -51,7 +51,7 @@ pub type MacroMeta = fn() -> alloc::Result; /// Runtime data for a function. pub struct FunctionData { pub(crate) item: ItemBuf, - pub(crate) handler: Arc, + pub(crate) handler: FunctionHandler, #[cfg(feature = "doc")] pub(crate) is_async: bool, #[cfg(feature = "doc")] @@ -63,7 +63,7 @@ pub struct FunctionData { } impl FunctionData { - pub(crate) fn from_raw(item: ItemBuf, handler: Arc) -> Self { + pub(crate) fn from_raw(item: ItemBuf, handler: FunctionHandler) -> Self { Self { item, handler, @@ -79,18 +79,18 @@ impl FunctionData { } #[inline] - pub(crate) fn new(name: N, f: F) -> alloc::Result + pub(crate) fn new(name: N, f: F) -> alloc::Result where - F: Function, N: IntoComponent, + F: Function, A: FunctionArgs, K: FunctionKind, { Ok(Self { item: ItemBuf::with_item([name])?, - handler: Arc::new(move |stack, addr, args, output| { - f.fn_call(stack, addr, args, output) - }), + handler: FunctionHandler::new(move |stack, addr, args, output| { + f.call(stack, addr, args, output) + })?, #[cfg(feature = "doc")] is_async: K::IS_ASYNC, #[cfg(feature = "doc")] @@ -117,8 +117,7 @@ impl FunctionMacroData { + Send + Sync + Fn(&mut MacroContext<'_, '_, '_>, &TokenStream) -> compile::Result, - N: IntoIterator, - N::Item: IntoComponent, + N: IntoIterator, { Ok(Self { item: ItemBuf::with_item(name)?, @@ -145,8 +144,7 @@ impl AttributeMacroData { &TokenStream, &TokenStream, ) -> compile::Result, - N: IntoIterator, - N::Item: IntoComponent, + N: IntoIterator, { Ok(Self { item: ItemBuf::with_item(name)?, @@ -261,7 +259,7 @@ impl Associated { /// Runtime data for an associated function. pub struct AssociatedFunctionData { pub(crate) associated: Associated, - pub(crate) handler: Arc, + pub(crate) handler: FunctionHandler, #[cfg(feature = "doc")] pub(crate) is_async: bool, #[cfg(feature = "doc")] @@ -273,7 +271,7 @@ pub struct AssociatedFunctionData { } impl AssociatedFunctionData { - pub(crate) fn from_raw(associated: Associated, handler: Arc) -> Self { + pub(crate) fn from_raw(associated: Associated, handler: FunctionHandler) -> Self { Self { associated, handler, @@ -297,9 +295,9 @@ impl AssociatedFunctionData { { Ok(Self { associated, - handler: Arc::new(move |stack, addr, args, output| { - f.fn_call(stack, addr, args, output) - }), + handler: FunctionHandler::new(move |stack, addr, args, output| { + f.call(stack, addr, args, output) + })?, #[cfg(feature = "doc")] is_async: K::IS_ASYNC, #[cfg(feature = "doc")] @@ -320,9 +318,9 @@ impl AssociatedFunctionData { { Ok(Self { associated: Associated::from_type::(name)?, - handler: Arc::new(move |stack, addr, args, output| { - f.fn_call(stack, addr, args, output) - }), + handler: FunctionHandler::new(move |stack, addr, args, output| { + f.call(stack, addr, args, output) + })?, #[cfg(feature = "doc")] is_async: K::IS_ASYNC, #[cfg(feature = "doc")] @@ -335,7 +333,7 @@ impl AssociatedFunctionData { } } -/// The kind of a [`FunctionMeta`]. +/// The kind of a `FunctionMeta`. /// /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. @@ -441,7 +439,7 @@ where } } -/// The kind of a [`FunctionMeta`]. +/// The kind of a `FunctionMeta`. /// /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. @@ -462,8 +460,7 @@ impl MacroMetaKind { + Send + Sync + Fn(&mut MacroContext<'_, '_, '_>, &TokenStream) -> compile::Result, - N: IntoIterator, - N::Item: IntoComponent, + N: IntoIterator, { Ok(Self::Function(FunctionMacroData::new(name, f)?)) } @@ -480,14 +477,13 @@ impl MacroMetaKind { &TokenStream, &TokenStream, ) -> compile::Result, - N: IntoIterator, - N::Item: IntoComponent, + N: IntoIterator, { Ok(Self::Attribute(AttributeMacroData::new(name, f)?)) } } -/// The data of a [`MacroMeta`]. +/// The data of a `MacroMeta`. /// /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. @@ -514,7 +510,7 @@ pub struct FunctionMetaStatics { pub arguments: &'static [&'static str], } -/// The data of a [`FunctionMeta`]. +/// The data of a `FunctionMeta`. /// /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. diff --git a/crates/rune/src/hash.rs b/crates/rune/src/hash.rs index f23247129..ede8b08a6 100644 --- a/crates/rune/src/hash.rs +++ b/crates/rune/src/hash.rs @@ -7,7 +7,9 @@ use core::hash::{BuildHasher, Hasher}; const SEED: u64 = 18446744073709551557u64; #[doc(inline)] -pub use rune_core::hash::{Hash, IntoHash, ParametersBuilder, ToTypeHash, TooManyParameters}; +pub use rune_core::hash::{ + Hash, IntoHash, NonZeroHash, ParametersBuilder, ToTypeHash, TooManyParameters, +}; /// A hash map suitable for storing values with hash keys. pub(crate) type Map = HashMap; diff --git a/crates/rune/src/hashbrown/table.rs b/crates/rune/src/hashbrown/table.rs index 2630e1c13..1deb77e85 100644 --- a/crates/rune/src/hashbrown/table.rs +++ b/crates/rune/src/hashbrown/table.rs @@ -7,14 +7,10 @@ use core::mem; use core::ptr; use crate::alloc; -use crate::alloc::prelude::*; - -#[cfg(feature = "alloc")] -use crate::runtime::Hasher; -use crate::runtime::{ProtocolCaller, RawAnyGuard, Ref, Value, VmError, VmResult}; - use crate::alloc::hashbrown::raw::{RawIter, RawTable}; use crate::alloc::hashbrown::ErrorOrInsertSlot; +use crate::alloc::prelude::*; +use crate::runtime::{Hasher, ProtocolCaller, RawAnyGuard, Ref, Value, VmError}; pub(crate) struct Table { table: RawTable<(Value, V)>, @@ -59,8 +55,8 @@ impl Table { key: Value, value: V, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { - let hash = vm_try!(hash(&self.state, &key, caller)); + ) -> Result, VmError> { + let hash = hash(&self.state, &key, caller)?; let existing = match self.table.find_or_find_insert_slot( caller, @@ -75,23 +71,23 @@ impl Table { } None } - Err(ErrorOrInsertSlot::Error(error)) => return VmResult::err(error), + Err(ErrorOrInsertSlot::Error(error)) => return Err(VmError::from(error)), }; - VmResult::Ok(existing) + Ok(existing) } pub(crate) fn get( &self, key: &Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { if self.table.is_empty() { - return VmResult::Ok(None); + return Ok(None); } - let hash = vm_try!(hash(&self.state, key, caller)); - VmResult::Ok(vm_try!(self.table.get(caller, hash, KeyEq::new(key)))) + let hash = hash(&self.state, key, caller)?; + self.table.get(caller, hash, KeyEq::new(key)) } #[inline(always)] @@ -99,12 +95,12 @@ impl Table { &mut self, key: &Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { - let hash = vm_try!(hash(&self.state, key, caller)); + ) -> Result, VmError> { + let hash = hash(&self.state, key, caller)?; match self.table.remove_entry(caller, hash, KeyEq::new(key)) { - Ok(value) => VmResult::Ok(value.map(|(_, value)| value)), - Err(error) => VmResult::Err(error), + Ok(value) => Ok(value.map(|(_, value)| value)), + Err(error) => Err(error), } } @@ -282,13 +278,13 @@ where } /// Convenience function to hash a value. -fn hash(state: &S, value: &Value, caller: &mut dyn ProtocolCaller) -> VmResult +fn hash(state: &S, value: &Value, caller: &mut dyn ProtocolCaller) -> Result where S: BuildHasher, { let mut hasher = Hasher::new_with(state); - vm_try!(value.hash_with(&mut hasher, caller)); - VmResult::Ok(hasher.finish()) + value.hash_with(&mut hasher, caller)?; + Ok(hasher.finish()) } struct StateHasher<'a> { @@ -305,7 +301,7 @@ impl<'a> StateHasher<'a> { impl alloc::hashbrown::HasherFn for StateHasher<'_> { #[inline] fn hash(&self, cx: &mut dyn ProtocolCaller, (key, _): &(Value, V)) -> Result { - hash(self.state, key, cx).into_result() + hash(self.state, key, cx) } } @@ -325,6 +321,6 @@ impl<'a> KeyEq<'a> { impl alloc::hashbrown::EqFn for KeyEq<'_> { #[inline] fn eq(&self, cx: &mut dyn ProtocolCaller, (other, _): &(Value, V)) -> Result { - self.key.eq_with(other, cx).into_result() + self.key.eq_with(other, cx) } } diff --git a/crates/rune/src/hir/lowering.rs b/crates/rune/src/hir/lowering.rs index 4a8aa019f..3939ec8f2 100644 --- a/crates/rune/src/hir/lowering.rs +++ b/crates/rune/src/hir/lowering.rs @@ -1659,19 +1659,24 @@ fn struct_match_for( (fields, kind) } + meta::Kind::Type { .. } if open => { + return Ok(Some(( + HashSet::new(), + hir::PatSequenceKind::Type { hash: meta.hash }, + ))); + } _ => { return Ok(None); } }; let fields = match fields { - meta::Fields::Unnamed(0) if open => HashSet::new(), - meta::Fields::Empty if open => HashSet::new(), meta::Fields::Named(st) => st .fields .iter() .map(|f| f.name.try_clone()) .try_collect::>()??, + _ if open => HashSet::new(), _ => return Ok(None), }; diff --git a/crates/rune/src/hir/lowering2.rs b/crates/rune/src/hir/lowering2.rs index 0d229e58d..8347e71a3 100644 --- a/crates/rune/src/hir/lowering2.rs +++ b/crates/rune/src/hir/lowering2.rs @@ -2648,19 +2648,24 @@ fn struct_match_for( (fields, kind) } + meta::Kind::Type { .. } if open => { + return Ok(Some(( + HashSet::new(), + hir::PatSequenceKind::Type { hash: meta.hash }, + ))); + } _ => { return Ok(None); } }; let fields = match fields { - meta::Fields::Unnamed(0) if open => HashSet::new(), - meta::Fields::Empty if open => HashSet::new(), meta::Fields::Named(st) => st .fields .iter() .map(|f| f.name.try_clone()) .try_collect::>()??, + _ if open => HashSet::new(), _ => return Ok(None), }; diff --git a/crates/rune/src/internal_macros.rs b/crates/rune/src/internal_macros.rs index 439a8fd16..09a2613b4 100644 --- a/crates/rune/src/internal_macros.rs +++ b/crates/rune/src/internal_macros.rs @@ -62,3 +62,55 @@ macro_rules! assert_impl { }; }; } + +/// Asynchronous helper to perform the try operation over an asynchronous +/// `Result`. +#[macro_export] +#[doc(hidden)] +macro_rules! __async_vm_try { + ($expr:expr) => { + match $expr { + ::core::result::Result::Ok(value) => value, + ::core::result::Result::Err(err) => { + return ::core::task::Poll::Ready(::core::result::Result::Err( + ::core::convert::From::from(err), + )); + } + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __vm_error { + ($ty:ty) => { + impl $crate::runtime::MaybeTypeOf for Result + where + T: $crate::runtime::MaybeTypeOf, + { + #[inline] + fn maybe_type_of() -> $crate::alloc::Result<$crate::compile::meta::DocType> { + ::maybe_type_of() + } + } + + impl $crate::runtime::IntoReturn for Result + where + T: $crate::runtime::ToValue, + { + #[inline] + fn into_return(self) -> Result<$crate::runtime::Value, $crate::runtime::VmError> { + match self { + Ok(value) => Ok(value.to_value()?), + Err(error) => Err($crate::runtime::VmError::from(error)), + } + } + } + }; +} + +#[doc(inline)] +pub(crate) use __async_vm_try as async_vm_try; + +#[doc(inline)] +pub(crate) use __vm_error as vm_error; diff --git a/crates/rune/src/languageserver/completion.rs b/crates/rune/src/languageserver/completion.rs index 53cfa8229..94d9b1a65 100644 --- a/crates/rune/src/languageserver/completion.rs +++ b/crates/rune/src/languageserver/completion.rs @@ -124,7 +124,7 @@ pub(super) fn complete_native_instance_data( .return_type .base .as_non_empty() - .and_then(|hash| context.lookup_meta_by_hash(hash).next()) + .and_then(|hash| context.lookup_meta_by_hash(hash.get()).next()) .and_then(|r| r.item.as_deref()); let docs = meta.docs.lines().join("\n"); @@ -189,7 +189,7 @@ pub(super) fn complete_native_loose_data( .return_type .base .as_non_empty() - .and_then(|hash| context.lookup_meta_by_hash(hash).next()) + .and_then(|hash| context.lookup_meta_by_hash(hash.get()).next()) .and_then(|r| r.item.as_deref()); let docs = meta.docs.lines().join("\n"); diff --git a/crates/rune/src/languageserver/connection.rs b/crates/rune/src/languageserver/connection.rs index 652968380..3e7ff06b8 100644 --- a/crates/rune/src/languageserver/connection.rs +++ b/crates/rune/src/languageserver/connection.rs @@ -1,6 +1,6 @@ use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use anyhow::{anyhow, bail, Result}; use tokio::io; @@ -20,7 +20,7 @@ pub(super) struct Frame<'a> { /// Input connection. pub(super) struct Input { - buf: ::rust_alloc::vec::Vec, + buf: rust_alloc::vec::Vec, stdin: BufReader, } @@ -139,10 +139,10 @@ impl Output { } /// Write the given response body. - async fn write_response(&self, bytes: &mut ::rust_alloc::vec::Vec) -> Result<()> { + async fn write_response(&self, bytes: &mut rust_alloc::vec::Vec) -> Result<()> { use std::io::Write as _; - let mut m = ::rust_alloc::vec::Vec::new(); + let mut m = rust_alloc::vec::Vec::new(); write!(m, "Content-Length: {}\r\n", bytes.len())?; write!(m, "\r\n")?; @@ -161,7 +161,7 @@ pub(super) fn stdio() -> Result<(Input, Output)> { let stdout = io::stdout(); let input = Input { - buf: ::rust_alloc::vec::Vec::new(), + buf: rust_alloc::vec::Vec::new(), stdin: BufReader::new(stdin), }; @@ -186,7 +186,7 @@ pub(super) struct Headers { impl Headers { /// Read headers from the given line stream. pub(super) async fn read( - buf: &mut ::rust_alloc::vec::Vec, + buf: &mut rust_alloc::vec::Vec, reader: &mut S, ) -> anyhow::Result> where diff --git a/crates/rune/src/languageserver/mod.rs b/crates/rune/src/languageserver/mod.rs index 6323fad53..4cbb5f115 100644 --- a/crates/rune/src/languageserver/mod.rs +++ b/crates/rune/src/languageserver/mod.rs @@ -267,7 +267,7 @@ async fn completion( async fn formatting( state: &mut State<'_>, params: lsp::DocumentFormattingParams, -) -> Result>> { +) -> Result>> { state .format(¶ms.text_document.uri) .map(|option| option.map(|formatted| vec![formatted])) @@ -277,7 +277,7 @@ async fn formatting( async fn range_formatting( state: &mut State<'_>, params: lsp::DocumentRangeFormattingParams, -) -> Result>> { +) -> Result>> { state .range_format(¶ms.text_document.uri, ¶ms.range) .map(|option| option.map(|formatted| vec![formatted])) diff --git a/crates/rune/src/languageserver/state.rs b/crates/rune/src/languageserver/state.rs index 8a9189d1b..0e627fd24 100644 --- a/crates/rune/src/languageserver/state.rs +++ b/crates/rune/src/languageserver/state.rs @@ -618,7 +618,7 @@ impl<'a> State<'a> { let mut options = self.options.clone(); if !build.workspace { - options.function_body = true; + options.script = true; } let unit = crate::prepare(&mut build.sources) diff --git a/crates/rune/src/lib.rs b/crates/rune/src/lib.rs index 127b5d731..8f7ab358d 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.81+. +//! Minimum support: Rust 1.87+. //!
//!
//! Visit the site 🌐 @@ -186,14 +186,18 @@ pub mod no_std; #[macro_use] mod internal_macros; +pub(crate) use self::internal_macros::{async_vm_try, vm_error}; -#[macro_use] mod exported_macros; +#[doc(inline)] +#[allow(deprecated)] +pub use self::exported_macros::{docstring, nested_try, vm_panic, vm_try, vm_write}; #[macro_use] pub mod ast; #[cfg(feature = "fmt")] +#[cfg_attr(rune_docsrs, doc(cfg(feature = "fmt")))] pub mod fmt; #[cfg(feature = "emit")] @@ -202,6 +206,7 @@ pub mod fmt; pub use ::codespan_reporting::term::termcolor; pub(crate) mod any; +#[doc(inline)] pub use self::any::Any; mod build; @@ -230,9 +235,8 @@ pub use self::diagnostics::Diagnostics; pub mod hash; #[doc(inline)] -pub use self::hash::{Hash, ToTypeHash}; +pub use self::hash::{Hash, NonZeroHash, ToTypeHash}; -#[cfg(feature = "alloc")] mod hashbrown; mod params; @@ -255,8 +259,8 @@ pub mod query; pub mod runtime; #[doc(inline)] pub use self::runtime::{ - from_const_value, from_value, to_const_value, to_value, FromValue, Mut, Ref, ToConstValue, - ToValue, TypeHash, Unit, Value, Vm, + from_const_value, from_value, to_const_value, to_value, FromConstValue, FromValue, Mut, Ref, + ToConstValue, ToValue, TypeHash, Unit, Value, Vm, VmError, }; mod shared; @@ -279,6 +283,44 @@ pub mod support; #[cfg_attr(rune_docsrs, doc(cfg(feature = "workspace")))] pub mod workspace; +/// Macro used to annotate native functions which can be loaded as attribute +/// macros in rune. +/// +/// See [`Module::macro_meta`][crate::Module::macro_meta]. +/// +/// # Examples +/// +/// ``` +/// use rune::Module; +/// use rune::ast; +/// use rune::compile; +/// use rune::macros::{quote, MacroContext, TokenStream}; +/// use rune::parse::Parser; +/// use rune::alloc::prelude::*; +/// +/// /// Takes an identifier and converts it into a string. +/// /// +/// /// # Examples +/// /// +/// /// ```rune +/// /// assert_eq!(ident_to_string!(Hello), "Hello"); +/// /// ``` +/// #[rune::macro_] +/// fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result { +/// let mut p = Parser::from_token_stream(stream, cx.input_span()); +/// let ident = p.parse_all::()?; +/// let ident = cx.resolve(ident)?.try_to_owned()?; +/// let string = cx.lit(&ident)?; +/// Ok(quote!(#string).into_token_stream(cx)?) +/// } +/// +/// let mut m = Module::new(); +/// m.macro_meta(ident_to_string)?; +/// # Ok::<_, rune::support::Error>(()) +/// ``` +#[doc(inline)] +pub use rune_macros::attribute_macro; + /// Macro used to annotate native functions which can be loaded into rune. /// /// This macro automatically performs the following things: @@ -398,17 +440,19 @@ pub mod workspace; /// define a protocol externally, you can simply do this: /// /// ```rust -/// # use rune::Any; -/// # use rune::runtime::{Formatter, VmResult}; +/// use rune::Any; +/// use rune::runtime::Formatter; +/// use rune::alloc::fmt::TryWrite; +/// use rune::alloc; +/// /// #[derive(Any)] /// struct Struct { /// /* .. */ /// } /// /// #[rune::function(instance, protocol = DISPLAY_FMT)] -/// fn display_fmt(this: &Struct, f: &mut Formatter) -> VmResult<()> { -/// /* .. */ -/// # todo!() +/// fn display_fmt(this: &Struct, f: &mut Formatter) -> alloc::Result<()> { +/// write!(f, "Struct {{ /* .. */ }}") /// } /// ``` /// @@ -461,9 +505,9 @@ pub mod workspace; /// /// ``` /// use rune::{Any, Module, ContextError}; -/// use rune::vm_write; -/// use rune::runtime::{Formatter, VmResult}; +/// use rune::runtime::Formatter; /// use rune::alloc::fmt::TryWrite; +/// use rune::alloc; /// /// #[derive(Any)] /// struct String { @@ -503,9 +547,8 @@ pub mod workspace; /// /// assert_eq!(format!("{}", string), "hello"); /// /// ``` /// #[rune::function(protocol = DISPLAY_FMT)] -/// fn display(&self, f: &mut Formatter) -> VmResult<()> { -/// vm_write!(f, "{}", self.inner); -/// VmResult::Ok(()) +/// fn display(&self, f: &mut Formatter) -> alloc::Result<()> { +/// write!(f, "{}", self.inner) /// } /// } /// @@ -553,6 +596,11 @@ pub mod workspace; /// /// # Using `vm_result` and `.vm?`. /// +/// > **Deprecated:** This feature will be removed in a future version of Rune. +/// > It is not recommended that you use a `Result` return type +/// > directly and make use of helpers like [`nested_try!`] for propagating +/// > inner errors. +/// /// In order to conveniently deal with virtual machine errors which require use /// [`VmResult`] this attribute macro supports the `vm_result` option. /// @@ -613,40 +661,148 @@ pub mod workspace; /// } /// ``` /// +/// [`vm_try!`]: crate::vm_try /// [`VmResult`]: crate::runtime::VmResult -/// [`vm_try!`]: crate::vm_try! +/// [`nested_try!`]: crate::nested_try +#[doc(inline)] pub use rune_macros::function; +/// Calculate a type hash at compile time. +/// +/// By default this uses the `rune` crate. +/// +/// # Examples +/// +/// ``` +/// use rune::Hash; +/// +/// let hash: Hash = rune::hash!(::std::option::Option::Some); +/// ``` +#[doc(inline)] +pub use rune_macros::hash; + +/// Calculate a type hash at compile time using a custom crate. +/// +/// By default the [`hash!`] macro uses the `rune` crate. +/// +/// # Examples +/// +/// ``` +/// use rune_core::hash::Hash; +/// +/// let hash: Hash = rune::hash_in!(rune_core::hash, ::std::option::Option::Some); +/// ``` +#[doc(inline)] +pub use rune_macros::hash_in; + +/// Construct an [`Item`] reference at compile time. +/// +/// # Examples +/// +/// ``` +/// use rune::{Item, ItemBuf}; +/// +/// static ITEM: &Item = rune::item!(::std::ops::generator::Generator); +/// +/// let mut item = ItemBuf::with_crate("std")?; +/// item.push("ops")?; +/// item.push("generator")?; +/// item.push("Generator")?; +/// +/// assert_eq!(item, ITEM); +/// # Ok::<_, rune::alloc::Error>(()) +/// ``` +#[doc(inline)] +pub use rune_macros::item; + +/// Construct an [`Item`] reference at compile time. +/// +/// This variant of the [`item!`] macro allows the module that's used to be +/// specified as the first argument. By default this is `rune`. +/// +/// # Examples +/// +/// ``` +/// use rune_core::item::{Item, ItemBuf}; +/// use rune_macros::item_in; +/// +/// static ITEM: &Item = rune::item_in!(rune_core::item, ::std::ops::generator::Generator); +/// +/// let mut item = ItemBuf::with_crate("std")?; +/// item.push("ops")?; +/// item.push("generator")?; +/// item.push("Generator")?; +/// +/// assert_eq!(item, ITEM); +/// # Ok::<_, rune_core::alloc::Error>(()) +/// ``` +#[doc(inline)] +pub use rune_macros::item_in; + /// Macro used to annotate native functions which can be loaded as macros in /// rune. /// -/// See [`Module::macro_meta`]. -#[doc(hidden)] -pub use rune_macros::macro_; - -/// Macro used to annotate native functions which can be loaded as attribute -/// macros in rune. +/// See [`Module::macro_meta`][crate::Module::macro_meta]. /// -/// See [`Module::macro_meta`]. -#[doc(hidden)] -pub use rune_macros::attribute_macro; +/// # Examples +/// +/// ``` +/// use rune::Module; +/// use rune::ast; +/// use rune::compile; +/// use rune::macros::{quote, MacroContext, TokenStream}; +/// use rune::parse::Parser; +/// use rune::alloc::prelude::*; +/// +/// /// Takes an identifier and converts it into a string. +/// /// +/// /// # Examples +/// /// +/// /// ```rune +/// /// assert_eq!(ident_to_string!(Hello), "Hello"); +/// /// ``` +/// #[rune::macro_] +/// fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result { +/// let mut p = Parser::from_token_stream(stream, cx.input_span()); +/// let ident = p.parse_all::()?; +/// let ident = cx.resolve(ident)?.try_to_owned()?; +/// let string = cx.lit(&ident)?; +/// Ok(quote!(#string).into_token_stream(cx)?) +/// } +/// +/// let mut m = Module::new(); +/// m.macro_meta(ident_to_string)?; +/// # Ok::<_, rune::support::Error>(()) +/// ``` +#[doc(inline)] +pub use rune_macros::macro_; /// Macro used to annotate a module with metadata. /// /// ThIs defines a local function `module_meta` which can be used in conjunction /// with [`Module::from_meta`] to construct a module with a given item and /// captured documentation. +/// +/// [`Module::from_meta`]: crate::module::Module::from_meta +/// +/// # Examples +/// +/// ``` +/// use rune::{ContextError, Module}; +/// +/// /// Utilities for working with colors. +/// #[rune::module(::color)] +/// pub fn module() -> Result { +/// let mut m = Module::from_meta(module__meta)?; +/// +/// // Populate module. +/// +/// Ok(m) +/// } +/// ``` #[doc(inline)] pub use rune_macros::module; -#[doc(inline)] -pub use rune_macros::hash; - -#[doc(inline)] -pub(crate) use rune_macros::hash_in; - -pub use rune_macros::item; - #[cfg(feature = "cli")] mod ace; @@ -655,6 +811,7 @@ mod ace; pub mod cli; #[cfg(feature = "languageserver")] +#[cfg_attr(rune_docsrs, doc(cfg(feature = "languageserver")))] pub mod languageserver; #[cfg(feature = "doc")] @@ -663,20 +820,83 @@ pub(crate) mod doc; /// Privately exported details. #[doc(hidden)] -pub mod __private { +pub mod __priv { pub use crate::any::AnyMarker; pub use crate::function_meta::{ FunctionMetaData, FunctionMetaKind, FunctionMetaStatics, MacroMetaData, MacroMetaKind, }; - pub use crate::item::ItemBuf; + pub use crate::item::{Item, ItemBuf}; pub use crate::module::{InstallWith, Module, ModuleMetaData}; pub use crate::params::Params; - pub use crate::runtime::{TypeHash, TypeOf}; + pub use crate::runtime::{ + AnyTypeInfo, ConstConstruct, ConstValue, FromConstValue, FromValue, MaybeTypeOf, Object, + OwnedTuple, Protocol, RawValueGuard, RuntimeError, ToConstValue, ToValue, Tuple, TypeHash, + TypeOf, TypeValue, UnsafeToMut, UnsafeToRef, UnsafeToValue, Value, ValueMutGuard, + ValueRefGuard, VmError, + }; + pub use core::clone::Clone; pub use rust_alloc::boxed::Box; pub use rust_alloc::sync::Arc; + + pub mod e { + use crate::alloc::borrow::TryToOwned; + use crate::runtime::{AnyTypeInfo, RuntimeError, TypeInfo, VmErrorKind}; + + #[doc(hidden)] + #[inline] + pub fn missing_struct_field(target: &'static str, name: &'static str) -> RuntimeError { + RuntimeError::new(VmErrorKind::MissingStructField { target, name }) + } + + #[doc(hidden)] + #[inline] + pub fn missing_variant(name: &str) -> RuntimeError { + match name.try_to_owned() { + Ok(name) => RuntimeError::new(VmErrorKind::MissingVariant { name }), + Err(error) => RuntimeError::from(error), + } + } + + #[doc(hidden)] + #[inline] + pub fn expected_variant(actual: TypeInfo) -> RuntimeError { + RuntimeError::new(VmErrorKind::ExpectedVariant { actual }) + } + + #[doc(hidden)] + #[inline] + pub fn missing_variant_name() -> RuntimeError { + RuntimeError::new(VmErrorKind::MissingVariantName) + } + + #[doc(hidden)] + #[inline] + pub fn missing_tuple_index(target: &'static str, index: usize) -> RuntimeError { + RuntimeError::new(VmErrorKind::MissingTupleIndex { target, index }) + } + + #[doc(hidden)] + #[inline] + pub fn unsupported_object_field_get(target: AnyTypeInfo) -> RuntimeError { + RuntimeError::new(VmErrorKind::UnsupportedObjectFieldGet { + target: TypeInfo::from(target), + }) + } + + #[doc(hidden)] + #[inline] + pub fn unsupported_tuple_index_get(target: AnyTypeInfo, index: usize) -> RuntimeError { + RuntimeError::new(VmErrorKind::UnsupportedTupleIndexGet { + target: TypeInfo::from(target), + index, + }) + } + } } +#[cfg(feature = "musli")] mod musli; +#[cfg(feature = "serde")] mod serde; #[cfg(test)] @@ -687,9 +907,8 @@ rune_macros::binding! { #[cfg(feature = "std")] #[cfg_attr(rune_docsrs, doc(cfg(feature = "std")))] impl ::std::io::Error for std::io::Error; - #[cfg(feature = "alloc")] - #[cfg_attr(rune_docsrs, doc(cfg(feature = "alloc")))] impl ::std::string::FromUtf8Error for crate::alloc::string::FromUtf8Error; + #[cfg(feature = "anyhow")] impl ::std::error::Error for anyhow::Error; impl ::std::fmt::Error for core::fmt::Error; impl ::std::char::ParseCharError for core::char::ParseCharError; @@ -743,10 +962,7 @@ rune_macros::binding! { #[type_of] impl ::std::cmp::Ordering for core::cmp::Ordering; #[type_of] - #[cfg(feature = "alloc")] - #[cfg_attr(rune_docsrs, doc(cfg(feature = "alloc")))] - #[type_of] - impl ::std::string::String for ::rust_alloc::string::String; + impl ::std::string::String for rust_alloc::string::String; #[type_of] impl ::std::string::String for crate::alloc::Box; #[type_of] @@ -754,24 +970,23 @@ rune_macros::binding! { #[type_of] impl ::std::vec::Vec for [Value]; #[type_of] - #[cfg(feature = "alloc")] - #[cfg_attr(rune_docsrs, doc(cfg(feature = "alloc")))] - #[type_of] - impl ::std::vec::Vec for ::rust_alloc::vec::Vec; + impl ::std::vec::Vec for rust_alloc::vec::Vec; #[type_of] impl ::std::vec::Vec for crate::alloc::Vec; #[type_of] + impl ::std::vec::Vec for [T; N]; + #[type_of] impl ::std::vec::Vec for crate::runtime::VecTuple; #[type_of] impl ::std::tuple::Tuple for crate::runtime::Tuple; #[type_of] - impl ::std::object::Object for crate::alloc::HashMap<::rust_alloc::string::String, T>; + impl ::std::object::Object for crate::alloc::HashMap; #[type_of] impl ::std::object::Object for crate::alloc::HashMap; #[type_of] #[cfg(feature = "std")] #[cfg_attr(rune_docsrs, doc(cfg(feature = "std")))] - impl ::std::object::Object for std::collections::HashMap<::rust_alloc::string::String, T>; + impl ::std::object::Object for std::collections::HashMap; #[type_of] #[cfg(feature = "std")] #[cfg_attr(rune_docsrs, doc(cfg(feature = "std")))] @@ -781,3 +996,5 @@ rune_macros::binding! { #[type_of] impl ::std::any::Hash for crate::hash::Hash; } + +vm_error!(crate::alloc::Error); diff --git a/crates/rune/src/macros/mod.rs b/crates/rune/src/macros/mod.rs index dcd43bfd3..61cd7cfc4 100644 --- a/crates/rune/src/macros/mod.rs +++ b/crates/rune/src/macros/mod.rs @@ -105,22 +105,35 @@ //! ``` mod format_args; -mod into_lit; -mod macro_compiler; -mod macro_context; -mod quote_fn; -mod storage; -mod token_stream; - +#[doc(inline)] pub use self::format_args::FormatArgs; + +mod into_lit; +#[doc(inline)] pub use self::into_lit::IntoLit; + +mod macro_compiler; +#[doc(inline)] pub(crate) use self::macro_compiler::MacroCompiler; + +mod macro_context; #[cfg(feature = "std")] +#[doc(inline)] pub use self::macro_context::test; +#[doc(inline)] pub use self::macro_context::MacroContext; + +mod quote_fn; +#[doc(inline)] pub use self::quote_fn::{quote_fn, Quote}; + +mod storage; pub(crate) use self::storage::Storage; +#[doc(inline)] pub use self::storage::{SyntheticId, SyntheticKind}; + +mod token_stream; +#[doc(inline)] pub use self::token_stream::{ToTokens, TokenStream, TokenStreamIter}; /// Macro helper function for quoting the token stream as macro output. diff --git a/crates/rune/src/module/item_fn_mut.rs b/crates/rune/src/module/item_fn_mut.rs index 3e4085615..a8b56d92a 100644 --- a/crates/rune/src/module/item_fn_mut.rs +++ b/crates/rune/src/module/item_fn_mut.rs @@ -12,7 +12,7 @@ use crate::runtime::MaybeTypeOf; /// metadata. /// /// This is returned by methods which insert meta items, such as: -/// * [`Module::raw_fn`]. +/// * [`Module::raw_function`]. /// * [`Module::function`]. /// * [`Module::associated_function`]. /// @@ -22,7 +22,7 @@ use crate::runtime::MaybeTypeOf; /// * [`Module::macro_meta`]. /// * [`Module::function_meta`]. /// -/// [`Module::raw_fn`]: super::Module::raw_fn +/// [`Module::raw_function`]: super::Module::raw_function /// [`Module::function`]: super::Module::function /// [`Module::associated_function`]: super::Module::associated_function /// [`Module::macro_meta`]: super::Module::macro_meta @@ -109,6 +109,19 @@ impl ItemFnMut<'_> { Ok(self) } + + /// Set argument names. + pub fn argument_names( + self, + #[cfg_attr(not(feature = "doc"), allow(unused))] names: impl IntoIterator>, + ) -> Result { + #[cfg(feature = "doc")] + { + self.docs.set_arguments(names)?; + } + + Ok(self) + } } impl fmt::Debug for ItemFnMut<'_> { diff --git a/crates/rune/src/module/mod.rs b/crates/rune/src/module/mod.rs index 8a1d3e14d..6d9b9110b 100644 --- a/crates/rune/src/module/mod.rs +++ b/crates/rune/src/module/mod.rs @@ -13,7 +13,7 @@ mod module_meta; pub(crate) use self::module_meta::{ AssociatedKey, DocFunction, Fields, ModuleAssociated, ModuleAssociatedKind, ModuleFunction, ModuleItem, ModuleItemCommon, ModuleItemKind, ModuleReexport, ModuleTrait, ModuleTraitImpl, - ModuleType, TraitFunction, TypeSpecification, + ModuleType, TraitFunction, TypeConstructor, TypeSpecification, }; use self::module_meta::{Enum, ModuleAttributeMacro, ModuleMacro, Variant}; #[doc(inline)] diff --git a/crates/rune/src/module/module.rs b/crates/rune/src/module/module.rs index 73286b0e2..560548749 100644 --- a/crates/rune/src/module/module.rs +++ b/crates/rune/src/module/module.rs @@ -1,13 +1,13 @@ use core::marker::PhantomData; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc::prelude::*; use crate::alloc::{self, HashMap, HashSet}; use crate::compile::context::{AttributeMacroHandler, MacroHandler}; use crate::compile::{self, meta, ContextError, Docs, Named}; -use crate::function::{Async, Function, FunctionKind, InstanceFunction, Plain}; +use crate::function::{Function, FunctionKind, InstanceFunction, Plain}; use crate::function_meta::{ Associated, AssociatedFunctionData, AssociatedName, FunctionArgs, FunctionBuilder, FunctionData, FunctionMeta, FunctionMetaKind, MacroMeta, MacroMetaKind, ToFieldFunction, @@ -17,17 +17,17 @@ use crate::item::IntoComponent; use crate::macros::{MacroContext, TokenStream}; use crate::module::DocFunction; use crate::runtime::{ - AnyTypeInfo, ConstConstruct, InstAddress, MaybeTypeOf, Memory, Output, Protocol, ToConstValue, - TypeHash, TypeOf, VmResult, + Address, AnyTypeInfo, ConstConstruct, MaybeTypeOf, Memory, Output, Protocol, ToConstValue, + TypeHash, TypeOf, VmError, }; use crate::{Hash, Item, ItemBuf}; use super::{ - AssociatedKey, EnumMut, InstallWith, ItemFnMut, ItemMut, ModuleAssociated, - ModuleAssociatedKind, ModuleAttributeMacro, ModuleConstantBuilder, ModuleFunction, - ModuleFunctionBuilder, ModuleItem, ModuleItemCommon, ModuleItemKind, ModuleMacro, ModuleMeta, - ModuleRawFunctionBuilder, ModuleReexport, ModuleTrait, ModuleTraitImpl, ModuleType, TraitMut, - TypeMut, TypeSpecification, VariantMut, + AssociatedKey, InstallWith, ItemFnMut, ItemMut, ModuleAssociated, ModuleAssociatedKind, + ModuleAttributeMacro, ModuleConstantBuilder, ModuleFunction, ModuleFunctionBuilder, ModuleItem, + ModuleItemCommon, ModuleItemKind, ModuleMacro, ModuleMeta, ModuleRawFunctionBuilder, + ModuleReexport, ModuleTrait, ModuleTraitImpl, ModuleType, TraitMut, TypeMut, TypeSpecification, + VariantMut, }; #[derive(Debug, TryClone, PartialEq, Eq, Hash)] @@ -44,7 +44,7 @@ enum Name { TraitImpl(Hash, Hash), } -/// A [Module] that is a collection of native functions and types. +/// A [`Module`] that is a collection of native functions and types. /// /// Needs to be installed into a [Context][crate::compile::Context] using /// [Context::install][crate::compile::Context::install]. @@ -116,7 +116,7 @@ impl Module { /// Construct a new module from the given module meta. pub fn from_meta(module_meta: ModuleMeta) -> Result { let meta = module_meta()?; - let mut m = Self::inner_new(meta.item); + let mut m = Self::inner_new(meta.item.try_to_owned()?); m.item_mut().static_docs(meta.docs)?; Ok(m) } @@ -262,35 +262,6 @@ impl Module { }) } - /// Register that the given type is a struct, and that it has the given - /// compile-time metadata. This implies that each field has a - /// [Protocol::GET] field function. - /// - /// This is typically not used directly, but is used automatically with the - /// [Any][crate::Any] derive. - #[deprecated = "Use type_meta::().make_struct(fields) instead"] - pub fn struct_meta(&mut self, fields: &'static [&'static str]) -> Result<(), ContextError> - where - T: ?Sized + TypeOf + Named, - { - self.type_meta::()?.make_named_struct(fields)?; - Ok(()) - } - - /// Register enum metadata for the given type `T`. This allows an enum to be - /// used in limited ways in Rune. - #[deprecated = "Use type_meta::().make_enum(variants) instead"] - #[doc(hidden)] - pub fn enum_meta( - &mut self, - variants: &'static [&'static str], - ) -> Result, ContextError> - where - T: ?Sized + TypeOf + Named, - { - self.type_meta::()?.make_enum(variants) - } - /// Access variant metadata for the given type and the index of its variant. pub fn variant_meta(&mut self, index: usize) -> Result, ContextError> where @@ -332,21 +303,6 @@ impl Module { }) } - /// Register a variant constructor for type `T`. - #[deprecated = "Use variant_meta() instead"] - pub fn variant_constructor( - &mut self, - index: usize, - constructor: F, - ) -> Result<(), ContextError> - where - F: Function, - { - self.variant_meta::(index)? - .constructor(constructor)?; - Ok(()) - } - /// Register a constant value, at a crate, module or associated level. /// /// # Examples @@ -524,8 +480,7 @@ impl Module { /// /// let mut m = Module::new(); /// m.macro_meta(ident_to_string)?; - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn macro_meta(&mut self, meta: MacroMeta) -> Result, ContextError> { @@ -616,8 +571,7 @@ impl Module { /// /// let mut m = Module::new(); /// m.macro_(["ident_to_string"], ident_to_string)?; - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn macro_(&mut self, name: N, f: M) -> Result, ContextError> where @@ -677,8 +631,7 @@ impl Module { /// /// let mut m = Module::new(); /// m.attribute_macro(["rename_fn"], rename_fn)?; - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn attribute_macro(&mut self, name: N, f: M) -> Result, ContextError> where @@ -878,35 +831,6 @@ impl Module { } } - /// See [`Module::function`]. - #[deprecated = "Use `Module::function`"] - pub fn function2( - &mut self, - name: N, - f: F, - ) -> Result, ContextError> - where - F: Function, - A: FunctionArgs, - K: FunctionKind, - { - Ok(ModuleFunctionBuilder { - module: self, - inner: FunctionBuilder::new(name, f), - }) - } - - /// See [`Module::function`]. - #[deprecated = "Use Module::function() instead"] - pub fn async_function(&mut self, name: N, f: F) -> Result, ContextError> - where - F: Function, - N: IntoComponent, - A: FunctionArgs, - { - self.function_inner(FunctionData::new(name, f)?, Docs::EMPTY, None) - } - /// Register an instance function. /// /// If possible, [`Module::function_meta`] should be used since it includes @@ -1102,30 +1026,6 @@ impl Module { ) } - /// See [`Module::associated_function`]. - #[deprecated = "Use Module::associated_function() instead"] - #[inline] - pub fn inst_fn(&mut self, name: N, f: F) -> Result, ContextError> - where - N: ToInstance, - F: InstanceFunction, - A: FunctionArgs, - K: FunctionKind, - { - self.associated_function(name, f) - } - - /// See [`Module::associated_function`]. - #[deprecated = "Use Module::associated_function() instead"] - pub fn async_inst_fn(&mut self, name: N, f: F) -> Result, ContextError> - where - N: ToInstance, - F: InstanceFunction, - A: FunctionArgs, - { - self.associated_function(name, f) - } - /// Install a protocol function that interacts with the given field. /// /// This returns a [`ItemMut`], which is a handle that can be used to @@ -1148,27 +1048,10 @@ impl Module { ) } - /// See [`Module::field_function`]. - #[deprecated = "Use Module::field_function() instead"] - #[inline] - pub fn field_fn( - &mut self, - protocol: &'static Protocol, - name: N, - f: F, - ) -> Result, ContextError> - where - N: ToFieldFunction, - F: InstanceFunction, - A: FunctionArgs, - { - self.field_function(protocol, name, f) - } - /// Install a protocol function that interacts with the given index. /// - /// An index can either be a field inside a tuple, or a variant inside of an - /// enum as configured with [Module::enum_meta]. + /// An index can either be a field inside a tuple or the equivalent inside + /// of a variant. pub fn index_function( &mut self, protocol: &'static Protocol, @@ -1187,22 +1070,6 @@ impl Module { ) } - /// See [`Module::index_function`]. - #[deprecated = "Use Module::index_function() instead"] - #[inline] - pub fn index_fn( - &mut self, - protocol: &'static Protocol, - index: usize, - f: F, - ) -> Result, ContextError> - where - F: InstanceFunction, - A: FunctionArgs, - { - self.index_function(protocol, index, f) - } - /// Register a raw function which interacts directly with the virtual /// machine. /// @@ -1213,18 +1080,18 @@ impl Module { /// /// ``` /// use rune::Module; - /// use rune::runtime::{Output, Memory, ToValue, VmResult, InstAddress}; + /// use rune::runtime::{Output, Memory, ToValue, VmError, Address}; /// use rune::{docstring, vm_try}; /// - /// fn sum(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + /// fn sum(stack: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { /// let mut number = 0; /// - /// for value in vm_try!(stack.slice_at(addr, args)) { - /// number += vm_try!(value.as_integer::()); + /// for value in stack.slice_at(addr, args)? { + /// number += value.as_integer::()?; /// } /// - /// out.store(stack, number); - /// VmResult::Ok(()) + /// out.store(stack, number)?; + /// Ok(()) /// } /// /// let mut module = Module::default(); @@ -1237,27 +1104,20 @@ impl Module { /// /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn raw_function(&mut self, name: N, f: F) -> ModuleRawFunctionBuilder<'_, N> + pub fn raw_function(&mut self, name: N, handler: F) -> ModuleRawFunctionBuilder<'_, N, F> where - F: 'static + Fn(&mut dyn Memory, InstAddress, usize, Output) -> VmResult<()> + Send + Sync, + F: 'static + + Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError> + + Send + + Sync, { ModuleRawFunctionBuilder { module: self, name, - handler: Arc::new(move |stack, addr, args, output| f(stack, addr, args, output)), + handler, } } - /// See [`Module::raw_function`]. - #[deprecated = "Use `raw_function` builder instead"] - pub fn raw_fn(&mut self, name: N, f: F) -> Result, ContextError> - where - F: 'static + Fn(&mut dyn Memory, InstAddress, usize, Output) -> VmResult<()> + Send + Sync, - N: IntoComponent, - { - self.raw_function(name, f).build() - } - fn function_inner( &mut self, data: FunctionData, diff --git a/crates/rune/src/module/module_constant_builder.rs b/crates/rune/src/module/module_constant_builder.rs index 3b58c74e1..9b3e85816 100644 --- a/crates/rune/src/module/module_constant_builder.rs +++ b/crates/rune/src/module/module_constant_builder.rs @@ -28,7 +28,6 @@ where /// /// ``` /// use rune::{Any, Module}; - /// use rune::runtime::VmResult; /// /// let mut m = Module::with_item(["module"])?; /// m.constant("NAME", "Hello World").build()?; diff --git a/crates/rune/src/module/module_meta.rs b/crates/rune/src/module/module_meta.rs index eb2096d55..4e1461440 100644 --- a/crates/rune/src/module/module_meta.rs +++ b/crates/rune/src/module/module_meta.rs @@ -1,6 +1,6 @@ use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc; @@ -9,12 +9,15 @@ use crate::compile::context::{AttributeMacroHandler, MacroHandler, TraitHandler} use crate::compile::{meta, Docs}; use crate::function_meta::AssociatedName; use crate::runtime::{ConstValue, FieldMap, FunctionHandler, TypeInfo}; -use crate::{Hash, ItemBuf}; +use crate::{Hash, Item, ItemBuf}; +/// Static module metadata. +/// +/// Note that this is not public API and should not be used directly. #[doc(hidden)] pub struct ModuleMetaData { #[doc(hidden)] - pub item: ItemBuf, + pub item: &'static Item, #[doc(hidden)] pub docs: &'static [&'static str], } @@ -48,7 +51,7 @@ pub(crate) struct ModuleType { /// The specification for the type. pub(crate) spec: Option, /// Handler to use if this type can be constructed through a regular function call. - pub(crate) constructor: Option>, + pub(crate) constructor: Option, } /// A trait defined in a module. @@ -88,6 +91,16 @@ pub(crate) enum Fields { } impl Fields { + /// Get the raw number of fields, regardless of whether they are named or unnamed. + #[inline] + pub(crate) fn len(&self) -> usize { + match self { + Fields::Named(fields) => fields.len(), + Fields::Unnamed(size) => *size, + Fields::Empty => 0, + } + } + /// Get the number of named fields. #[inline] fn size(&self) -> usize { @@ -119,7 +132,7 @@ pub struct Variant { /// Variant metadata. pub(crate) fields: Option, /// Handler to use if this variant can be constructed through a regular function call. - pub(crate) constructor: Option>, + pub(crate) constructor: Option, /// Variant deprecation. pub(crate) deprecated: Option>, /// Variant documentation. @@ -162,6 +175,14 @@ pub(crate) enum TypeSpecification { Enum(Enum), } +/// A type constructor. +pub(crate) struct TypeConstructor { + /// The handler for the constructor. + pub(crate) handler: FunctionHandler, + /// The number of arguments the constructor takes. + pub(crate) args: usize, +} + /// A key that identifies an associated function. #[derive(Debug, TryClone, PartialEq, Eq, Hash)] #[non_exhaustive] @@ -205,7 +226,7 @@ pub(crate) struct DocFunction { #[derive(TryClone)] pub(crate) struct ModuleFunction { /// The handler for the function. - pub(crate) handler: Arc, + pub(crate) handler: FunctionHandler, /// If the function is associated with a trait, this is the hash of that trait. pub(crate) trait_hash: Option, /// Documentation related to the function. diff --git a/crates/rune/src/module/module_raw_function_builder.rs b/crates/rune/src/module/module_raw_function_builder.rs index a0a6ed181..76b160c6b 100644 --- a/crates/rune/src/module/module_raw_function_builder.rs +++ b/crates/rune/src/module/module_raw_function_builder.rs @@ -1,13 +1,11 @@ -use ::rust_alloc::sync::Arc; - use crate::compile::ContextError; use crate::function_meta::{ Associated, AssociatedFunctionData, FunctionData, FunctionMetaKind, ToInstance, }; use crate::item::IntoComponent; use crate::module::ItemFnMut; -use crate::runtime::{FunctionHandler, TypeInfo, TypeOf}; -use crate::{Hash, ItemBuf}; +use crate::runtime::{Address, FunctionHandler, Memory, Output, TypeInfo, TypeOf}; +use crate::{Hash, ItemBuf, VmError}; use super::Module; @@ -17,13 +15,16 @@ use super::Module; /// [`ModuleRawFunctionBuilder::build`] or statically associate the function /// with a type through [`ModuleRawFunctionBuilder::build_associated::`]. #[must_use = "Must call one of the build functions, like `build` or `build_associated`"] -pub struct ModuleRawFunctionBuilder<'a, N> { +pub struct ModuleRawFunctionBuilder<'a, N, F> { pub(super) module: &'a mut Module, pub(super) name: N, - pub(super) handler: Arc, + pub(super) handler: F, } -impl<'a, N> ModuleRawFunctionBuilder<'a, N> { +impl<'a, N, F> ModuleRawFunctionBuilder<'a, N, F> +where + F: 'static + Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError> + Send + Sync, +{ /// Construct a regular function. /// /// This register the function as a free function in the module it's @@ -34,10 +35,9 @@ impl<'a, N> ModuleRawFunctionBuilder<'a, N> { /// /// ``` /// use rune::{Any, Module}; - /// use rune::runtime::VmResult; /// /// let mut m = Module::with_item(["module"])?; - /// m.raw_function("floob", |_, _, _, _| VmResult::Ok(())).build()?; + /// m.raw_function("floob", |_, _, _, _| Ok(())).build()?; /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] @@ -46,10 +46,11 @@ impl<'a, N> ModuleRawFunctionBuilder<'a, N> { N: IntoComponent, { let item = ItemBuf::with_item([self.name])?; + let handler = FunctionHandler::new(self.handler)?; + self.module .function_from_meta_kind(FunctionMetaKind::Function(FunctionData::from_raw( - item, - self.handler, + item, handler, ))) } @@ -83,14 +84,13 @@ impl<'a, N> ModuleRawFunctionBuilder<'a, N> { /// /// ``` /// use rune::{Any, Module}; - /// use rune::runtime::VmResult; /// /// #[derive(Any)] /// struct Thing; /// /// let mut m = Module::default(); /// m.ty::()?; - /// m.raw_function("floob", |_, _, _, _| VmResult::Ok(())).build_associated::()?; + /// m.raw_function("floob", |_, _, _, _| Ok(())).build_associated::()?; /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] @@ -100,10 +100,11 @@ impl<'a, N> ModuleRawFunctionBuilder<'a, N> { T: TypeOf, { let associated = Associated::from_type::(self.name.to_instance()?)?; + let handler = FunctionHandler::new(self.handler)?; self.module .function_from_meta_kind(FunctionMetaKind::AssociatedFunction( - AssociatedFunctionData::from_raw(associated, self.handler), + AssociatedFunctionData::from_raw(associated, handler), )) } @@ -134,9 +135,11 @@ impl<'a, N> ModuleRawFunctionBuilder<'a, N> { N: ToInstance, { let associated = Associated::new(self.name.to_instance()?, container, container_type_info); + let handler = FunctionHandler::new(self.handler)?; + self.module .function_from_meta_kind(FunctionMetaKind::AssociatedFunction( - AssociatedFunctionData::from_raw(associated, self.handler), + AssociatedFunctionData::from_raw(associated, handler), )) } } diff --git a/crates/rune/src/module/trait_mut.rs b/crates/rune/src/module/trait_mut.rs index abd81c750..64f941757 100644 --- a/crates/rune/src/module/trait_mut.rs +++ b/crates/rune/src/module/trait_mut.rs @@ -1,6 +1,6 @@ use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; #[cfg(feature = "doc")] use crate::alloc::Box; diff --git a/crates/rune/src/module/type_mut.rs b/crates/rune/src/module/type_mut.rs index ef1e49379..0417d9c7c 100644 --- a/crates/rune/src/module/type_mut.rs +++ b/crates/rune/src/module/type_mut.rs @@ -1,15 +1,13 @@ use core::fmt; use core::marker::PhantomData; -use ::rust_alloc::sync::Arc; - use crate::alloc::prelude::*; use crate::compile::{ContextError, Docs}; use crate::function::{Function, Plain}; use crate::runtime::{FunctionHandler, TypeOf}; use crate::Item; -use super::{Enum, EnumMut, Fields, TypeSpecification, Variant}; +use super::{Enum, EnumMut, Fields, TypeConstructor, TypeSpecification, Variant}; /// Handle to a a type inserted into a module which allows for mutation of its /// metadata. @@ -29,7 +27,7 @@ where #[cfg(feature = "doc")] pub(super) deprecated: &'a mut Option>, pub(super) spec: &'a mut Option, - pub(super) constructor: &'a mut Option>, + pub(super) constructor: &'a mut Option, pub(super) item: &'a Item, pub(super) _marker: PhantomData, } @@ -127,9 +125,14 @@ where }); } - *self.constructor = Some(Arc::new(move |stack, addr, args, output| { - constructor.fn_call(stack, addr, args, output) - })); + let handler: FunctionHandler = FunctionHandler::new(move |stack, addr, args, output| { + constructor.call(stack, addr, args, output) + })?; + + *self.constructor = Some(TypeConstructor { + handler, + args: F::ARGS, + }); Ok(self) } diff --git a/crates/rune/src/module/variant_mut.rs b/crates/rune/src/module/variant_mut.rs index cab938ac9..b8d47e420 100644 --- a/crates/rune/src/module/variant_mut.rs +++ b/crates/rune/src/module/variant_mut.rs @@ -1,12 +1,10 @@ use core::marker::PhantomData; -use ::rust_alloc::sync::Arc; - use crate::compile::{ContextError, Docs}; use crate::function::{Function, Plain}; use crate::runtime::{FunctionHandler, TypeOf}; -use super::Fields; +use super::{Fields, TypeConstructor}; /// Handle to a a variant inserted into a module which allows for mutation of /// its metadata. @@ -17,7 +15,7 @@ where pub(crate) name: &'static str, pub(crate) docs: &'a mut Docs, pub(crate) fields: &'a mut Option, - pub(crate) constructor: &'a mut Option>, + pub(crate) constructor: &'a mut Option, pub(crate) _marker: PhantomData, } @@ -72,9 +70,14 @@ where }); } - *self.constructor = Some(Arc::new(move |stack, addr, args, output| { - constructor.fn_call(stack, addr, args, output) - })); + let handler = FunctionHandler::new(move |stack, addr, args, output| { + constructor.call(stack, addr, args, output) + })?; + + *self.constructor = Some(TypeConstructor { + handler, + args: F::ARGS, + }); Ok(self) } diff --git a/crates/rune/src/modules/any.rs b/crates/rune/src/modules/any.rs index 8bc83b948..9f01d9f25 100644 --- a/crates/rune/src/modules/any.rs +++ b/crates/rune/src/modules/any.rs @@ -2,8 +2,8 @@ use crate as rune; use crate::alloc::fmt::TryWrite; -use crate::alloc::String; -use crate::runtime::{Formatter, Type, Value, VmResult}; +use crate::alloc::{self, String}; +use crate::runtime::{Formatter, Type, Value, VmError}; use crate::{docstring, ContextError, Hash, Module}; /// Dynamic typing and type reflection. @@ -14,7 +14,7 @@ use crate::{docstring, ContextError, Hash, Module}; /// constructed through the [`Type::of_val`] function. #[rune::module(::std::any)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?.docs(docstring! { /// Represents a type in the Rune type system. @@ -57,8 +57,8 @@ fn type_of_val(value: Value) -> Type { /// assert_eq!(format!("{}", any::Type::of_val(42)), "Type(0x1cad9186c9641c4f)"); /// ``` #[rune::function(instance, protocol = DISPLAY_FMT)] -fn format_type(ty: Type, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", ty) +fn format_type(ty: Type, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{ty:?}") } /// Get the type name of a value. @@ -76,6 +76,6 @@ fn format_type(ty: Type, f: &mut Formatter) -> VmResult<()> { /// ``` #[rune::function] #[inline] -pub fn type_name_of_val(value: Value) -> VmResult { +pub fn type_name_of_val(value: Value) -> Result { value.into_type_name() } diff --git a/crates/rune/src/modules/bytes.rs b/crates/rune/src/modules/bytes.rs index 18996529b..5d7f7f0f5 100644 --- a/crates/rune/src/modules/bytes.rs +++ b/crates/rune/src/modules/bytes.rs @@ -7,13 +7,13 @@ use crate as rune; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::alloc::Vec; -use crate::runtime::{Bytes, Formatter, Hasher, Panic, VmErrorKind, VmResult}; +use crate::runtime::{Bytes, Formatter, Hasher, VmError, VmErrorKind}; use crate::{ContextError, Module, Value}; /// The bytes module. #[rune::module(::std::bytes)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(new)?; @@ -87,8 +87,8 @@ pub const fn new() -> Bytes { /// ``` #[rune::function(free, path = Bytes::with_capacity)] #[inline] -pub fn with_capacity(capacity: usize) -> VmResult { - VmResult::Ok(vm_try!(Bytes::with_capacity(capacity))) +pub fn with_capacity(capacity: usize) -> Result { + Ok(Bytes::with_capacity(capacity)?) } /// Convert a byte array into bytes. @@ -133,8 +133,8 @@ pub fn into_vec(bytes: Bytes) -> Vec { /// ``` #[rune::function(instance)] #[inline] -pub fn as_vec(bytes: &Bytes) -> VmResult> { - VmResult::Ok(vm_try!(Vec::try_from(bytes.as_slice()))) +pub fn as_vec(bytes: &Bytes) -> Result, VmError> { + Ok(Vec::try_from(bytes.as_slice())?) } /// Extend these bytes with another collection of bytes. @@ -148,9 +148,9 @@ pub fn as_vec(bytes: &Bytes) -> VmResult> { /// ``` #[rune::function(instance)] #[inline] -pub fn extend(this: &mut Bytes, other: &Bytes) -> VmResult<()> { - vm_try!(this.extend(other)); - VmResult::Ok(()) +pub fn extend(this: &mut Bytes, other: &Bytes) -> Result<(), VmError> { + this.extend(other)?; + Ok(()) } /// Extend this bytes collection with a string. @@ -163,9 +163,9 @@ pub fn extend(this: &mut Bytes, other: &Bytes) -> VmResult<()> { /// assert_eq!(bytes, b"abcdefgh"); /// ``` #[rune::function(instance)] -pub fn extend_str(this: &mut Bytes, s: &str) -> VmResult<()> { - vm_try!(this.extend(s.as_bytes())); - VmResult::Ok(()) +pub fn extend_str(this: &mut Bytes, s: &str) -> Result<(), VmError> { + this.extend(s.as_bytes())?; + Ok(()) } /// Pop the last byte. @@ -194,9 +194,9 @@ pub fn pop(this: &mut Bytes) -> Option { /// ``` #[rune::function(instance)] #[inline] -pub fn push(this: &mut Bytes, value: u8) -> VmResult<()> { - vm_try!(this.push(value)); - VmResult::Ok(()) +pub fn push(this: &mut Bytes, value: u8) -> Result<(), VmError> { + this.push(value)?; + Ok(()) } /// Removes and returns the byte at position `index` within the Bytes, @@ -219,16 +219,16 @@ pub fn push(this: &mut Bytes, value: u8) -> VmResult<()> { /// assert_eq!(bytes, b"ac"); /// ``` #[rune::function(instance)] -fn remove(this: &mut Bytes, index: usize) -> VmResult { +fn remove(this: &mut Bytes, index: usize) -> Result { if index >= this.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: this.len().into(), - }); + })); } let value = this.remove(index); - VmResult::Ok(value) + Ok(value) } /// Inserts a byte at position `index` within the inner vector, shifting all @@ -248,16 +248,16 @@ fn remove(this: &mut Bytes, index: usize) -> VmResult { /// assert_eq!(bytes, b"aebcd"); /// ``` #[rune::function(instance)] -fn insert(this: &mut Bytes, index: usize, value: u8) -> VmResult<()> { +fn insert(this: &mut Bytes, index: usize, value: u8) -> Result<(), VmError> { if index > this.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: this.len().into(), - }); + })); } - vm_try!(this.insert(index, value)); - VmResult::Ok(()) + this.insert(index, value)?; + Ok(()) } /// Get the first byte. @@ -367,9 +367,9 @@ fn clear(this: &mut Bytes) { /// assert!(vec.capacity() >= 11); /// ``` #[rune::function(instance)] -fn reserve(this: &mut Bytes, additional: usize) -> VmResult<()> { - vm_try!(this.reserve(additional)); - VmResult::Ok(()) +fn reserve(this: &mut Bytes, additional: usize) -> Result<(), VmError> { + this.reserve(additional)?; + Ok(()) } /// Reserves the minimum capacity for at least `additional` more elements to be @@ -397,9 +397,9 @@ fn reserve(this: &mut Bytes, additional: usize) -> VmResult<()> { /// assert!(vec.capacity() >= 11); /// ``` #[rune::function(instance)] -fn reserve_exact(this: &mut Bytes, additional: usize) -> VmResult<()> { - vm_try!(this.reserve_exact(additional)); - VmResult::Ok(()) +fn reserve_exact(this: &mut Bytes, additional: usize) -> Result<(), VmError> { + this.reserve_exact(additional)?; + Ok(()) } /// Clone the byte array. @@ -416,8 +416,8 @@ fn reserve_exact(this: &mut Bytes, additional: usize) -> VmResult<()> { /// assert_eq!(b, b"hello world"); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn clone(this: &Bytes) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn clone(this: &Bytes) -> Result { + Ok(this.try_clone()?) } /// Test two byte arrays for partial equality. @@ -524,8 +524,8 @@ fn hash(this: &[u8], hasher: &mut Hasher) { /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] #[inline] -fn debug_fmt(this: &[u8], f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{this:?}") +fn debug_fmt(this: &[u8], f: &mut Formatter) -> Result<(), VmError> { + Ok(write!(f, "{this:?}")?) } /// Shrinks the capacity of the byte array as much as possible. @@ -543,9 +543,9 @@ fn debug_fmt(this: &[u8], f: &mut Formatter) -> VmResult<()> { /// assert!(bytes.capacity() >= 3); /// ``` #[rune::function(instance)] -fn shrink_to_fit(this: &mut Bytes) -> VmResult<()> { - vm_try!(this.shrink_to_fit()); - VmResult::Ok(()) +fn shrink_to_fit(this: &mut Bytes) -> Result<(), VmError> { + this.shrink_to_fit()?; + Ok(()) } /// Returns a subslice of Bytes. @@ -575,10 +575,10 @@ fn shrink_to_fit(this: &mut Bytes) -> VmResult<()> { /// assert_eq!(bytes[0], b'a'); /// ``` #[rune::function(instance, protocol = INDEX_GET)] -fn index_get(this: &Bytes, index: Value) -> VmResult { - match vm_try!(this.index_get(index)) { - Some(bytes) => VmResult::Ok(bytes), - None => VmResult::err(Panic::custom("missing bytes slice")), +fn index_get(this: &Bytes, index: Value) -> Result { + match this.index_get(index)? { + Some(bytes) => Ok(bytes), + None => Err(VmError::panic("missing bytes slice")), } } @@ -592,6 +592,6 @@ fn index_get(this: &Bytes, index: Value) -> VmResult { /// assert_eq!(bytes, b"aecd"); /// ``` #[rune::function(instance, protocol = INDEX_SET)] -fn index_set(this: &mut Bytes, index: usize, value: u8) -> VmResult<()> { +fn index_set(this: &mut Bytes, index: usize, value: u8) -> Result<(), VmError> { this.set(index, value) } diff --git a/crates/rune/src/modules/capture_io.rs b/crates/rune/src/modules/capture_io.rs index 11bc2e342..d3c0ecdcf 100644 --- a/crates/rune/src/modules/capture_io.rs +++ b/crates/rune/src/modules/capture_io.rs @@ -15,7 +15,7 @@ use core::mem::take; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use parking_lot::Mutex; @@ -23,22 +23,19 @@ use crate as rune; use crate::alloc::fmt::TryWrite; use crate::alloc::string::FromUtf8Error; use crate::alloc::{String, Vec}; -use crate::runtime::{InstAddress, Memory, Output, VmError, VmResult}; +use crate::runtime::{Address, Memory, Output, VmError}; use crate::{ContextError, Module, Value}; /// I/O module capable of capturing what's been written to a buffer. #[rune::module(::std::io)] pub fn module(io: &CaptureIo) -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut module = Module::from_meta(self::module__meta)?; let o = io.clone(); module .function("print", move |m: &str| { - match write!(o.inner.lock(), "{}", m) { - Ok(()) => VmResult::Ok(()), - Err(error) => VmResult::panic(error), - } + write!(o.inner.lock(), "{}", m).map_err(VmError::panic) }) .build()?; @@ -46,10 +43,7 @@ pub fn module(io: &CaptureIo) -> Result { module .function("println", move |m: &str| { - match writeln!(o.inner.lock(), "{}", m) { - Ok(()) => VmResult::Ok(()), - Err(error) => VmResult::panic(error), - } + writeln!(o.inner.lock(), "{}", m).map_err(VmError::panic) }) .build()?; @@ -114,14 +108,14 @@ impl CaptureIo { fn dbg_impl( o: &mut Vec, stack: &mut dyn Memory, - addr: InstAddress, + addr: Address, args: usize, out: Output, -) -> VmResult<()> { - for value in vm_try!(stack.slice_at(addr, args)) { - vm_try!(writeln!(o, "{:?}", value).map_err(VmError::panic)); +) -> Result<(), VmError> { + for value in stack.slice_at(addr, args)? { + writeln!(o, "{value:?}").map_err(VmError::panic)?; } - vm_try!(out.store(stack, Value::unit)); - VmResult::Ok(()) + out.store(stack, Value::unit)?; + Ok(()) } diff --git a/crates/rune/src/modules/char.rs b/crates/rune/src/modules/char.rs index 4d1264875..6603c514f 100644 --- a/crates/rune/src/modules/char.rs +++ b/crates/rune/src/modules/char.rs @@ -2,7 +2,7 @@ use core::char::ParseCharError; -use crate::runtime::{Value, VmErrorKind, VmResult}; +use crate::runtime::{Value, VmError, VmErrorKind}; use crate::{ContextError, Module}; use crate as rune; @@ -10,7 +10,7 @@ use crate as rune; /// The character module for Rune. #[rune::module(::std::char)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut module = Module::from_meta(self::module__meta)?; module.ty::()?; module.function_meta(from_i64)?; @@ -35,17 +35,17 @@ pub fn module() -> Result { /// assert!(c.is_some()); /// ``` #[rune::function] -fn from_i64(value: i64) -> VmResult> { +fn from_i64(value: i64) -> Result, VmError> { if value < 0 { - VmResult::err(VmErrorKind::Underflow) + Err(VmError::new(VmErrorKind::Underflow)) } else if value > u32::MAX as i64 { - VmResult::err(VmErrorKind::Overflow) + Err(VmError::new(VmErrorKind::Overflow)) } else { - let Some(c) = core::char::from_u32(value as u32) else { - return VmResult::Ok(None); + let Some(c) = char::from_u32(value as u32) else { + return Ok(None); }; - VmResult::Ok(Some(Value::from(c))) + Ok(Some(Value::from(c))) } } @@ -58,8 +58,8 @@ fn from_i64(value: i64) -> VmResult> { /// assert_eq!(c.to_i64(), 80); /// ``` #[rune::function(instance)] -fn to_i64(value: char) -> VmResult { - VmResult::Ok(value as i64) +fn to_i64(value: char) -> i64 { + value as i64 } /// Returns `true` if this `char` has the `Alphabetic` property. @@ -312,10 +312,10 @@ fn is_whitespace(c: char) -> bool { /// ``` #[rune::function(instance)] #[inline] -fn to_digit(c: char, radix: u32) -> VmResult> { +fn to_digit(c: char, radix: u32) -> Result, VmError> { if radix > 36 { - return VmResult::panic("to_digit: radix is too high (maximum 36)"); + return Err(VmError::panic("to_digit: radix is too high (maximum 36)")); } - VmResult::Ok(char::to_digit(c, radix)) + Ok(char::to_digit(c, radix)) } diff --git a/crates/rune/src/modules/clone.rs b/crates/rune/src/modules/clone.rs index b37a92410..dfefeeda7 100644 --- a/crates/rune/src/modules/clone.rs +++ b/crates/rune/src/modules/clone.rs @@ -1,8 +1,8 @@ //! The cloning trait for Rune. use crate as rune; -use crate::runtime::{Protocol, Value, VmResult}; -use crate::{ContextError, Module}; +use crate::runtime::{Protocol, Value, VmError}; +use crate::{docstring, ContextError, Module}; /// Cloning for Rune. /// @@ -12,7 +12,7 @@ use crate::{ContextError, Module}; /// unique instance of it you must clone it. #[rune::module(::std::clone)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.function_meta(clone)?; let mut t = m.define_trait(["Clone"])?; @@ -75,6 +75,6 @@ pub fn module() -> Result { /// assert_eq!(c, 42); /// ``` #[rune::function] -fn clone(value: Value) -> VmResult { +fn clone(value: Value) -> Result { value.clone_() } diff --git a/crates/rune/src/modules/cmp.rs b/crates/rune/src/modules/cmp.rs index f86b69266..4a735ef00 100644 --- a/crates/rune/src/modules/cmp.rs +++ b/crates/rune/src/modules/cmp.rs @@ -3,15 +3,18 @@ use core::cmp::Ordering; use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; -use crate::runtime::{Formatter, Protocol, Value, VmResult}; +use crate::docstring; +use crate::hash; +use crate::runtime::{Formatter, Protocol, Value}; use crate::shared::Caller; -use crate::{hash, ContextError, Hash, Module}; +use crate::{ContextError, Hash, Module, VmError}; /// Comparison and ordering. #[rune::module(::std::cmp)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; { let ty = m.ty::()?.docs(docstring! { @@ -181,8 +184,8 @@ pub fn module() -> Result { let partial_eq = cx.find(&Protocol::PARTIAL_EQ)?; let partial_eq = Caller::<(Value, Value), 2, bool>::new(partial_eq); - cx.function("ne", move |a: Value, b: Value| { - VmResult::Ok(!vm_try!(partial_eq.call((a, b)))) + cx.function("ne", move |a: Value, b: Value| -> Result { + Ok(!partial_eq.call((a, b))?) })?; Ok(()) @@ -405,48 +408,48 @@ pub fn module() -> Result { cx.find_or_define(&Protocol::LT, { let partial_cmp = partial_cmp.clone(); - move |a: Value, b: Value| { - let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { - return VmResult::Ok(false); + move |a: Value, b: Value| -> Result { + let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else { + return Ok(false); }; - VmResult::Ok(matches!(o, Ordering::Less)) + Ok(matches!(o, Ordering::Less)) } })?; cx.find_or_define(&Protocol::LE, { let partial_cmp = partial_cmp.clone(); - move |a: Value, b: Value| { - let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { - return VmResult::Ok(false); + move |a: Value, b: Value| -> Result { + let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else { + return Ok(false); }; - VmResult::Ok(matches!(o, Ordering::Less | Ordering::Equal)) + Ok(matches!(o, Ordering::Less | Ordering::Equal)) } })?; cx.find_or_define(&Protocol::GT, { let partial_cmp = partial_cmp.clone(); - move |a: Value, b: Value| { - let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { - return VmResult::Ok(false); + move |a: Value, b: Value| -> Result { + let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else { + return Ok(false); }; - VmResult::Ok(matches!(o, Ordering::Greater)) + Ok(matches!(o, Ordering::Greater)) } })?; cx.find_or_define(&Protocol::GE, { let partial_cmp = partial_cmp.clone(); - move |a: Value, b: Value| { - let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { - return VmResult::Ok(false); + move |a: Value, b: Value| -> Result { + let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else { + return Ok(false); }; - VmResult::Ok(matches!(o, Ordering::Greater | Ordering::Equal)) + Ok(matches!(o, Ordering::Greater | Ordering::Equal)) } })?; @@ -607,18 +610,22 @@ pub fn module() -> Result { cx.find_or_define(&Protocol::MIN, { let cmp = cmp.clone(); - move |a: Value, b: Value| match vm_try!(cmp.call((a.clone(), b.clone()))) { - Ordering::Less | Ordering::Equal => VmResult::Ok(a), - Ordering::Greater => VmResult::Ok(b), + move |a: Value, b: Value| -> Result<_, VmError> { + match cmp.call((a.clone(), b.clone()))? { + Ordering::Less | Ordering::Equal => Ok(a), + Ordering::Greater => Ok(b), + } } })?; cx.find_or_define(&Protocol::MAX, { let cmp = cmp.clone(); - move |a: Value, b: Value| match vm_try!(cmp.call((a.clone(), b.clone()))) { - Ordering::Less | Ordering::Equal => VmResult::Ok(b), - Ordering::Greater => VmResult::Ok(a), + move |a: Value, b: Value| -> Result<_, VmError> { + match cmp.call((a.clone(), b.clone()))? { + Ordering::Less | Ordering::Equal => Ok(b), + Ordering::Greater => Ok(a), + } } })?; @@ -690,8 +697,8 @@ pub fn module() -> Result { /// assert_eq!(max(2, 2), 2); /// ``` #[rune::function(keep)] -fn max(v1: Value, v2: Value) -> VmResult { - VmResult::Ok(match vm_try!(Value::cmp(&v1, &v2)) { +fn max(v1: Value, v2: Value) -> Result { + Ok(match Value::cmp(&v1, &v2)? { Ordering::Less | Ordering::Equal => v2, Ordering::Greater => v1, }) @@ -712,8 +719,8 @@ fn max(v1: Value, v2: Value) -> VmResult { /// assert_eq!(min(2, 2), 2); /// ``` #[rune::function(keep)] -fn min(v1: Value, v2: Value) -> VmResult { - VmResult::Ok(match vm_try!(Value::cmp(&v1, &v2)) { +fn min(v1: Value, v2: Value) -> Result { + Ok(match Value::cmp(&v1, &v2)? { Ordering::Less | Ordering::Equal => v1, Ordering::Greater => v2, }) @@ -760,6 +767,6 @@ fn ordering_eq(this: Ordering, other: Ordering) -> bool { /// assert_eq!(format!("{:?}", Ordering::Less), "Less"); /// ``` #[rune::function(instance, protocol = DEBUG_FMT)] -fn ordering_debug_fmt(this: Ordering, s: &mut Formatter) -> VmResult<()> { - vm_write!(s, "{:?}", this) +fn ordering_debug_fmt(this: Ordering, s: &mut Formatter) -> alloc::Result<()> { + write!(s, "{this:?}") } diff --git a/crates/rune/src/modules/collections/hash_map.rs b/crates/rune/src/modules/collections/hash_map.rs index bc051c50b..578f3645e 100644 --- a/crates/rune/src/modules/collections/hash_map.rs +++ b/crates/rune/src/modules/collections/hash_map.rs @@ -3,15 +3,15 @@ use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::hashbrown::{IterRef, KeysRef, Table, ValuesRef}; use crate::runtime::{ - EnvProtocolCaller, Formatter, FromValue, Iterator, ProtocolCaller, Ref, Value, VmErrorKind, - VmResult, + EnvProtocolCaller, Formatter, FromValue, Iterator, ProtocolCaller, Ref, Value, VmError, + VmErrorKind, }; use crate::{Any, ContextError, Module}; /// A dynamic hash map. #[rune::module(::std::collections::hash_map)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(HashMap::new__meta)?; @@ -171,9 +171,9 @@ impl HashMap { /// let map = HashMap::with_capacity(10); /// ``` #[rune::function(keep, path = Self::with_capacity)] - pub(crate) fn with_capacity(capacity: usize) -> VmResult { - VmResult::Ok(Self { - table: vm_try!(Table::try_with_capacity(capacity)), + pub(crate) fn with_capacity(capacity: usize) -> Result { + Ok(Self { + table: Table::try_with_capacity(capacity)?, }) } @@ -253,9 +253,8 @@ impl HashMap { /// assert_eq!(map[37], "c"); /// ``` #[rune::function(keep)] - pub(crate) fn insert(&mut self, key: Value, value: Value) -> VmResult> { - let mut caller = EnvProtocolCaller; - self.table.insert_with(key, value, &mut caller) + pub(crate) fn insert(&mut self, key: Value, value: Value) -> Result, VmError> { + self.table.insert_with(key, value, &mut EnvProtocolCaller) } /// Returns the value corresponding to the [`Key`]. @@ -271,9 +270,11 @@ impl HashMap { /// assert_eq!(map.get(2), None); /// ``` #[rune::function(keep)] - fn get(&self, key: Value) -> VmResult> { - let mut caller = EnvProtocolCaller; - VmResult::Ok(vm_try!(self.table.get(&key, &mut caller)).map(|(_, v)| v.clone())) + fn get(&self, key: Value) -> Result, VmError> { + Ok(self + .table + .get(&key, &mut EnvProtocolCaller)? + .map(|(_, v)| v.clone())) } /// Returns `true` if the map contains a value for the specified [`Key`]. @@ -289,9 +290,8 @@ impl HashMap { /// assert_eq!(map.contains_key(2), false); /// ``` #[rune::function(keep)] - fn contains_key(&self, key: Value) -> VmResult { - let mut caller = EnvProtocolCaller; - VmResult::Ok(vm_try!(self.table.get(&key, &mut caller)).is_some()) + fn contains_key(&self, key: Value) -> Result { + Ok(self.table.get(&key, &mut EnvProtocolCaller)?.is_some()) } /// Removes a key from the map, returning the value at the [`Key`] if the @@ -308,9 +308,8 @@ impl HashMap { /// assert_eq!(map.remove(1), None); /// ``` #[rune::function(keep)] - fn remove(&mut self, key: Value) -> VmResult> { - let mut caller = EnvProtocolCaller; - self.table.remove_with(&key, &mut caller) + fn remove(&mut self, key: Value) -> Result, VmError> { + self.table.remove_with(&key, &mut EnvProtocolCaller) } /// Clears the map, removing all key-value pairs. Keeps the allocated memory @@ -433,15 +432,15 @@ impl HashMap { /// ]); /// ``` #[rune::function(keep)] - fn extend(&mut self, value: Value) -> VmResult<()> { - let mut it = vm_try!(value.into_iter()); + fn extend(&mut self, value: Value) -> Result<(), VmError> { + let mut it = value.into_iter()?; - while let Some(value) = vm_try!(it.next()) { - let (key, value) = vm_try!(<(Value, Value)>::from_value(value)); - vm_try!(self.insert(key, value)); + while let Some(value) = it.next()? { + let (key, value) = <(Value, Value)>::from_value(value)?; + self.insert(key, value)?; } - VmResult::Ok(()) + Ok(()) } /// Clone the map. @@ -464,9 +463,9 @@ impl HashMap { /// assert_eq!(b.len(), 3); /// ``` #[rune::function(keep, instance, path = Self::clone, protocol = CLONE)] - fn clone(this: &HashMap) -> VmResult { - VmResult::Ok(Self { - table: vm_try!(this.table.try_clone()), + fn clone(this: &HashMap) -> Result { + Ok(Self { + table: this.table.try_clone()?, }) } @@ -486,23 +485,22 @@ impl HashMap { /// assert_eq!(map.get("b"), Some(2)); /// ``` #[rune::function(keep, path = Self::from_iter)] - fn from_iter(it: Iterator) -> VmResult { - let mut caller = EnvProtocolCaller; - Self::from_iter_with(it, &mut caller) + fn from_iter(it: Iterator) -> Result { + Self::from_iter_with(it, &mut EnvProtocolCaller) } pub(crate) fn from_iter_with( mut it: Iterator, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { let mut map = Self::new(); - while let Some(value) = vm_try!(it.next()) { - let (key, value) = vm_try!(<(Value, Value)>::from_value(value)); - vm_try!(map.table.insert_with(key, value, caller)); + while let Some(value) = it.next()? { + let (key, value) = <(Value, Value)>::from_value(value)?; + map.table.insert_with(key, value, caller)?; } - VmResult::Ok(map) + Ok(map) } /// Inserts a key-value pair into the map. @@ -524,9 +522,9 @@ impl HashMap { /// assert_eq!(map[37], "c"); /// ``` #[rune::function(keep, protocol = INDEX_SET)] - fn index_set(&mut self, key: Value, value: Value) -> VmResult<()> { - let _ = vm_try!(self.insert(key, value)); - VmResult::Ok(()) + fn index_set(&mut self, key: Value, value: Value) -> Result<(), VmError> { + let _ = self.insert(key, value)?; + Ok(()) } /// Returns a the value corresponding to the key. @@ -552,18 +550,16 @@ impl HashMap { /// assert_eq!(map[1], "a"); /// ``` #[rune::function(keep, protocol = INDEX_GET)] - fn index_get(&self, key: Value) -> VmResult { + fn index_get(&self, key: Value) -> Result { use crate::runtime::TypeOf; - let mut caller = EnvProtocolCaller; - - let Some((_, value)) = vm_try!(self.table.get(&key, &mut caller)) else { - return VmResult::err(VmErrorKind::MissingIndexKey { + let Some((_, value)) = self.table.get(&key, &mut EnvProtocolCaller)? else { + return Err(VmError::from(VmErrorKind::MissingIndexKey { target: Self::type_info(), - }); + })); }; - VmResult::Ok(value.clone()) + Ok(value.clone()) } /// Debug format the current map. @@ -579,7 +575,7 @@ impl HashMap { /// assert_eq!(format!("{:?}", map), "{1: \"a\"}"); /// ``` #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { + fn debug_fmt(&self, f: &mut Formatter) -> Result<(), VmError> { self.debug_fmt_with(f, &mut EnvProtocolCaller) } @@ -587,23 +583,23 @@ impl HashMap { &self, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { - vm_try!(vm_write!(f, "{{")); + ) -> Result<(), VmError> { + write!(f, "{{")?; let mut it = self.table.iter().peekable(); while let Some((key, value)) = it.next() { - vm_try!(key.debug_fmt_with(f, caller)); - vm_try!(vm_write!(f, ": ")); - vm_try!(value.debug_fmt_with(f, caller)); + key.debug_fmt_with(f, caller)?; + write!(f, ": ")?; + value.debug_fmt_with(f, caller)?; if it.peek().is_some() { - vm_try!(vm_write!(f, ", ")); + write!(f, ", ")?; } } - vm_try!(vm_write!(f, "}}")); - VmResult::Ok(()) + write!(f, "}}")?; + Ok(()) } /// Perform a partial equality check over two maps. @@ -633,26 +629,30 @@ impl HashMap { /// assert!(map1 != map2); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - fn partial_eq(&self, other: &Self) -> VmResult { + fn partial_eq(&self, other: &Self) -> Result { self.partial_eq_with(other, &mut EnvProtocolCaller) } - fn partial_eq_with(&self, other: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + fn partial_eq_with( + &self, + other: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { if self.table.len() != other.table.len() { - return VmResult::Ok(false); + return Ok(false); } for (k, v1) in self.table.iter() { - let Some((_, v2)) = vm_try!(other.table.get(k, caller)) else { - return VmResult::Ok(false); + let Some((_, v2)) = other.table.get(k, caller)? else { + return Ok(false); }; - if !vm_try!(Value::partial_eq_with(v1, v2, caller)) { - return VmResult::Ok(false); + if !Value::partial_eq_with(v1, v2, caller)? { + return Ok(false); } } - VmResult::Ok(true) + Ok(true) } /// Perform a total equality check over two maps. @@ -678,26 +678,26 @@ impl HashMap { /// assert!(eq(map1, map2)); /// ``` #[rune::function(keep, protocol = EQ)] - fn eq(&self, other: &Self) -> VmResult { + fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - fn eq_with(&self, other: &Self, caller: &mut EnvProtocolCaller) -> VmResult { + fn eq_with(&self, other: &Self, caller: &mut EnvProtocolCaller) -> Result { if self.table.len() != other.table.len() { - return VmResult::Ok(false); + return Ok(false); } for (k, v1) in self.table.iter() { - let Some((_, v2)) = vm_try!(other.table.get(k, caller)) else { - return VmResult::Ok(false); + let Some((_, v2)) = other.table.get(k, caller)? else { + return Ok(false); }; - if !vm_try!(Value::eq_with(v1, v2, caller)) { - return VmResult::Ok(false); + if !Value::eq_with(v1, v2, caller)? { + return Ok(false); } } - VmResult::Ok(true) + Ok(true) } /// An iterator visiting all key-value pairs in arbitrary order. diff --git a/crates/rune/src/modules/collections/hash_set.rs b/crates/rune/src/modules/collections/hash_set.rs index 816d84079..a76d51386 100644 --- a/crates/rune/src/modules/collections/hash_set.rs +++ b/crates/rune/src/modules/collections/hash_set.rs @@ -1,19 +1,20 @@ use core::ptr; use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; use crate::alloc::hashbrown::raw::RawIter; use crate::alloc::prelude::*; use crate::hashbrown::{IterRef, Table}; use crate::runtime::{ - EnvProtocolCaller, Formatter, Iterator, ProtocolCaller, RawAnyGuard, Ref, Value, VmResult, + EnvProtocolCaller, Formatter, Iterator, ProtocolCaller, RawAnyGuard, Ref, Value, VmError, }; use crate::{Any, ContextError, Module}; /// A dynamic hash set. #[rune::module(::std::collections::hash_set)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(HashSet::new__meta)?; @@ -150,9 +151,9 @@ impl HashSet { /// assert!(set.capacity() >= 10); /// ``` #[rune::function(keep, path = Self::with_capacity)] - pub(crate) fn with_capacity(capacity: usize) -> VmResult { - VmResult::Ok(Self { - table: vm_try!(Table::try_with_capacity(capacity)), + pub(crate) fn with_capacity(capacity: usize) -> alloc::Result { + Ok(Self { + table: Table::try_with_capacity(capacity)?, }) } @@ -224,9 +225,11 @@ impl HashSet { /// assert_eq!(set.len(), 1); /// ``` #[rune::function(keep)] - pub(crate) fn insert(&mut self, key: Value) -> VmResult { - let mut caller = EnvProtocolCaller; - VmResult::Ok(vm_try!(self.table.insert_with(key, (), &mut caller)).is_none()) + pub(crate) fn insert(&mut self, key: Value) -> Result { + Ok(self + .table + .insert_with(key, (), &mut EnvProtocolCaller)? + .is_none()) } /// Removes a value from the set. Returns whether the value was present in @@ -244,9 +247,11 @@ impl HashSet { /// assert_eq!(set.remove(2), false); /// ``` #[rune::function(keep)] - fn remove(&mut self, key: Value) -> VmResult { - let mut caller = EnvProtocolCaller; - VmResult::Ok(vm_try!(self.table.remove_with(&key, &mut caller)).is_some()) + fn remove(&mut self, key: Value) -> Result { + Ok(self + .table + .remove_with(&key, &mut EnvProtocolCaller)? + .is_some()) } /// Returns `true` if the set contains a value. @@ -262,9 +267,8 @@ impl HashSet { /// assert!(!set.contains(4)); /// ``` #[rune::function(keep)] - fn contains(&self, key: Value) -> VmResult { - let mut caller = EnvProtocolCaller; - VmResult::Ok(vm_try!(self.table.get(&key, &mut caller)).is_some()) + fn contains(&self, key: Value) -> Result { + Ok(self.table.get(&key, &mut EnvProtocolCaller)?.is_some()) } /// Clears the set, removing all values. @@ -366,7 +370,7 @@ impl HashSet { /// assert_eq!(union, HashSet::from_iter([1, 2, 3, 4])); /// ``` #[rune::function(keep, instance, path = Self::union)] - fn union(this: Ref, other: Ref) -> VmResult { + fn union(this: Ref, other: Ref) -> Union { unsafe { let (this, this_guard) = Ref::into_raw(Ref::map(this, |this| &this.table)); let (other, other_guard) = Ref::into_raw(Ref::map(other, |this| &this.table)); @@ -394,7 +398,7 @@ impl HashSet { } }; - VmResult::Ok(iter) + iter } } @@ -419,15 +423,15 @@ impl HashSet { /// Extend this set from an iterator. #[rune::function(keep)] - fn extend(&mut self, value: Value) -> VmResult<()> { + fn extend(&mut self, value: Value) -> Result<(), VmError> { let mut caller = EnvProtocolCaller; - let mut it = vm_try!(value.into_iter()); + let mut it = value.into_iter()?; - while let Some(key) = vm_try!(it.next()) { - vm_try!(self.table.insert_with(key, (), &mut caller)); + while let Some(key) = it.next()? { + self.table.insert_with(key, (), &mut caller)?; } - VmResult::Ok(()) + Ok(()) } /// Convert the set into an iterator. @@ -466,25 +470,25 @@ impl HashSet { /// println!("{:?}", set); /// ``` #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { + fn debug_fmt(&self, f: &mut Formatter) -> Result<(), VmError> { self.debug_fmt_with(f, &mut EnvProtocolCaller) } - fn debug_fmt_with(&self, f: &mut Formatter, _: &mut dyn ProtocolCaller) -> VmResult<()> { - vm_try!(vm_write!(f, "{{")); + fn debug_fmt_with(&self, f: &mut Formatter, _: &mut dyn ProtocolCaller) -> Result<(), VmError> { + write!(f, "{{")?; let mut it = self.table.iter().peekable(); - while let Some(value) = it.next() { - vm_try!(vm_write!(f, "{:?}", value)); + while let Some((value, _)) = it.next() { + write!(f, "{value:?}")?; if it.peek().is_some() { - vm_try!(vm_write!(f, ", ")); + write!(f, ", ")?; } } - vm_try!(vm_write!(f, "}}")); - VmResult::Ok(()) + write!(f, "}}")?; + Ok(()) } /// Convert a [`HashSet`] from an iterator. @@ -503,23 +507,22 @@ impl HashSet { /// assert!(set.contains("b")); /// ``` #[rune::function(keep, path = Self::from_iter)] - fn from_iter(it: Iterator) -> VmResult { - let mut caller = EnvProtocolCaller; - Self::from_iter_with(it, &mut caller) + fn from_iter(it: Iterator) -> Result { + Self::from_iter_with(it, &mut EnvProtocolCaller) } pub(crate) fn from_iter_with( mut it: Iterator, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - let (lo, _) = vm_try!(it.size_hint()); - let mut set = vm_try!(Table::try_with_capacity(lo)); + ) -> Result { + let (lo, _) = it.size_hint()?; + let mut set = Table::try_with_capacity(lo)?; - while let Some(key) = vm_try!(it.next()) { - vm_try!(set.insert_with(key, (), caller)); + while let Some(key) = it.next()? { + set.insert_with(key, (), caller)?; } - VmResult::Ok(HashSet { table: set }) + Ok(HashSet { table: set }) } /// Perform a partial equality test between two sets. @@ -536,7 +539,7 @@ impl HashSet { /// assert_ne!(set, HashSet::from_iter([2, 3, 4])); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - fn partial_eq(&self, other: &Self) -> VmResult { + fn partial_eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } @@ -553,28 +556,28 @@ impl HashSet { /// assert!(!eq(set, HashSet::from_iter([2, 3, 4]))); /// ``` #[rune::function(keep, protocol = EQ)] - fn eq(&self, other: &Self) -> VmResult { + fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - fn eq_with(&self, other: &Self, caller: &mut EnvProtocolCaller) -> VmResult { + fn eq_with(&self, other: &Self, caller: &mut EnvProtocolCaller) -> Result { if self.table.len() != other.table.len() { - return VmResult::Ok(false); + return Ok(false); } for (key, ()) in self.table.iter() { - if vm_try!(other.table.get(key, caller)).is_none() { - return VmResult::Ok(false); + if other.table.get(key, caller)?.is_none() { + return Ok(false); } } - VmResult::Ok(true) + Ok(true) } #[rune::function(keep, instance, path = Self::clone, protocol = CLONE)] - fn clone(this: &HashSet) -> VmResult { - VmResult::Ok(Self { - table: vm_try!(this.table.try_clone()), + fn clone(this: &HashSet) -> Result { + Ok(Self { + table: this.table.try_clone()?, }) } } @@ -612,23 +615,23 @@ struct Intersection { impl Intersection { #[rune::function(keep, instance, protocol = NEXT)] - pub(crate) fn next(&mut self) -> VmResult> { + pub(crate) fn next(&mut self) -> Result, VmError> { let mut caller = EnvProtocolCaller; let Some(other) = &self.other else { - return VmResult::Ok(None); + return Ok(None); }; for (key, ()) in self.this.by_ref() { - let c = vm_try!(other.table.get(&key, &mut caller)).is_some(); + let c = other.table.get(&key, &mut caller)?.is_some(); if c { - return VmResult::Ok(Some(key)); + return Ok(Some(key)); } } self.other = None; - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, instance, protocol = SIZE_HINT)] @@ -647,23 +650,23 @@ struct Difference { impl Difference { #[rune::function(keep, instance, protocol = NEXT)] - pub(crate) fn next(&mut self) -> VmResult> { + pub(crate) fn next(&mut self) -> Result, VmError> { let mut caller = EnvProtocolCaller; let Some(other) = &self.other else { - return VmResult::Ok(None); + return Ok(None); }; for (key, ()) in self.this.by_ref() { - let c = vm_try!(other.table.get(&key, &mut caller)).is_some(); + let c = other.table.get(&key, &mut caller)?.is_some(); if !c { - return VmResult::Ok(Some(key)); + return Ok(Some(key)); } } self.other = None; - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, instance, protocol = SIZE_HINT)] @@ -684,13 +687,13 @@ struct Union { impl Union { #[rune::function(keep, instance, protocol = NEXT)] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { // SAFETY: we're holding onto the ref guards for both collections during // iteration, so this is valid for the lifetime of the iterator. unsafe { if let Some(bucket) = self.this_iter.next() { let (value, ()) = bucket.as_ref(); - return VmResult::Ok(Some(value.clone())); + return Ok(Some(value.clone())); } let mut caller = EnvProtocolCaller; @@ -698,12 +701,12 @@ impl Union { for bucket in self.other_iter.by_ref() { let (key, ()) = bucket.as_ref(); - if vm_try!(self.this.as_ref().get(key, &mut caller)).is_none() { - return VmResult::Ok(Some(key.clone())); + if self.this.as_ref().get(key, &mut caller)?.is_none() { + return Ok(Some(key.clone())); } } - VmResult::Ok(None) + Ok(None) } } } diff --git a/crates/rune/src/modules/collections/mod.rs b/crates/rune/src/modules/collections/mod.rs index 240fef742..588ba46f0 100644 --- a/crates/rune/src/modules/collections/mod.rs +++ b/crates/rune/src/modules/collections/mod.rs @@ -1,18 +1,12 @@ //! Dynamic collections. -#[cfg(feature = "alloc")] pub(crate) mod hash_map; -#[cfg(feature = "alloc")] pub(crate) use hash_map::HashMap; -#[cfg(feature = "alloc")] pub(crate) mod hash_set; -#[cfg(feature = "alloc")] pub(crate) use hash_set::HashSet; -#[cfg(feature = "alloc")] pub(crate) mod vec_deque; -#[cfg(feature = "alloc")] pub(crate) use vec_deque::VecDeque; use crate as rune; @@ -21,21 +15,18 @@ use crate::{ContextError, Module}; /// Module defining collections. #[rune::module(::std::collections)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; - #[cfg(feature = "alloc")] m.reexport( ["HashMap"], rune::item!(::std::collections::hash_map::HashMap), )?; - #[cfg(feature = "alloc")] m.reexport( ["HashSet"], rune::item!(::std::collections::hash_set::HashSet), )?; - #[cfg(feature = "alloc")] m.reexport( ["VecDeque"], rune::item!(::std::collections::vec_deque::VecDeque), diff --git a/crates/rune/src/modules/collections/vec_deque.rs b/crates/rune/src/modules/collections/vec_deque.rs index 7a1ff37ec..41431be16 100644 --- a/crates/rune/src/modules/collections/vec_deque.rs +++ b/crates/rune/src/modules/collections/vec_deque.rs @@ -7,14 +7,14 @@ use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::runtime::{ EnvProtocolCaller, Formatter, Iterator, Protocol, ProtocolCaller, RawAnyGuard, Ref, Value, Vec, - VmErrorKind, VmResult, + VmError, VmErrorKind, }; use crate::{Any, ContextError, Module}; /// A dynamic vec deque. #[rune::module(::std::collections::vec_deque)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; @@ -124,9 +124,9 @@ impl VecDeque { /// assert!(deque.capacity() >= 10); /// ``` #[rune::function(keep, path = Self::with_capacity)] - pub(crate) fn with_capacity(count: usize) -> VmResult { - VmResult::Ok(Self { - inner: vm_try!(alloc::VecDeque::try_with_capacity(count)), + pub(crate) fn with_capacity(count: usize) -> alloc::Result { + Ok(Self { + inner: alloc::VecDeque::try_with_capacity(count)?, }) } @@ -145,14 +145,14 @@ impl VecDeque { /// assert_eq!(Some(3), deque.pop_back()); /// ``` #[rune::function] - pub fn extend(&mut self, value: Value) -> VmResult<()> { - let mut it = vm_try!(value.into_iter()); + pub fn extend(&mut self, value: Value) -> Result<(), VmError> { + let mut it = value.into_iter()?; - while let Some(value) = vm_try!(it.next()) { - vm_try!(self.inner.try_push_back(value)); + while let Some(value) = it.next()? { + self.inner.try_push_back(value)?; } - VmResult::Ok(()) + Ok(()) } /// Provides a reference to the front element, or `None` if the deque is @@ -208,9 +208,8 @@ impl VecDeque { /// assert_eq!(Some(3), buf.back()); /// ``` #[rune::function(keep)] - pub(crate) fn push_back(&mut self, value: Value) -> VmResult<()> { - vm_try!(self.inner.try_push_back(value)); - VmResult::Ok(()) + pub(crate) fn push_back(&mut self, value: Value) -> alloc::Result<()> { + self.inner.try_push_back(value) } /// Prepends an element to the deque. @@ -226,9 +225,8 @@ impl VecDeque { /// assert_eq!(d.front(), Some(2)); /// ``` #[rune::function] - fn push_front(&mut self, value: Value) -> VmResult<()> { - vm_try!(self.inner.try_push_front(value)); - VmResult::Ok(()) + fn push_front(&mut self, value: Value) -> alloc::Result<()> { + self.inner.try_push_front(value) } /// Removes the first element and returns it, or `None` if the deque is @@ -289,9 +287,8 @@ impl VecDeque { /// assert!(buf.capacity() >= 11); /// ``` #[rune::function] - fn reserve(&mut self, index: usize) -> VmResult<()> { - vm_try!(self.inner.try_reserve(index)); - VmResult::Ok(()) + fn reserve(&mut self, index: usize) -> alloc::Result<()> { + self.inner.try_reserve(index) } /// Returns the number of elements in the deque. @@ -350,16 +347,16 @@ impl VecDeque { /// assert_eq!(buf, ['a', 'd', 'b', 'c']); /// ``` #[rune::function] - fn insert(&mut self, index: usize, value: Value) -> VmResult<()> { + fn insert(&mut self, index: usize, value: Value) -> Result<(), VmError> { if index > self.inner.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: self.inner.len().into(), - }); + })); } - vm_try!(self.inner.try_insert(index, value)); - VmResult::Ok(()) + self.inner.try_insert(index, value)?; + Ok(()) } /// Removes and returns the element at `index` from the deque. @@ -422,16 +419,16 @@ impl VecDeque { /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// ``` #[rune::function] - fn rotate_left(&mut self, mid: usize) -> VmResult<()> { + fn rotate_left(&mut self, mid: usize) -> Result<(), VmError> { if mid > self.inner.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: mid.into(), length: self.inner.len().into(), - }); + })); } self.inner.rotate_left(mid); - VmResult::Ok(()) + Ok(()) } /// Rotates the double-ended queue `k` places to the right. @@ -468,16 +465,16 @@ impl VecDeque { /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// ``` #[rune::function] - fn rotate_right(&mut self, mid: usize) -> VmResult<()> { + fn rotate_right(&mut self, mid: usize) -> Result<(), VmError> { if mid > self.inner.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: mid.into(), length: self.inner.len().into(), - }); + })); } self.inner.rotate_right(mid); - VmResult::Ok(()) + Ok(()) } /// Returns a front-to-back iterator. @@ -526,38 +523,38 @@ impl VecDeque { /// assert_eq!(deque.len(), 1); /// ``` #[rune::function(keep, path = Self::from_iter)] - fn from_iter(mut it: Iterator) -> VmResult { - let (lo, _) = vm_try!(it.size_hint()); - let mut inner = vm_try!(alloc::VecDeque::try_with_capacity(lo)); + fn from_iter(mut it: Iterator) -> Result { + let (lo, _) = it.size_hint()?; + let mut inner = alloc::VecDeque::try_with_capacity(lo)?; - while let Some(value) = vm_try!(it.next()) { - vm_try!(inner.try_push_back(value)); + while let Some(value) = it.next()? { + inner.try_push_back(value)?; } - VmResult::Ok(Self { inner }) + Ok(Self { inner }) } - fn get(&self, index: usize) -> VmResult { + fn get(&self, index: usize) -> Result { let Some(v) = self.inner.get(index) else { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: self.inner.len().into(), - }); + })); }; - VmResult::Ok(v.clone()) + Ok(v.clone()) } - fn set(&mut self, index: usize, value: Value) -> VmResult<()> { + fn set(&mut self, index: usize, value: Value) -> Result<(), VmError> { let Some(v) = self.inner.get_mut(index) else { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: self.inner.len().into(), - }); + })); }; *v = value; - VmResult::Ok(()) + Ok(()) } /// Write a debug representation to a string. @@ -574,26 +571,30 @@ impl VecDeque { /// assert_eq!(format!("{:?}", deque), "[1, 2, 3]"); /// ``` #[rune::function(protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { + fn debug_fmt(&self, f: &mut Formatter) -> Result<(), VmError> { self.debug_fmt_with(f, &mut EnvProtocolCaller) } #[inline] - fn debug_fmt_with(&self, f: &mut Formatter, caller: &mut dyn ProtocolCaller) -> VmResult<()> { + fn debug_fmt_with( + &self, + f: &mut Formatter, + caller: &mut dyn ProtocolCaller, + ) -> Result<(), VmError> { let mut it = self.inner.iter().peekable(); - vm_try!(vm_write!(f, "[")); + write!(f, "[")?; while let Some(value) = it.next() { - vm_try!(value.debug_fmt_with(f, caller)); + value.debug_fmt_with(f, caller)?; if it.peek().is_some() { - vm_try!(vm_write!(f, ", ")); + write!(f, ", ")?; } } - vm_try!(vm_write!(f, "]")); - VmResult::Ok(()) + write!(f, "]")?; + Ok(()) } /// Perform a partial equality check with this deque. @@ -613,28 +614,28 @@ impl VecDeque { /// assert!(deque != [2, 3, 4]); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - fn partial_eq(&self, b: Value) -> VmResult { + fn partial_eq(&self, b: Value) -> Result { self.partial_eq_with(b, &mut EnvProtocolCaller) } - fn partial_eq_with(&self, b: Value, caller: &mut dyn ProtocolCaller) -> VmResult { - let mut b = vm_try!(b.into_iter_with(caller)); + fn partial_eq_with(&self, b: Value, caller: &mut dyn ProtocolCaller) -> Result { + let mut b = b.into_iter_with(caller)?; for a in &self.inner { - let Some(b) = vm_try!(b.next()) else { - return VmResult::Ok(false); + let Some(b) = b.next()? else { + return Ok(false); }; - if !vm_try!(Value::partial_eq_with(a, &b, caller)) { - return VmResult::Ok(false); + if !Value::partial_eq_with(a, &b, caller)? { + return Ok(false); } } - if vm_try!(b.next()).is_some() { - return VmResult::Ok(false); + if b.next()?.is_some() { + return Ok(false); } - VmResult::Ok(true) + Ok(true) } /// Perform a total equality check with this deque. @@ -651,28 +652,28 @@ impl VecDeque { /// assert!(!eq(deque, VecDeque::from::([2, 3, 4]))); /// ``` #[rune::function(keep, protocol = EQ)] - fn eq(&self, b: &VecDeque) -> VmResult { + fn eq(&self, b: &VecDeque) -> Result { self.eq_with(b, &mut EnvProtocolCaller) } - fn eq_with(&self, b: &VecDeque, caller: &mut dyn ProtocolCaller) -> VmResult { + fn eq_with(&self, b: &VecDeque, caller: &mut dyn ProtocolCaller) -> Result { let mut b = b.inner.iter(); for a in &self.inner { let Some(b) = b.next() else { - return VmResult::Ok(false); + return Ok(false); }; - if !vm_try!(Value::eq_with(a, b, caller)) { - return VmResult::Ok(false); + if !Value::eq_with(a, b, caller)? { + return Ok(false); } } if b.next().is_some() { - return VmResult::Ok(false); + return Ok(false); } - VmResult::Ok(true) + Ok(true) } /// Perform a partial comparison check with this deque. @@ -688,7 +689,7 @@ impl VecDeque { /// assert!(deque < VecDeque::from::([2, 2, 3])); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - fn partial_cmp(&self, b: &VecDeque) -> VmResult> { + fn partial_cmp(&self, b: &VecDeque) -> Result, VmError> { self.partial_cmp_with(b, &mut EnvProtocolCaller) } @@ -696,25 +697,25 @@ impl VecDeque { &self, b: &VecDeque, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { let mut b = b.inner.iter(); for a in self.inner.iter() { let Some(b) = b.next() else { - return VmResult::Ok(Some(Ordering::Greater)); + return Ok(Some(Ordering::Greater)); }; - match vm_try!(Value::partial_cmp_with(a, b, caller)) { + match Value::partial_cmp_with(a, b, caller)? { Some(Ordering::Equal) => (), - other => return VmResult::Ok(other), + other => return Ok(other), } } if b.next().is_some() { - return VmResult::Ok(Some(Ordering::Less)); + return Ok(Some(Ordering::Less)); }; - VmResult::Ok(Some(Ordering::Equal)) + Ok(Some(Ordering::Equal)) } /// Perform a total comparison check with this deque. @@ -732,29 +733,33 @@ impl VecDeque { /// assert_eq!(cmp(deque, VecDeque::from::([2, 2, 3])), Ordering::Less); /// ``` #[rune::function(keep, protocol = CMP)] - fn cmp(&self, b: &VecDeque) -> VmResult { + fn cmp(&self, b: &VecDeque) -> Result { self.cmp_with(b, &mut EnvProtocolCaller) } - fn cmp_with(&self, other: &VecDeque, caller: &mut dyn ProtocolCaller) -> VmResult { + fn cmp_with( + &self, + other: &VecDeque, + caller: &mut dyn ProtocolCaller, + ) -> Result { let mut b = other.inner.iter(); for a in self.inner.iter() { let Some(b) = b.next() else { - return VmResult::Ok(Ordering::Greater); + return Ok(Ordering::Greater); }; - match vm_try!(Value::cmp_with(a, b, caller)) { + match Value::cmp_with(a, b, caller)? { Ordering::Equal => (), - other => return VmResult::Ok(other), + other => return Ok(other), } } if b.next().is_some() { - return VmResult::Ok(Ordering::Less); + return Ok(Ordering::Less); }; - VmResult::Ok(Ordering::Equal) + Ok(Ordering::Equal) } } @@ -792,8 +797,8 @@ impl TryClone for VecDeque { /// let buf = VecDeque::from::([1, 2, 3]); /// ``` #[rune::function(free, path = VecDeque::from::)] -fn from(vec: Vec) -> VmResult { - VmResult::Ok(VecDeque::from(vec)) +fn from(vec: Vec) -> VecDeque { + VecDeque::from(vec) } #[derive(Any)] @@ -839,6 +844,7 @@ impl iter::Iterator for Iter { } impl iter::DoubleEndedIterator for Iter { + #[inline] fn next_back(&mut self) -> Option { Iter::next_back(self) } diff --git a/crates/rune/src/modules/core.rs b/crates/rune/src/modules/core.rs index 04928f7f6..3c7692a24 100644 --- a/crates/rune/src/modules/core.rs +++ b/crates/rune/src/modules/core.rs @@ -5,15 +5,15 @@ use crate::alloc::prelude::*; use crate::compile; use crate::macros::{quote, FormatArgs, MacroContext, TokenStream}; use crate::parse::Parser; -use crate::runtime::{Panic, Value, VmResult}; +use crate::runtime::{Value, VmError}; use crate::{docstring, ContextError, Module}; -#[rune::module(::std)] /// Core types and methods in Rune. /// /// These are types and methods for which Rune as a language would not work without. +#[rune::module(::std)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?.with_unique("std"); + let mut module = Module::from_meta(self::module__meta)?.with_unique("std"); module.ty::()?.docs(docstring! { /// The primitive boolean type. @@ -48,8 +48,8 @@ pub fn module() -> Result { /// /// If you want to format a message, consider using the [panic!] macro. #[rune::function] -fn panic(message: &str) -> VmResult<()> { - VmResult::err(Panic::custom(vm_try!(message.try_to_owned()))) +fn panic(message: &str) -> Result<(), VmError> { + Err(VmError::panic(message.try_to_owned()?)) } /// Test if the given `value` is readable. diff --git a/crates/rune/src/modules/disable_io.rs b/crates/rune/src/modules/disable_io.rs index c0a4cc075..048f95073 100644 --- a/crates/rune/src/modules/disable_io.rs +++ b/crates/rune/src/modules/disable_io.rs @@ -12,13 +12,13 @@ //! ``` use crate as rune; -use crate::runtime::{InstAddress, Memory, Output, VmResult}; +use crate::runtime::{Address, Memory, Output}; use crate::{ContextError, Module}; /// I/O methods which will cause any output to be ignored. #[rune::module(::std::io)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut module = Module::from_meta(self::module__meta)?; module.function("print", move |_: &str| {}).build()?; module.function("println", move |_: &str| {}).build()?; @@ -26,9 +26,9 @@ pub fn module() -> Result { module .raw_function( "dbg", - move |stack: &mut dyn Memory, _: InstAddress, _: usize, out: Output| { - vm_try!(out.store(stack, ())); - VmResult::Ok(()) + move |stack: &mut dyn Memory, _: Address, _: usize, out: Output| { + out.store(stack, ())?; + Ok(()) }, ) .build()?; diff --git a/crates/rune/src/modules/f64.rs b/crates/rune/src/modules/f64.rs index 0c4ade653..3c82eb82e 100644 --- a/crates/rune/src/modules/f64.rs +++ b/crates/rune/src/modules/f64.rs @@ -4,7 +4,7 @@ use core::cmp::Ordering; use core::num::ParseFloatError; use crate as rune; -use crate::runtime::{VmErrorKind, VmResult}; +use crate::runtime::{VmError, VmErrorKind}; use crate::{ContextError, Module}; /// Floating point numbers. @@ -13,7 +13,7 @@ use crate::{ContextError, Module}; /// numbers. #[rune::module(::std::f64)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.function_meta(parse)? .deprecated("Use std::string::parse:: instead")?; @@ -434,12 +434,15 @@ fn partial_eq(this: f64, rhs: f64) -> bool { /// ``` #[rune::function(keep, instance, protocol = EQ)] #[inline] -fn eq(this: f64, rhs: f64) -> VmResult { +fn eq(this: f64, rhs: f64) -> Result { let Some(ordering) = this.partial_cmp(&rhs) else { - return VmResult::err(VmErrorKind::IllegalFloatComparison { lhs: this, rhs }); + return Err(VmError::new(VmErrorKind::IllegalFloatComparison { + lhs: this, + rhs, + })); }; - VmResult::Ok(matches!(ordering, Ordering::Equal)) + Ok(matches!(ordering, Ordering::Equal)) } /// Perform a partial ordered comparison between two floats. @@ -475,10 +478,13 @@ fn partial_cmp(this: f64, rhs: f64) -> Option { /// ``` #[rune::function(keep, instance, protocol = CMP)] #[inline] -fn cmp(this: f64, rhs: f64) -> VmResult { +fn cmp(this: f64, rhs: f64) -> Result { let Some(ordering) = this.partial_cmp(&rhs) else { - return VmResult::err(VmErrorKind::IllegalFloatComparison { lhs: this, rhs }); + return Err(VmError::new(VmErrorKind::IllegalFloatComparison { + lhs: this, + rhs, + })); }; - VmResult::Ok(ordering) + Ok(ordering) } diff --git a/crates/rune/src/modules/fmt.rs b/crates/rune/src/modules/fmt.rs index 046a9798b..290b02fdb 100644 --- a/crates/rune/src/modules/fmt.rs +++ b/crates/rune/src/modules/fmt.rs @@ -3,12 +3,13 @@ use core::fmt; use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::compile; use crate::macros::{FormatArgs, MacroContext, TokenStream}; use crate::parse::Parser; -use crate::runtime::{EnvProtocolCaller, Format, Formatter, VmResult}; +use crate::runtime::{EnvProtocolCaller, Format, Formatter, VmError}; use crate::{ContextError, Module}; /// Formatting text. @@ -24,7 +25,7 @@ use crate::{ContextError, Module}; /// ``` #[rune::module(::std::fmt)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?.with_unique("std::fmt"); + let mut m = Module::from_meta(self::module__meta)?.with_unique("std::fmt"); m.ty::()?; m.ty::()?; @@ -41,8 +42,8 @@ pub fn module() -> Result { } #[rune::function(instance, protocol = DISPLAY_FMT)] -fn fmt_error_display_fmt(error: &fmt::Error, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{error}") +fn fmt_error_display_fmt(error: &fmt::Error, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{error}") } /// Format a string using a format specifier. @@ -75,9 +76,11 @@ pub(crate) fn format( /// assert_eq!(format!("{value}"), "Hello00000"); /// ``` #[rune::function(keep, instance, protocol = DISPLAY_FMT)] -fn format_display_fmt(format: &Format, f: &mut Formatter) -> VmResult<()> { - vm_try!(format.spec.format(&format.value, f, &mut EnvProtocolCaller)); - VmResult::Ok(()) +fn format_display_fmt(format: &Format, f: &mut Formatter) -> Result<(), VmError> { + format + .spec + .format(&format.value, f, &mut EnvProtocolCaller)?; + Ok(()) } /// Write a debug representation of a format specification. @@ -90,8 +93,8 @@ fn format_display_fmt(format: &Format, f: &mut Formatter) -> VmResult<()> { /// assert!(string is String); /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] -fn format_debug_fmt(format: &Format, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{format:?}") +fn format_debug_fmt(format: &Format, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{format:?}") } /// Clones a format specification. @@ -104,6 +107,6 @@ fn format_debug_fmt(format: &Format, f: &mut Formatter) -> VmResult<()> { /// assert_eq!(format!("{value}"), "Hello00000"); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn format_clone(this: &Format) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn format_clone(this: &Format) -> Result { + Ok(this.try_clone()?) } diff --git a/crates/rune/src/modules/future.rs b/crates/rune/src/modules/future.rs index 5bc206317..a082940d5 100644 --- a/crates/rune/src/modules/future.rs +++ b/crates/rune/src/modules/future.rs @@ -2,60 +2,60 @@ use crate as rune; use crate::alloc::Vec; -use crate::runtime::{self, Future, Inline, Repr, SelectFuture, Value, VmErrorKind, VmResult}; +use crate::runtime::{self, Future, Inline, Repr, SelectFuture, Value, VmError, VmErrorKind}; use crate::{ContextError, Module, TypeHash}; /// Asynchronous computations. #[rune::module(::std::future)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut module = Module::from_meta(self::module__meta)?; module.ty::()?; module.function_meta(join__meta)?; Ok(module) } -async fn try_join_impl<'a, I, F>(values: I, len: usize, factory: F) -> VmResult +async fn try_join_impl<'a, I, F>(values: I, len: usize, factory: F) -> Result where I: IntoIterator, - F: FnOnce(Vec) -> VmResult, + F: FnOnce(Vec) -> Result, { use futures_util::stream::StreamExt as _; let mut futures = futures_util::stream::FuturesUnordered::new(); - let mut results = vm_try!(Vec::try_with_capacity(len)); + let mut results = Vec::try_with_capacity(len)?; for (index, value) in values.into_iter().enumerate() { match value.as_ref() { Repr::Inline(value) => { - return VmResult::err([ + return Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(index), - ]); + ])); } Repr::Dynamic(value) => { - return VmResult::err([ + return Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(index), - ]); + ])); } Repr::Any(value) => match value.type_hash() { Future::HASH => { - let future = vm_try!(Value::from(value.clone()).into_future()); + let future = Value::from(value.clone()).into_future()?; futures.push(SelectFuture::new(index, future)); - vm_try!(results.try_push(Value::empty())); + results.try_push(Value::empty())?; } _ => { - return VmResult::err([ + return Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(index), - ]); + ])); } }, } } while !futures.is_empty() { - let (index, value) = vm_try!(futures.next().await.unwrap()); + let (index, value) = futures.next().await.unwrap()?; *results.get_mut(index).unwrap() = value; } @@ -97,42 +97,42 @@ where /// let [] = future::join([]).await; /// ``` #[rune::function(keep)] -async fn join(value: Value) -> VmResult { +async fn join(value: Value) -> Result { match value.as_ref() { Repr::Inline(value) => match value { - Inline::Unit => VmResult::Ok(Value::unit()), - value => VmResult::err([ + Inline::Unit => Ok(Value::unit()), + value => Err(VmError::from([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), - ]), + ])), }, - Repr::Dynamic(value) => VmResult::err([ + Repr::Dynamic(value) => Err(VmError::from([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), - ]), + ])), Repr::Any(value) => match value.type_hash() { runtime::Vec::HASH => { - let vec = vm_try!(value.borrow_ref::()); + let vec = value.borrow_ref::()?; let result = try_join_impl(vec.iter(), vec.len(), |vec| { - VmResult::Ok(vm_try!(Value::vec(vec))) + Value::vec(vec).map_err(VmError::from) }) .await; - VmResult::Ok(vm_try!(result)) + Ok(result?) } runtime::OwnedTuple::HASH => { - let tuple = vm_try!(value.borrow_ref::()); + let tuple = value.borrow_ref::()?; let result = try_join_impl(tuple.iter(), tuple.len(), |vec| { - VmResult::Ok(vm_try!(Value::tuple(vec))) + Value::tuple(vec).map_err(VmError::from) }) .await; - VmResult::Ok(vm_try!(result)) + Ok(result?) } - _ => VmResult::err([ + _ => Err(VmError::from([ VmErrorKind::bad_argument(0), VmErrorKind::expected::(value.type_info()), - ]), + ])), }, } } diff --git a/crates/rune/src/modules/hash.rs b/crates/rune/src/modules/hash.rs index f5153c0c9..4197e3bc6 100644 --- a/crates/rune/src/modules/hash.rs +++ b/crates/rune/src/modules/hash.rs @@ -8,7 +8,7 @@ use crate::{ContextError, Module}; #[rune::module(::std::hash)] pub fn module() -> Result { #[allow(unused_mut)] - let mut module = Module::from_meta(self::module_meta)?; + let mut module = Module::from_meta(self::module__meta)?; module.ty::()?; Ok(module) } diff --git a/crates/rune/src/modules/i64.rs b/crates/rune/src/modules/i64.rs index 2787f7be3..7202eba18 100644 --- a/crates/rune/src/modules/i64.rs +++ b/crates/rune/src/modules/i64.rs @@ -4,9 +4,7 @@ use core::cmp::Ordering; use core::num::ParseIntError; use crate as rune; -use crate::alloc; use crate::alloc::string::TryToString; -use crate::runtime::{VmErrorKind, VmResult}; use crate::{ContextError, Module}; /// Signed integers. @@ -14,7 +12,7 @@ use crate::{ContextError, Module}; /// This provides methods for computing over and parsing 64-bit signed integers. #[rune::module(::std::i64)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; signed!(m, i64); Ok(m) } diff --git a/crates/rune/src/modules/inner_macros.rs b/crates/rune/src/modules/inner_macros.rs index 90c5bfa96..a1c2a5414 100644 --- a/crates/rune/src/modules/inner_macros.rs +++ b/crates/rune/src/modules/inner_macros.rs @@ -45,31 +45,35 @@ macro_rules! unsigned { $m.function_meta(cmp__meta)?; $m.implement_trait::<$ty>(rune::item!(::std::cmp::Ord))?; - $m.constant("MIN", <$ty>::MIN).build()?.docs(docstring! { - /// The smallest value that can be represented by this integer type - /// (−263). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```rune - #[doc = concat!(" assert_eq!(", $n, "::MIN, -9223372036854775808);")] - /// ``` - })?; - - $m.constant("MAX", <$ty>::MAX).build()?.docs(docstring! { - /// The largest value that can be represented by this integer type - /// (263 − 1). - /// - /// # Examples - /// - /// Basic usage: - /// - /// ```rune - #[doc = concat!(" assert_eq!(", $n, "::MAX, 9223372036854775807);")] - /// ``` - })?; + $m.constant("MIN", <$ty>::MIN) + .build()? + .docs($crate::docstring! { + /// The smallest value that can be represented by this integer type + /// (−263). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```rune + #[doc = concat!(" assert_eq!(", $n, "::MIN, -9223372036854775808);")] + /// ``` + })?; + + $m.constant("MAX", <$ty>::MAX) + .build()? + .docs($crate::docstring! { + /// The largest value that can be represented by this integer type + /// (263 − 1). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```rune + #[doc = concat!(" assert_eq!(", $n, "::MAX, 9223372036854775807);")] + /// ``` + })?; }; } @@ -336,12 +340,12 @@ macro_rules! unsigned_fns { /// ``` #[rune::function(instance)] #[inline] - fn wrapping_div(this: $ty, rhs: $ty) -> VmResult<$ty> { + fn wrapping_div(this: $ty, rhs: $ty) -> Result<$ty, $crate::runtime::VmError> { if rhs == 0 { - return VmResult::err(VmErrorKind::DivideByZero); + return Err($crate::runtime::VmError::new($crate::runtime::VmErrorKind::DivideByZero)); } - VmResult::Ok(<$ty>::wrapping_div(this, rhs)) + Ok(<$ty>::wrapping_div(this, rhs)) } /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at @@ -380,12 +384,12 @@ macro_rules! unsigned_fns { /// ``` #[rune::function(instance)] #[inline] - fn wrapping_rem(this: $ty, rhs: $ty) -> VmResult<$ty> { + fn wrapping_rem(this: $ty, rhs: $ty) -> Result<$ty, $crate::runtime::VmError> { if rhs == 0 { - return VmResult::err(VmErrorKind::DivideByZero); + return Err($crate::runtime::VmError::new($crate::runtime::VmErrorKind::DivideByZero)); } - VmResult::Ok(<$ty>::wrapping_rem(this, rhs)) + Ok(<$ty>::wrapping_rem(this, rhs)) } /// Saturating integer addition. Computes `self + rhs`, saturating at the @@ -557,8 +561,8 @@ macro_rules! unsigned_fns { /// ``` #[rune::function(instance)] #[inline] - fn to_string(this: $ty) -> VmResult { - VmResult::Ok(vm_try!(this.try_to_string())) + fn to_string(this: $ty) -> $crate::alloc::Result<$crate::alloc::String> { + this.try_to_string() } }; } diff --git a/crates/rune/src/modules/io.rs b/crates/rune/src/modules/io.rs index f6e32afd8..418fd41d7 100644 --- a/crates/rune/src/modules/io.rs +++ b/crates/rune/src/modules/io.rs @@ -5,22 +5,24 @@ use std::io::{self, Write as _}; use crate as rune; #[cfg(feature = "std")] +use crate::alloc; +#[cfg(feature = "std")] use crate::alloc::fmt::TryWrite; use crate::compile; use crate::macros::{quote, FormatArgs, MacroContext, TokenStream}; use crate::parse::Parser; #[cfg(feature = "std")] -use crate::runtime::{Formatter, InstAddress, Memory, Output, Panic, VmResult}; -use crate::{ContextError, Module}; +use crate::runtime::{Address, Formatter, Memory, Output, VmError}; +use crate::{docstring, ContextError, Module}; /// I/O functions. #[rune::module(::std::io)] pub fn module( #[cfg_attr(not(feature = "std"), allow(unused))] stdio: bool, ) -> Result { - let mut module = Module::from_meta(self::module_meta)?.with_unique("std::io"); + let mut m = Module::from_meta(self::module__meta)?.with_unique("std::io"); - module.item_mut().docs(docstring! { + m.item_mut().docs(docstring! { /// The std::io module contains a number of common things /// you’ll need when doing input and output. /// The most core parts of this module are the [print()], [println()], @@ -37,72 +39,74 @@ pub fn module( })?; #[cfg(feature = "std")] - module.ty::()?; + m.ty::()?; #[cfg(feature = "std")] - module.function_meta(io_error_display_fmt)?; + m.function_meta(io_error_display_fmt)?; #[cfg(feature = "std")] - module.function_meta(io_error_debug_fmt)?; + m.function_meta(io_error_debug_fmt)?; #[cfg(feature = "std")] if stdio { - module.function_meta(print_impl)?; - module.function_meta(println_impl)?; - - module - .raw_function("dbg", dbg_impl) - .build()? - .docs(docstring! { - /// Debug to output. - /// - /// This is the actual output hook, and if you install rune modules without - /// `I/O` enabled this will not be defined. It is then up to someone else to - /// provide an implementation. - /// - /// # Examples - /// - /// ```rune - /// let number = 10; - /// let number = number * 4; - /// - /// let who = "World"; - /// let string = format!("Hello {who}"); - /// - /// dbg(number, string); - /// ``` - })?; + m.function_meta(print_impl)?; + m.function_meta(println_impl)?; + + m.raw_function("dbg", dbg_impl).build()?.docs(docstring! { + /// Debug to output. + /// + /// This is the actual output hook, and if you install rune modules without + /// `I/O` enabled this will not be defined. It is then up to someone else to + /// provide an implementation. + /// + /// # Examples + /// + /// ```rune + /// let number = 10; + /// let number = number * 4; + /// + /// let who = "World"; + /// let string = format!("Hello {who}"); + /// + /// dbg(number, string); + /// ``` + })?; } // These are unconditionally included, but using them might cause a // compilation error unless `::std::io::*` functions are provided somehow. - module.macro_meta(dbg_macro)?; - module.macro_meta(print_macro)?; - module.macro_meta(println_macro)?; - Ok(module) + m.macro_meta(dbg_macro)?; + m.macro_meta(print_macro)?; + m.macro_meta(println_macro)?; + Ok(m) } #[rune::function(instance, protocol = DISPLAY_FMT)] #[cfg(feature = "std")] -fn io_error_display_fmt(error: &io::Error, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{error}") +fn io_error_display_fmt(error: &io::Error, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{error}") } #[rune::function(instance, protocol = DEBUG_FMT)] #[cfg(feature = "std")] -fn io_error_debug_fmt(error: &io::Error, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{error:?}") +fn io_error_debug_fmt(error: &io::Error, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{error:?}") } #[cfg(feature = "std")] -fn dbg_impl(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { +fn dbg_impl( + stack: &mut dyn Memory, + addr: Address, + args: usize, + out: Output, +) -> Result<(), VmError> { let stdout = io::stdout(); let mut stdout = stdout.lock(); - for value in vm_try!(stack.slice_at(addr, args)) { - vm_try!(writeln!(stdout, "{:?}", value).map_err(Panic::custom)); + for value in stack.slice_at(addr, args)? { + writeln!(stdout, "{:?}", value).map_err(VmError::panic)?; } - vm_try!(out.store(stack, ())); - VmResult::Ok(()) + out.store(stack, ())?; + Ok(()) } /// Debug print the given argument. @@ -168,15 +172,11 @@ pub(crate) fn print_macro( /// ``` #[rune::function(path = print)] #[cfg(feature = "std")] -fn print_impl(m: &str) -> VmResult<()> { +fn print_impl(m: &str) -> Result<(), VmError> { let stdout = io::stdout(); let mut stdout = stdout.lock(); - - if let Err(error) = write!(stdout, "{}", m) { - return VmResult::err(Panic::custom(error)); - } - - VmResult::Ok(()) + write!(stdout, "{m}").map_err(VmError::panic)?; + Ok(()) } /// Prints to output, with a newline. @@ -214,13 +214,9 @@ pub(crate) fn println_macro( /// ``` #[rune::function(path = println)] #[cfg(feature = "std")] -fn println_impl(message: &str) -> VmResult<()> { +fn println_impl(message: &str) -> Result<(), VmError> { let stdout = io::stdout(); let mut stdout = stdout.lock(); - - if let Err(error) = writeln!(stdout, "{}", message) { - return VmResult::err(Panic::custom(error)); - } - - VmResult::Ok(()) + writeln!(stdout, "{message}").map_err(VmError::panic)?; + Ok(()) } diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index cd1dac14f..fac63527c 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -3,23 +3,21 @@ use crate as rune; use crate::alloc; use crate::alloc::prelude::*; -use crate::modules::collections::VecDeque; -#[cfg(feature = "alloc")] -use crate::modules::collections::{HashMap, HashSet}; +use crate::modules::collections::{HashMap, HashSet, VecDeque}; use crate::runtime::range::RangeIter; use crate::runtime::{ - FromValue, Function, Inline, InstAddress, Object, Output, OwnedTuple, Protocol, Repr, TypeHash, - Value, Vec, VmErrorKind, VmResult, + Address, FromValue, Function, Inline, Object, Output, OwnedTuple, Protocol, Repr, TypeHash, + Value, Vec, VmError, VmErrorKind, }; use crate::shared::Caller; -use crate::{Any, ContextError, Module, Params}; +use crate::{docstring, Any, ContextError, Module, Params}; /// Rune support for iterators. /// /// This module contains types and methods for working with iterators in Rune. #[rune::module(::std::iter)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(Rev::next__meta)?; @@ -214,12 +212,12 @@ pub fn module() -> Result { let next = next.clone(); move |iter: Value, mut n: usize| loop { - let Some(value) = vm_try!(next.call((iter.clone(),))) else { - break VmResult::Ok(None); + let Some(value) = next.call((iter.clone(),))? else { + break Ok(None); }; if n == 0 { - break VmResult::Ok(Some(value)); + break Ok::<_, VmError>(Some(value)); } n -= 1; @@ -237,8 +235,8 @@ pub fn module() -> Result { let mut n = 0usize; loop { - if vm_try!(next.call((iter.clone(),))).is_none() { - break VmResult::Ok(n); + if next.call((iter.clone(),))?.is_none() { + break Ok::<_, VmError>(n); }; n += 1; @@ -251,11 +249,11 @@ pub fn module() -> Result { cx.function("fold", move |iter: Value, mut acc: Value, f: Function| { loop { - let Some(value) = vm_try!(next.call((iter.clone(),))) else { - break VmResult::Ok(acc); + let Some(value) = next.call((iter.clone(),))? else { + break Ok::<_, VmError>(acc); }; - acc = vm_try!(f.call((acc, value))); + acc = f.call((acc, value))?; } })?; } @@ -264,65 +262,80 @@ pub fn module() -> Result { let next = next.clone(); cx.function("reduce", move |iter: Value, f: Function| { - let Some(mut acc) = vm_try!(next.call((iter.clone(),))) else { - return VmResult::Ok(None); + let Some(mut acc) = next.call((iter.clone(),))? else { + return Ok::<_, VmError>(None); }; - while let Some(value) = vm_try!(next.call((iter.clone(),))) { - acc = vm_try!(f.call((acc, value))); + while let Some(value) = next.call((iter.clone(),))? { + acc = f.call((acc, value))?; } - VmResult::Ok(Some(acc)) + Ok(Some(acc)) })?; } { let next = next.clone(); - cx.function("find", move |iter: Value, f: Function| loop { - let Some(value) = vm_try!(next.call((iter.clone(),))) else { - break VmResult::Ok(None); - }; + cx.function( + "find", + move |iter: Value, f: Function| -> Result, VmError> { + loop { + let Some(value) = next.call((iter.clone(),))? else { + break Ok(None); + }; - if vm_try!(f.call::((value.clone(),))) { - break VmResult::Ok(Some(value)); - } - })?; + if f.call::((value.clone(),))? { + break Ok(Some(value)); + } + } + }, + )?; } { let next = next.clone(); - cx.function("any", move |iter: Value, f: Function| loop { - let Some(value) = vm_try!(next.call((iter.clone(),))) else { - break VmResult::Ok(false); - }; + cx.function( + "any", + move |iter: Value, f: Function| -> Result { + loop { + let Some(value) = next.call((iter.clone(),))? else { + break Ok(false); + }; - if vm_try!(f.call::((value.clone(),))) { - break VmResult::Ok(true); - } - })?; + if f.call::((value.clone(),))? { + break Ok(true); + } + } + }, + )?; } { let next = next.clone(); - cx.function("all", move |iter: Value, f: Function| loop { - let Some(value) = vm_try!(next.call((iter.clone(),))) else { - break VmResult::Ok(true); - }; + cx.function( + "all", + move |iter: Value, f: Function| -> Result { + loop { + let Some(value) = next.call((iter.clone(),))? else { + break Ok(true); + }; - if !vm_try!(f.call::((value.clone(),))) { - break VmResult::Ok(false); - } - })?; + if !f.call::((value.clone(),))? { + break Ok(false); + } + } + }, + )?; } { - cx.function("chain", |a: Value, b: Value| { - let b = vm_try!(b.protocol_into_iter()); + cx.function("chain", |a: Value, b: Value| -> Result { + let b = b.protocol_into_iter()?; - VmResult::Ok(Chain { + Ok(Chain { a: Some(a.clone()), b: Some(b.clone()), }) @@ -357,16 +370,19 @@ pub fn module() -> Result { let next = next.clone(); let size_hint = size_hint.clone(); - cx.function(Params::new("collect", [Vec::HASH]), move |iter: Value| { - let (cap, _) = vm_try!(size_hint.call((&iter,))); - let mut vec = vm_try!(Vec::with_capacity(cap)); + cx.function( + Params::new("collect", [Vec::HASH]), + move |iter: Value| -> Result { + let (cap, _) = size_hint.call((&iter,))?; + let mut vec = Vec::with_capacity(cap)?; - while let Some(value) = vm_try!(next.call((iter.clone(),))) { - vm_try!(vec.push(value)); - } + while let Some(value) = next.call((iter.clone(),))? { + vec.push(value)?; + } - VmResult::Ok(vec) - })?; + Ok(vec) + }, + )?; } { @@ -375,15 +391,15 @@ pub fn module() -> Result { cx.function( Params::new("collect", [VecDeque::HASH]), - move |iter: Value| { - let (cap, _) = vm_try!(size_hint.call((&iter,))); - let mut vec = vm_try!(Vec::with_capacity(cap)); + move |iter: Value| -> Result { + let (cap, _) = size_hint.call((&iter,))?; + let mut vec = Vec::with_capacity(cap)?; - while let Some(value) = vm_try!(next.call((iter.clone(),))) { - vm_try!(vec.push(value)); + while let Some(value) = next.call((iter.clone(),))? { + vec.push(value)?; } - VmResult::Ok(VecDeque::from(vec)) + Ok(VecDeque::from(vec)) }, )?; } @@ -394,15 +410,15 @@ pub fn module() -> Result { cx.function( Params::new("collect", [HashSet::HASH]), - move |iter: Value| { - let (cap, _) = vm_try!(size_hint.call((&iter,))); - let mut set = vm_try!(HashSet::with_capacity(cap)); + move |iter: Value| -> Result { + let (cap, _) = size_hint.call((&iter,))?; + let mut set = HashSet::with_capacity(cap)?; - while let Some(value) = vm_try!(next.call((iter.clone(),))) { - vm_try!(set.insert(value)); + while let Some(value) = next.call((iter.clone(),))? { + set.insert(value)?; } - VmResult::Ok(set) + Ok(set) }, )?; } @@ -413,15 +429,15 @@ pub fn module() -> Result { cx.function( Params::new("collect", [HashMap::HASH]), - move |iter: Value| { - let (cap, _) = vm_try!(size_hint.call((&iter,))); - let mut map = vm_try!(HashMap::with_capacity(cap)); + move |iter: Value| -> Result { + let (cap, _) = size_hint.call((&iter,))?; + let mut map = HashMap::with_capacity(cap)?; - while let Some((key, value)) = vm_try!(next.call((iter.clone(),))) { - vm_try!(map.insert(key, value)); + while let Some((key, value)) = next.call((iter.clone(),))? { + map.insert(key, value)?; } - VmResult::Ok(map) + Ok(map) }, )?; } @@ -432,15 +448,15 @@ pub fn module() -> Result { cx.function( Params::new("collect", [Object::HASH]), - move |iter: Value| { - let (cap, _) = vm_try!(size_hint.call((&iter,))); - let mut map = vm_try!(Object::with_capacity(cap)); + move |iter: Value| -> Result { + let (cap, _) = size_hint.call((&iter,))?; + let mut map = Object::with_capacity(cap)?; - while let Some((key, value)) = vm_try!(next.call((iter.clone(),))) { - vm_try!(map.insert(key, value)); + while let Some((key, value)) = next.call((iter.clone(),))? { + map.insert(key, value)?; } - VmResult::Ok(map) + Ok(map) }, )?; } @@ -451,15 +467,15 @@ pub fn module() -> Result { cx.function( Params::new("collect", [OwnedTuple::HASH]), - move |iter: Value| { - let (cap, _) = vm_try!(size_hint.call((&iter,))); - let mut vec = vm_try!(alloc::Vec::try_with_capacity(cap)); + move |iter: Value| -> Result { + let (cap, _) = size_hint.call((&iter,))?; + let mut vec = alloc::Vec::try_with_capacity(cap)?; - while let Some(value) = vm_try!(next.call((iter.clone(),))) { - vm_try!(vec.try_push(value)); + while let Some(value) = next.call((iter.clone(),))? { + vec.try_push(value)?; } - VmResult::Ok(vm_try!(OwnedTuple::try_from(vec))) + Ok(OwnedTuple::try_from(vec)?) }, )?; } @@ -472,30 +488,30 @@ pub fn module() -> Result { move |iter: Value| { let mut string = String::new(); - while let Some(value) = vm_try!(next.call((iter.clone(),))) { + while let Some(value) = next.call((iter.clone(),))? { match value.as_ref() { Repr::Inline(Inline::Char(c)) => { - vm_try!(string.try_push(*c)); + string.try_push(*c)?; } Repr::Inline(value) => { - return VmResult::expected::(value.type_info()); + return Err(VmError::expected::(value.type_info())); } Repr::Dynamic(value) => { - return VmResult::expected::(value.type_info()); + return Err(VmError::expected::(value.type_info())); } Repr::Any(value) => match value.type_hash() { String::HASH => { - let s = vm_try!(value.borrow_ref::()); - vm_try!(string.try_push_str(&s)); + let s = value.borrow_ref::()?; + string.try_push_str(&s)?; } _ => { - return VmResult::expected::(value.type_info()); + return Err(VmError::expected::(value.type_info())); } }, } } - VmResult::Ok(string) + Ok(string) }, )?; } @@ -503,44 +519,47 @@ pub fn module() -> Result { macro_rules! ops { ($ty:ty) => {{ cx.function(Params::new("product", [<$ty>::HASH]), |iter: Value| { - let mut product = match vm_try!(iter.protocol_next()) { - Some(init) => vm_try!(<$ty>::from_value(init)), + let mut product = match iter.protocol_next()? { + Some(init) => <$ty>::from_value(init)?, None => <$ty>::ONE, }; - while let Some(v) = vm_try!(iter.protocol_next()) { - let v = vm_try!(<$ty>::from_value(v)); + while let Some(v) = iter.protocol_next()? { + let v = <$ty>::from_value(v)?; let Some(out) = product.checked_mul(v) else { - return VmResult::err(VmErrorKind::Overflow); + return Err(VmError::new(VmErrorKind::Overflow)); }; product = out; } - VmResult::Ok(product) + Ok(product) })?; } { - cx.function(Params::new("sum", [<$ty>::HASH]), |iter: Value| { - let mut sum = match vm_try!(iter.protocol_next()) { - Some(init) => vm_try!(<$ty>::from_value(init)), - None => <$ty>::ZERO, - }; + cx.function( + Params::new("sum", [<$ty>::HASH]), + |iter: Value| -> Result<$ty, VmError> { + let mut sum = match iter.protocol_next()? { + Some(init) => <$ty>::from_value(init)?, + None => <$ty>::ZERO, + }; - while let Some(v) = vm_try!(iter.protocol_next()) { - let v = vm_try!(<$ty>::from_value(v)); + while let Some(v) = iter.protocol_next()? { + let v = <$ty>::from_value(v)?; - let Some(out) = sum.checked_add(v) else { - return VmResult::err(VmErrorKind::Overflow); - }; + let Some(out) = sum.checked_add(v) else { + return Err(VmError::new(VmErrorKind::Overflow)); + }; - sum = out; - } + sum = out; + } - VmResult::Ok(sum) - })?; + Ok(sum) + }, + )?; }}; } @@ -552,6 +571,7 @@ pub fn module() -> Result { t.function("next")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::>()? .docs(docstring! { /// Advances the iterator and returns the next value. @@ -588,6 +608,7 @@ pub fn module() -> Result { t.function("nth")? .argument_types::<(Value, usize)>()? + .argument_names(["self", "n"])? .return_type::>()? .docs(docstring! { /// Returns the `n`th element of the iterator. @@ -633,6 +654,7 @@ pub fn module() -> Result { t.function("size_hint")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::<(usize, Option)>()? .docs(docstring! { /// Returns the bounds on the remaining length of the iterator. @@ -704,6 +726,7 @@ pub fn module() -> Result { t.function("count")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Consumes the iterator, counting the number of iterations and returning it. @@ -739,6 +762,7 @@ pub fn module() -> Result { t.function("fold")? .argument_types::<(Value, Value, Function)>()? + .argument_names(["self", "init", "f"])? .return_type::()? .docs(docstring! { /// Folds every element into an accumulator by applying an operation, returning @@ -846,6 +870,7 @@ pub fn module() -> Result { t.function("reduce")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "f"])? .return_type::>()? .docs(docstring! { /// Reduces the elements to a single one, by repeatedly applying a reducing @@ -875,6 +900,7 @@ pub fn module() -> Result { t.function("find")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "predicate"])? .return_type::>()? .docs(docstring! { /// Searches for an element of an iterator that satisfies a predicate. @@ -922,6 +948,7 @@ pub fn module() -> Result { t.function("any")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "f"])? .return_type::()? .docs(docstring! { /// Tests if any element of the iterator matches a predicate. @@ -964,6 +991,7 @@ pub fn module() -> Result { t.function("all")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "f"])? .return_type::()? .docs(docstring! { /// Tests if every element of the iterator matches a predicate. @@ -1006,6 +1034,7 @@ pub fn module() -> Result { t.function("chain")? .argument_types::<(Value, Value)>()? + .argument_names(["self", "other"])? .return_type::()? .docs(docstring! { /// Takes two iterators and creates a new iterator over both in sequence. @@ -1063,6 +1092,7 @@ pub fn module() -> Result { t.function("enumerate")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Creates an iterator which gives the current iteration count as well as @@ -1091,6 +1121,7 @@ pub fn module() -> Result { t.function("filter")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "filter"])? .return_type::()? .docs(docstring! { /// Creates an iterator which uses a closure to determine if an element @@ -1113,6 +1144,7 @@ pub fn module() -> Result { t.function("map")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "f"])? .return_type::()? .docs(docstring! { /// Takes a closure and creates an iterator which calls that closure on each @@ -1163,6 +1195,7 @@ pub fn module() -> Result { t.function("filter_map")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "f"])? .return_type::()? .docs(docstring! { /// Creates an iterator that both filters and maps. @@ -1204,6 +1237,7 @@ pub fn module() -> Result { t.function("flat_map")? .argument_types::<(Value, Function)>()? + .argument_names(["self", "f"])? .return_type::()? .docs(docstring! { /// Creates an iterator that works like map, but flattens nested @@ -1240,6 +1274,7 @@ pub fn module() -> Result { t.function("peekable")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Creates an iterator which can use the [`peek`] method to @@ -1284,6 +1319,7 @@ pub fn module() -> Result { t.function("skip")? .argument_types::<(Value, usize)>()? + .argument_names(["self", "n"])? .return_type::()? .docs(docstring! { /// Creates an iterator that skips the first `n` elements. @@ -1310,6 +1346,7 @@ pub fn module() -> Result { t.function("take")? .argument_types::<(Value, usize)>()? + .argument_names(["self", "n"])? .return_type::()? .docs(docstring! { /// Creates an iterator that yields the first `n` elements, or @@ -1364,6 +1401,7 @@ pub fn module() -> Result { ($ty:ty) => { t.function(Params::new("sum", [<$ty>::HASH]))? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::<$ty>()? .docs(docstring! { /// Sums the elements of an iterator. @@ -1407,6 +1445,7 @@ pub fn module() -> Result { ($ty:ty) => { t.function(Params::new("product", [<$ty>::HASH]))? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::<$ty>()? .docs(docstring! { /// Iterates over the entire iterator, multiplying all @@ -1441,6 +1480,8 @@ pub fn module() -> Result { } t.function(Params::new("collect", [Vec::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as a [`Vec`]. @@ -1455,6 +1496,8 @@ pub fn module() -> Result { })?; t.function(Params::new("collect", [VecDeque::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as a [`VecDeque`]. @@ -1469,6 +1512,8 @@ pub fn module() -> Result { })?; t.function(Params::new("collect", [HashSet::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as a [`HashSet`]. @@ -1486,6 +1531,8 @@ pub fn module() -> Result { })?; t.function(Params::new("collect", [HashMap::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as a [`HashMap`]. @@ -1508,6 +1555,8 @@ pub fn module() -> Result { })?; t.function(Params::new("collect", [Object::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as an [`Object`]. @@ -1520,6 +1569,8 @@ pub fn module() -> Result { })?; t.function(Params::new("collect", [OwnedTuple::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as a [`Tuple`]. @@ -1532,6 +1583,8 @@ pub fn module() -> Result { })?; t.function(Params::new("collect", [String::HASH]))? + .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Collect the iterator as a [`String`]. @@ -1547,6 +1600,7 @@ pub fn module() -> Result { ($ty:ty) => { t.function(Params::new("product", [<$ty>::HASH]))? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::<$ty>()? .docs(docstring! { /// Iterates over the entire iterator, multiplying all @@ -1635,43 +1689,39 @@ pub fn module() -> Result { cx.find_or_define(&Protocol::NTH_BACK, { let next_back = next_back.clone(); - move |iterator: Value, mut n: usize| loop { - let mut memory = [iterator.clone()]; + move |iterator: Value, mut n: usize| -> Result, VmError> { + loop { + let mut memory = [iterator.clone()]; + next_back.call(&mut memory, Address::ZERO, 1, Output::keep(0))?; + let [value] = memory; - vm_try!(next_back( - &mut memory, - InstAddress::ZERO, - 1, - Output::keep(0) - )); - let [value] = memory; + let Some(value) = Option::::from_value(value)? else { + break Ok(None); + }; - let Some(value) = vm_try!(Option::::from_value(value)) else { - break VmResult::Ok(None); - }; + if n == 0 { + break Ok(Some(value)); + } - if n == 0 { - break VmResult::Ok(Some(value)); + n -= 1; } - - n -= 1; } })?; cx.raw_function("rev", |stack, addr, len, out| { - let [value] = vm_try!(stack.slice_at(addr, len)) else { - return VmResult::err(VmErrorKind::BadArgumentCount { + let [value] = stack.slice_at(addr, len)? else { + return Err(VmError::new(VmErrorKind::BadArgumentCount { actual: len, expected: 1, - }); + })); }; let rev = Rev { value: value.clone(), }; - vm_try!(out.store(stack, || rune::to_value(rev))); - VmResult::Ok(()) + out.store(stack, || rune::to_value(rev))?; + Ok(()) })?; Ok(()) @@ -1679,6 +1729,7 @@ pub fn module() -> Result { t.function("next_back")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::>()? .docs(docstring! { /// Removes and returns an element from the end of the iterator. @@ -1707,6 +1758,7 @@ pub fn module() -> Result { t.function("nth_back")? .argument_types::<(Value, usize)>()? + .argument_names(["self", "n"])? .return_type::>()? .docs(docstring! { /// Returns the `n`th element from the end of the iterator. @@ -1756,6 +1808,7 @@ pub fn module() -> Result { t.function("rev")? .argument_types::<(Value,)>()? + .argument_names(["self"])? .return_type::()? .docs(docstring! { /// Reverses an iterator's direction. @@ -1897,7 +1950,7 @@ fn range(start: i64, end: i64) -> RangeIter { macro_rules! fuse { ($self:ident . $iter:ident . $($call:tt)+) => { match $self.$iter { - Some(ref mut iter) => match vm_try!(iter.$($call)+) { + Some(ref mut iter) => match iter.$($call)+? { None => { $self.$iter = None; None @@ -1914,7 +1967,7 @@ macro_rules! fuse { macro_rules! maybe { ($self:ident . $iter:ident . $($call:tt)+) => { match $self.$iter { - Some(ref mut iter) => vm_try!(iter.$($call)+), + Some(ref mut iter) => iter.$($call)+?, None => None, } }; @@ -1930,8 +1983,8 @@ struct Chain { impl Chain { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { - VmResult::Ok(match fuse!(self.a.protocol_next()) { + fn next(&mut self) -> Result, VmError> { + Ok(match fuse!(self.a.protocol_next()) { None => maybe!(self.b.protocol_next()), item => item, }) @@ -1939,8 +1992,8 @@ impl Chain { #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { - VmResult::Ok(match fuse!(self.b.protocol_next_back()) { + fn next_back(&mut self) -> Result, VmError> { + Ok(match fuse!(self.b.protocol_next_back()) { None => maybe!(self.a.protocol_next_back()), item => item, }) @@ -1948,14 +2001,14 @@ impl Chain { #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { match self { Self { a: Some(a), b: Some(b), } => { - let (a_lower, a_upper) = vm_try!(a.protocol_size_hint()); - let (b_lower, b_upper) = vm_try!(b.protocol_size_hint()); + let (a_lower, a_upper) = a.protocol_size_hint()?; + let (b_lower, b_upper) = b.protocol_size_hint()?; let lower = a_lower.saturating_add(b_lower); @@ -1964,7 +2017,7 @@ impl Chain { _ => None, }; - VmResult::Ok((lower, upper)) + Ok((lower, upper)) } Self { a: Some(a), @@ -1974,21 +2027,21 @@ impl Chain { a: None, b: Some(b), } => b.protocol_size_hint(), - Self { a: None, b: None } => VmResult::Ok((0, Some(0))), + Self { a: None, b: None } => Ok((0, Some(0))), } } #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { + fn len(&self) -> Result { match self { Self { a: Some(a), b: Some(b), } => { - let a_len = vm_try!(a.protocol_len()); - let b_len = vm_try!(b.protocol_len()); - VmResult::Ok(a_len.saturating_add(b_len)) + let a_len = a.protocol_len()?; + let b_len = b.protocol_len()?; + Ok(a_len.saturating_add(b_len)) } Self { a: Some(a), @@ -1998,7 +2051,7 @@ impl Chain { a: None, b: Some(b), } => b.protocol_len(), - Self { a: None, b: None } => VmResult::Ok(0), + Self { a: None, b: None } => Ok(0), } } } @@ -2013,36 +2066,36 @@ struct Enumerate { impl Enumerate { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { - if let Some(value) = vm_try!(self.iter.protocol_next()) { + fn next(&mut self) -> Result, VmError> { + if let Some(value) = self.iter.protocol_next()? { let i = self.count; self.count += 1; - return VmResult::Ok(Some((i, value))); + return Ok(Some((i, value))); } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { - if let Some(value) = vm_try!(self.iter.protocol_next_back()) { - let len = vm_try!(self.iter.protocol_len()); - return VmResult::Ok(Some((self.count + len, value))); + fn next_back(&mut self) -> Result, VmError> { + if let Some(value) = self.iter.protocol_next_back()? { + let len = self.iter.protocol_len()?; + return Ok(Some((self.count + len, value))); } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { self.iter.protocol_size_hint() } #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { + fn len(&self) -> Result { self.iter.protocol_len() } } @@ -2057,33 +2110,33 @@ struct Filter { impl Filter { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { - while let Some(value) = vm_try!(self.iter.protocol_next()) { - if vm_try!(self.f.call::((value.clone(),))) { - return VmResult::Ok(Some(value)); + fn next(&mut self) -> Result, VmError> { + while let Some(value) = self.iter.protocol_next()? { + if self.f.call::((value.clone(),))? { + return Ok(Some(value)); } } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { - while let Some(value) = vm_try!(self.iter.protocol_next_back()) { - if vm_try!(self.f.call::((value.clone(),))) { - return VmResult::Ok(Some(value)); + fn next_back(&mut self) -> Result, VmError> { + while let Some(value) = self.iter.protocol_next_back()? { + if self.f.call::((value.clone(),))? { + return Ok(Some(value)); } } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { - let (_, hi) = vm_try!(self.iter.protocol_size_hint()); - VmResult::Ok((0, hi)) + fn size_hint(&self) -> Result<(usize, Option), VmError> { + let (_, hi) = self.iter.protocol_size_hint()?; + Ok((0, hi)) } } @@ -2097,29 +2150,29 @@ struct Map { impl Map { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { if let Some(value) = fuse!(self.iter.protocol_next()) { - return VmResult::Ok(Some(vm_try!(self.f.call::((value.clone(),))))); + return Ok(Some(self.f.call::((value.clone(),))?)); } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { + fn next_back(&mut self) -> Result, VmError> { if let Some(value) = fuse!(self.iter.protocol_next_back()) { - return VmResult::Ok(Some(vm_try!(self.f.call::((value.clone(),))))); + return Ok(Some(self.f.call::((value.clone(),))?)); } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { let Some(iter) = &self.iter else { - return VmResult::Ok((0, Some(0))); + return Ok((0, Some(0))); }; iter.protocol_size_hint() @@ -2127,9 +2180,9 @@ impl Map { #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { + fn len(&self) -> Result { let Some(iter) = &self.iter else { - return VmResult::Ok(0); + return Ok(0); }; iter.protocol_len() @@ -2146,26 +2199,26 @@ struct FilterMap { impl FilterMap { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { while let Some(value) = fuse!(self.iter.protocol_next()) { - if let Some(value) = vm_try!(self.f.call::>((value.clone(),))) { - return VmResult::Ok(Some(value)); + if let Some(value) = self.f.call::>((value.clone(),))? { + return Ok(Some(value)); } } - VmResult::Ok(None) + Ok(None) } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { + fn next_back(&mut self) -> Result, VmError> { while let Some(value) = fuse!(self.iter.protocol_next_back()) { - if let Some(value) = vm_try!(self.f.call::>((value.clone(),))) { - return VmResult::Ok(Some(value)); + if let Some(value) = self.f.call::>((value.clone(),))? { + return Ok(Some(value)); } } - VmResult::Ok(None) + Ok(None) } } @@ -2180,64 +2233,64 @@ struct FlatMap { impl FlatMap { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { loop { if let Some(iter) = &mut self.frontiter { - match vm_try!(iter.protocol_next()) { + match iter.protocol_next()? { None => self.frontiter = None, - item @ Some(_) => return VmResult::Ok(item), + item @ Some(_) => return Ok(item), } } - let Some(value) = vm_try!(self.map.next()) else { - return VmResult::Ok(match &mut self.backiter { - Some(backiter) => vm_try!(backiter.protocol_next()), + let Some(value) = self.map.next()? else { + return Ok(match &mut self.backiter { + Some(backiter) => backiter.protocol_next()?, None => None, }); }; - self.frontiter = Some(vm_try!(value.protocol_into_iter())) + self.frontiter = Some(value.protocol_into_iter()?) } } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { + fn next_back(&mut self) -> Result, VmError> { loop { if let Some(ref mut iter) = self.backiter { - match vm_try!(iter.protocol_next_back()) { + match iter.protocol_next_back()? { None => self.backiter = None, - item @ Some(_) => return VmResult::Ok(item), + item @ Some(_) => return Ok(item), } } - let Some(value) = vm_try!(self.map.next_back()) else { - return VmResult::Ok(match &mut self.frontiter { - Some(frontiter) => vm_try!(frontiter.protocol_next_back()), + let Some(value) = self.map.next_back()? else { + return Ok(match &mut self.frontiter { + Some(frontiter) => frontiter.protocol_next_back()?, None => None, }); }; - self.backiter = Some(vm_try!(value.protocol_into_iter())); + self.backiter = Some(value.protocol_into_iter()?); } } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { let (flo, fhi) = match &self.frontiter { - Some(iter) => vm_try!(iter.protocol_size_hint()), + Some(iter) => iter.protocol_size_hint()?, None => (0, Some(0)), }; let (blo, bhi) = match &self.backiter { - Some(iter) => vm_try!(iter.protocol_size_hint()), + Some(iter) => iter.protocol_size_hint()?, None => (0, Some(0)), }; let lo = flo.saturating_add(blo); - VmResult::Ok(match (vm_try!(self.map.size_hint()), fhi, bhi) { + Ok(match (self.map.size_hint()?, fhi, bhi) { ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)), _ => (lo, None), }) @@ -2254,33 +2307,33 @@ struct Peekable { impl Peekable { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { - VmResult::Ok(match self.peeked.take() { + fn next(&mut self) -> Result, VmError> { + Ok(match self.peeked.take() { Some(v) => v, - None => vm_try!(self.iter.protocol_next()), + None => self.iter.protocol_next()?, }) } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { - VmResult::Ok(match self.peeked.as_mut() { - Some(v @ Some(_)) => vm_try!(self.iter.protocol_next_back()).or_else(|| v.take()), + fn next_back(&mut self) -> Result, VmError> { + Ok(match self.peeked.as_mut() { + Some(v @ Some(_)) => self.iter.protocol_next_back()?.or_else(|| v.take()), Some(None) => None, - None => vm_try!(self.iter.protocol_next_back()), + None => self.iter.protocol_next_back()?, }) } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { let peek_len = match &self.peeked { - Some(None) => return VmResult::Ok((0, Some(0))), + Some(None) => return Ok((0, Some(0))), Some(Some(_)) => 1, None => 0, }; - let (lo, hi) = vm_try!(self.iter.protocol_size_hint()); + let (lo, hi) = self.iter.protocol_size_hint()?; let lo = lo.saturating_add(peek_len); let hi = match hi { @@ -2288,20 +2341,20 @@ impl Peekable { None => None, }; - VmResult::Ok((lo, hi)) + Ok((lo, hi)) } #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { + fn len(&self) -> Result { let peek_len = match &self.peeked { - Some(None) => return VmResult::Ok(0), + Some(None) => return Ok(0), Some(Some(_)) => 1, None => 0, }; - let len = vm_try!(self.iter.protocol_len()); - VmResult::Ok(len.saturating_add(peek_len)) + let len = self.iter.protocol_len()?; + Ok(len.saturating_add(peek_len)) } /// Returns a reference to the `next()` value without advancing the iterator. @@ -2342,14 +2395,14 @@ impl Peekable { /// ``` #[rune::function(keep)] #[inline] - fn peek(&mut self) -> VmResult> { + fn peek(&mut self) -> Result, VmError> { if let Some(v) = &self.peeked { - return VmResult::Ok(v.clone()); + return Ok(v.clone()); } - let value = vm_try!(self.iter.protocol_next()); + let value = self.iter.protocol_next()?; self.peeked = Some(value.clone()); - VmResult::Ok(value) + Ok(value) } } @@ -2363,15 +2416,15 @@ struct Skip { impl Skip { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { if self.n > 0 { let old_n = self.n; self.n = 0; for _ in 0..old_n { - match vm_try!(self.iter.protocol_next()) { + match self.iter.protocol_next()? { Some(..) => (), - None => return VmResult::Ok(None), + None => return Ok(None), } } } @@ -2381,9 +2434,9 @@ impl Skip { #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { - VmResult::Ok(if vm_try!(self.len()) > 0 { - vm_try!(self.iter.protocol_next_back()) + fn next_back(&mut self) -> Result, VmError> { + Ok(if self.len()? > 0 { + self.iter.protocol_next_back()? } else { None }) @@ -2391,18 +2444,18 @@ impl Skip { #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { - let (lower, upper) = vm_try!(self.iter.protocol_size_hint()); + fn size_hint(&self) -> Result<(usize, Option), VmError> { + let (lower, upper) = self.iter.protocol_size_hint()?; let lower = lower.saturating_sub(self.n); let upper = upper.map(|x| x.saturating_sub(self.n)); - VmResult::Ok((lower, upper)) + Ok((lower, upper)) } #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { - let len = vm_try!(self.iter.protocol_len()); - VmResult::Ok(len.saturating_sub(self.n)) + fn len(&self) -> Result { + let len = self.iter.protocol_len()?; + Ok(len.saturating_sub(self.n)) } } @@ -2416,9 +2469,9 @@ struct Take { impl Take { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { if self.n == 0 { - return VmResult::Ok(None); + return Ok(None); } self.n -= 1; @@ -2427,25 +2480,25 @@ impl Take { #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { + fn next_back(&mut self) -> Result, VmError> { if self.n == 0 { - VmResult::Ok(None) + Ok(None) } else { let n = self.n; self.n -= 1; - let len = vm_try!(self.iter.protocol_len()); + let len = self.iter.protocol_len()?; self.iter.protocol_nth_back(len.saturating_sub(n)) } } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { if self.n == 0 { - return VmResult::Ok((0, Some(0))); + return Ok((0, Some(0))); } - let (lower, upper) = vm_try!(self.iter.protocol_size_hint()); + let (lower, upper) = self.iter.protocol_size_hint()?; let lower = lower.min(self.n); @@ -2454,18 +2507,18 @@ impl Take { _ => Some(self.n), }; - VmResult::Ok((lower, upper)) + Ok((lower, upper)) } #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { + fn len(&self) -> Result { if self.n == 0 { - return VmResult::Ok(0); + return Ok(0); } - let len = vm_try!(self.iter.protocol_len()); - VmResult::Ok(len.min(self.n)) + let len = self.iter.protocol_len()?; + Ok(len.min(self.n)) } } @@ -2478,25 +2531,25 @@ struct Rev { impl Rev { #[rune::function(keep, protocol = NEXT)] #[inline] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { self.value.protocol_next_back() } #[rune::function(keep, protocol = NEXT_BACK)] #[inline] - fn next_back(&mut self) -> VmResult> { + fn next_back(&mut self) -> Result, VmError> { self.value.protocol_next() } #[rune::function(keep, protocol = SIZE_HINT)] #[inline] - fn size_hint(&self) -> VmResult<(usize, Option)> { + fn size_hint(&self) -> Result<(usize, Option), VmError> { self.value.protocol_size_hint() } #[rune::function(keep, protocol = LEN)] #[inline] - fn len(&self) -> VmResult { + fn len(&self) -> Result { self.value.protocol_len() } } diff --git a/crates/rune/src/modules/macros.rs b/crates/rune/src/modules/macros.rs index 606a42fa3..fb0349d75 100644 --- a/crates/rune/src/modules/macros.rs +++ b/crates/rune/src/modules/macros.rs @@ -8,5 +8,5 @@ use crate::{ContextError, Module}; /// Macro support. #[rune::module(::std::macros)] pub fn module() -> Result { - Module::from_meta(self::module_meta) + Module::from_meta(self::module__meta) } diff --git a/crates/rune/src/modules/macros/builtin.rs b/crates/rune/src/modules/macros/builtin.rs index 8368eccc2..fdceea28c 100644 --- a/crates/rune/src/modules/macros/builtin.rs +++ b/crates/rune/src/modules/macros/builtin.rs @@ -9,10 +9,10 @@ use crate::{ContextError, Module}; /// Built-in macros. #[rune::module(::std::macros::builtin)] pub fn module() -> Result { - let mut builtins = Module::from_meta(self::module_meta)?.with_unique("std::macros::builtin"); - builtins.macro_meta(file)?; - builtins.macro_meta(line)?; - Ok(builtins) + let mut m = Module::from_meta(self::module__meta)?.with_unique("std::macros::builtin"); + m.macro_meta(file)?; + m.macro_meta(line)?; + Ok(m) } /// Return the line in the current file. diff --git a/crates/rune/src/modules/mem.rs b/crates/rune/src/modules/mem.rs index e372571b8..28747d0a8 100644 --- a/crates/rune/src/modules/mem.rs +++ b/crates/rune/src/modules/mem.rs @@ -1,14 +1,15 @@ //! Working with memory. use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; -use crate::runtime::{self, Formatter, Value, VmResult}; +use crate::runtime::{self, Formatter, Value, VmError}; use crate::{Any, ContextError, Module}; /// Working with memory. #[rune::module(::std::mem)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.function_meta(drop)?; m.function_meta(snapshot)?; @@ -157,13 +158,13 @@ impl Snapshot { } #[rune::function(protocol = DISPLAY_FMT)] - fn display(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{}", self.inner) + fn display(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{}", self.inner) } #[rune::function(protocol = DEBUG_FMT)] - fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{:?}", self.inner) + fn debug(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{:?}", self.inner) } } @@ -181,9 +182,8 @@ impl Snapshot { /// drop(v); /// ``` #[rune::function] -fn drop(value: Value) -> VmResult<()> { - vm_try!(value.drop()); - VmResult::Ok(()) +fn drop(value: Value) -> Result<(), VmError> { + value.drop() } /// Get the usage snapshot of a value. diff --git a/crates/rune/src/modules/num.rs b/crates/rune/src/modules/num.rs index 2f52e0fc7..de2324639 100644 --- a/crates/rune/src/modules/num.rs +++ b/crates/rune/src/modules/num.rs @@ -11,7 +11,7 @@ use crate::{ContextError, Module}; /// when a number cannot be parsed. #[rune::module(::std::num)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?; + let mut module = Module::from_meta(self::module__meta)?; module.ty::()?; module.ty::()?; Ok(module) diff --git a/crates/rune/src/modules/object.rs b/crates/rune/src/modules/object.rs index d12e52514..a08500cab 100644 --- a/crates/rune/src/modules/object.rs +++ b/crates/rune/src/modules/object.rs @@ -1,10 +1,11 @@ //! The dynamic [`Object`] container. use crate as rune; +use crate::alloc; use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::runtime::object::{RuneIter, RuneIterKeys, RuneValues}; -use crate::runtime::{EnvProtocolCaller, Formatter, Object, Protocol, Value, VmResult}; +use crate::runtime::{EnvProtocolCaller, Formatter, Object, Protocol, Value, VmError}; use crate::{ContextError, Module}; /// The dynamic [`Object`] container. @@ -35,15 +36,15 @@ use crate::{ContextError, Module}; /// ``` #[rune::module(::std::object)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(Object::new__meta)?; - m.function_meta(Object::rune_with_capacity)?; + m.function_meta(Object::with_capacity__meta)?; m.function_meta(Object::len__meta)?; m.function_meta(Object::is_empty__meta)?; - m.function_meta(Object::rune_insert)?; + m.function_meta(Object::insert__meta)?; m.function_meta(remove__meta)?; m.function_meta(Object::clear__meta)?; m.function_meta(contains_key__meta)?; @@ -146,7 +147,7 @@ fn get(object: &Object, key: &str) -> Option { /// assert_ne!(b, a); /// ``` #[rune::function(keep, instance, protocol = PARTIAL_EQ)] -fn partial_eq(this: &Object, other: &Object) -> VmResult { +fn partial_eq(this: &Object, other: &Object) -> Result { Object::partial_eq_with(this, other, &mut EnvProtocolCaller) } @@ -165,7 +166,7 @@ fn partial_eq(this: &Object, other: &Object) -> VmResult { /// assert_eq!(eq(b, a), false); /// ``` #[rune::function(keep, instance, protocol = EQ)] -fn eq(this: &Object, other: &Object) -> VmResult { +fn eq(this: &Object, other: &Object) -> Result { Object::eq_with(this, other, Value::eq_with, &mut EnvProtocolCaller) } @@ -182,8 +183,8 @@ fn eq(this: &Object, other: &Object) -> VmResult { /// assert_ne!(a, b); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn clone(this: &Object) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn clone(this: &Object) -> alloc::Result { + this.try_clone() } /// Write a debug representation of an object. @@ -197,6 +198,6 @@ fn clone(this: &Object) -> VmResult { /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] #[inline] -fn debug_fmt(this: &Object, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{this:?}") +fn debug_fmt(this: &Object, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{this:?}") } diff --git a/crates/rune/src/modules/ops.rs b/crates/rune/src/modules/ops.rs index 456e6dfbe..d5ebee685 100644 --- a/crates/rune/src/modules/ops.rs +++ b/crates/rune/src/modules/ops.rs @@ -14,7 +14,7 @@ use crate::runtime::range_from::RangeFromIter; use crate::runtime::range_inclusive::RangeInclusiveIter; use crate::runtime::{ ControlFlow, EnvProtocolCaller, Function, Hasher, Range, RangeFrom, RangeFull, RangeInclusive, - RangeTo, RangeToInclusive, Value, VmResult, + RangeTo, RangeToInclusive, Value, VmError, }; use crate::{ContextError, Module}; @@ -23,7 +23,7 @@ static STATE: OnceCell = OnceCell::new(); /// Overloadable operators and associated types. #[rune::module(::std::ops)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; macro_rules! iter { ($ty:ident) => { @@ -233,7 +233,7 @@ pub fn module() -> Result { /// assert!(!partial_eq(1.0, 2.0)); /// ``` #[rune::function(keep)] -fn partial_eq(lhs: Value, rhs: Value) -> VmResult { +fn partial_eq(lhs: Value, rhs: Value) -> Result { Value::partial_eq(&lhs, &rhs) } @@ -256,7 +256,7 @@ fn partial_eq(lhs: Value, rhs: Value) -> VmResult { /// assert!(!eq(1.0, 2.0)); /// ``` #[rune::function(keep)] -fn eq(lhs: Value, rhs: Value) -> VmResult { +fn eq(lhs: Value, rhs: Value) -> Result { Value::eq(&lhs, &rhs) } @@ -283,7 +283,7 @@ fn eq(lhs: Value, rhs: Value) -> VmResult { /// assert_eq!(partial_cmp(1.0, f64::NAN), None); /// ``` #[rune::function(keep)] -fn partial_cmp(lhs: Value, rhs: Value) -> VmResult> { +fn partial_cmp(lhs: Value, rhs: Value) -> Result, VmError> { Value::partial_cmp(&lhs, &rhs) } @@ -311,7 +311,7 @@ fn partial_cmp(lhs: Value, rhs: Value) -> VmResult> { /// assert_eq!(cmp(1, 2), Ordering::Less); /// ``` #[rune::function(keep)] -fn cmp(lhs: Value, rhs: Value) -> VmResult { +fn cmp(lhs: Value, rhs: Value) -> Result { Value::cmp(&lhs, &rhs) } @@ -338,15 +338,11 @@ fn cmp(lhs: Value, rhs: Value) -> VmResult { /// assert_eq!(hash([1, 2]), hash((1, 2))); /// ``` #[rune::function(keep)] -fn hash(value: Value) -> VmResult { +fn hash(value: Value) -> Result { let state = STATE.get_or_init(RandomState::new); let mut hasher = Hasher::new_with(state); - vm_try!(Value::hash_with( - &value, - &mut hasher, - &mut EnvProtocolCaller - )); + Value::hash_with(&value, &mut hasher, &mut EnvProtocolCaller)?; - VmResult::Ok(hasher.finish()) + Ok(hasher.finish()) } diff --git a/crates/rune/src/modules/ops/generator.rs b/crates/rune/src/modules/ops/generator.rs index 44bb4499c..226f4f96b 100644 --- a/crates/rune/src/modules/ops/generator.rs +++ b/crates/rune/src/modules/ops/generator.rs @@ -1,16 +1,17 @@ //! Overloadable operators and associated types. use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::runtime::generator::Iter; -use crate::runtime::{EnvProtocolCaller, Formatter, Generator, GeneratorState, Value, VmResult}; -use crate::{ContextError, Module}; +use crate::runtime::{EnvProtocolCaller, Formatter, Generator, GeneratorState, Value, VmError}; +use crate::{docstring, ContextError, Module}; /// Types related to generators. #[rune::module(::std::ops::generator)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; { m.ty::()?; @@ -67,7 +68,7 @@ pub fn module() -> Result { /// assert_eq!(g.next(), None); /// `` #[rune::function(keep, instance, path = next)] -fn generator_next(this: &mut Generator) -> VmResult> { +fn generator_next(this: &mut Generator) -> Result, VmError> { this.next() } @@ -114,7 +115,7 @@ fn generator_next(this: &mut Generator) -> VmResult> { /// assert_eq!(g.resume(()), GeneratorState::Complete(())); /// `` #[rune::function(keep, instance, path = resume)] -fn generator_resume(this: &mut Generator, value: Value) -> VmResult { +fn generator_resume(this: &mut Generator, value: Value) -> Result { this.resume(value) } @@ -180,8 +181,8 @@ fn generator_into_iter(this: Generator) -> Iter { /// println!("{a:?}"); /// `` #[rune::function(keep, instance, protocol = DEBUG_FMT)] -fn generator_debug(this: &Generator, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{this:?}") +fn generator_debug(this: &Generator, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{this:?}") } /// Clone a generator. @@ -210,8 +211,8 @@ fn generator_debug(this: &Generator, f: &mut Formatter) -> VmResult<()> { /// assert_eq!(b.resume(()), GeneratorState::Complete(())); /// `` #[rune::function(keep, instance, protocol = CLONE)] -fn generator_clone(this: &Generator) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn generator_clone(this: &Generator) -> alloc::Result { + this.try_clone() } /// Test for partial equality over a generator state. @@ -233,7 +234,10 @@ fn generator_clone(this: &Generator) -> VmResult { /// assert_eq!(g.resume(()), GeneratorState::Complete(())); /// `` #[rune::function(keep, instance, protocol = PARTIAL_EQ)] -fn generator_state_partial_eq(this: &GeneratorState, other: &GeneratorState) -> VmResult { +fn generator_state_partial_eq( + this: &GeneratorState, + other: &GeneratorState, +) -> Result { this.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -257,7 +261,7 @@ fn generator_state_partial_eq(this: &GeneratorState, other: &GeneratorState) -> /// assert!(eq(g.resume(()), GeneratorState::Complete(()))); /// `` #[rune::function(keep, instance, protocol = EQ)] -fn generator_state_eq(this: &GeneratorState, other: &GeneratorState) -> VmResult { +fn generator_state_eq(this: &GeneratorState, other: &GeneratorState) -> Result { this.eq_with(other, &mut EnvProtocolCaller) } @@ -275,21 +279,21 @@ fn generator_state_eq(this: &GeneratorState, other: &GeneratorState) -> VmResult /// println!("{b:?}"); /// `` #[rune::function(keep, instance, protocol = DEBUG_FMT)] -fn generator_state_debug(this: &GeneratorState, f: &mut Formatter) -> VmResult<()> { +fn generator_state_debug(this: &GeneratorState, f: &mut Formatter) -> Result<(), VmError> { match this { GeneratorState::Yielded(value) => { - vm_try!(vm_write!(f, "Yielded(")); - vm_try!(value.debug_fmt_with(f, &mut EnvProtocolCaller)); - vm_try!(vm_write!(f, ")")); + write!(f, "Yielded(")?; + value.debug_fmt_with(f, &mut EnvProtocolCaller)?; + write!(f, ")")?; } GeneratorState::Complete(value) => { - vm_try!(vm_write!(f, "Complete(")); - vm_try!(value.debug_fmt_with(f, &mut EnvProtocolCaller)); - vm_try!(vm_write!(f, ")")); + write!(f, "Complete(")?; + value.debug_fmt_with(f, &mut EnvProtocolCaller)?; + write!(f, ")")?; } } - VmResult::Ok(()) + Ok(()) } /// Clone a generator state. @@ -305,6 +309,6 @@ fn generator_state_debug(this: &GeneratorState, f: &mut Formatter) -> VmResult<( /// assert_eq!(a, b); /// `` #[rune::function(keep, instance, protocol = CLONE)] -fn generator_state_clone(this: &GeneratorState) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn generator_state_clone(this: &GeneratorState) -> alloc::Result { + this.try_clone() } diff --git a/crates/rune/src/modules/option.rs b/crates/rune/src/modules/option.rs index 46b975742..5ab2f2202 100644 --- a/crates/rune/src/modules/option.rs +++ b/crates/rune/src/modules/option.rs @@ -7,8 +7,7 @@ use crate as rune; use crate::alloc::fmt::TryWrite; use crate::alloc::String; use crate::runtime::{ - ControlFlow, EnvProtocolCaller, Formatter, Function, Hasher, Panic, Protocol, RuntimeError, - Value, VmResult, + ControlFlow, EnvProtocolCaller, Formatter, Function, Hasher, Panic, Protocol, Value, VmError, }; use crate::Any; use crate::{hash_in, ContextError, Hash, Module}; @@ -18,20 +17,20 @@ use crate::{hash_in, ContextError, Hash, Module}; /// This module deals with the fundamental [`Option`] type in rune. #[rune::module(::std::option)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; let mut option = m.ty::>()?.make_enum(&["Some", "None"])?; option .variant_mut(0)? .make_unnamed(1)? .constructor(Option::Some)? - .static_docs(&["A some value."])?; + .static_docs(&["Some value."])?; option .variant_mut(1)? .make_empty()? .constructor(|| Option::None)? - .static_docs(&["The empty value."])?; + .static_docs(&["No value."])?; m.associated_function( &Protocol::IS_VARIANT, @@ -43,8 +42,8 @@ pub fn module() -> Result { )?; m.index_function(&Protocol::GET, 0, |this: &Option| match this { - Option::Some(value) => VmResult::Ok(value.clone()), - _ => VmResult::err(RuntimeError::__rune_macros__unsupported_tuple_index_get( + Option::Some(value) => Ok(value.clone()), + _ => Err(crate::__priv::e::unsupported_tuple_index_get( as Any>::ANY_TYPE_INFO, 0, )), @@ -136,13 +135,13 @@ pub fn module() -> Result { /// Styles"](../../std/error/index.html#common-message-styles) in the /// [`std::error`](../../std/error/index.html) module docs. #[rune::function(instance)] -fn expect(option: &Option, message: Value) -> VmResult { +fn expect(option: &Option, message: Value) -> Result { match option { - Some(some) => VmResult::Ok(some.clone()), + Some(some) => Ok(some.clone()), None => { let mut s = String::new(); - vm_try!(Formatter::format_with(&mut s, |f| message.display_fmt(f))); - VmResult::err(Panic::custom(s)) + Formatter::format_with(&mut s, |f| message.display_fmt(f))?; + Err(VmError::from(Panic::custom(s))) } } } @@ -249,11 +248,11 @@ fn into_iter(this: &Option) -> Iter { /// assert_eq!(item_2_0, None); /// ``` #[rune::function(instance)] -fn and_then(option: &Option, then: Function) -> VmResult> { +fn and_then(option: &Option, then: Function) -> Result, VmError> { match option { // no need to clone v, passing the same reference forward - Some(v) => VmResult::Ok(vm_try!(then.call((v.clone(),)))), - None => VmResult::Ok(None), + Some(v) => Ok(then.call((v.clone(),))?), + None => Ok(None), } } @@ -277,11 +276,11 @@ fn and_then(option: &Option, then: Function) -> VmResult> { /// assert_eq!(x.map(|s| s.len()), None); /// ``` #[rune::function(instance)] -fn map(option: &Option, then: Function) -> VmResult> { +fn map(option: &Option, then: Function) -> Result, VmError> { match option { // no need to clone v, passing the same reference forward - Some(v) => VmResult::Ok(Some(vm_try!(then.call((v.clone(),))))), - None => VmResult::Ok(None), + Some(v) => Ok(Some(then.call((v.clone(),))?)), + None => Ok(None), } } @@ -319,25 +318,25 @@ fn take(option: &mut Option) -> Option { /// assert_eq!(x, y.transpose()); /// ``` #[rune::function(instance)] -fn transpose(this: &Option) -> VmResult { +fn transpose(this: &Option) -> Result { let value = match this { Some(value) => value, 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 none = Value::try_from(Option::::None)?; + let result = Value::try_from(Result::::Ok(none))?; + return Ok(result); } }; - match &*vm_try!(value.borrow_ref::>()) { + match &*value.borrow_ref::>()? { Ok(ok) => { - let some = vm_try!(Value::try_from(Some(ok.clone()))); - let result = vm_try!(Value::try_from(Ok(some))); - VmResult::Ok(result) + let some = Value::try_from(Some(ok.clone()))?; + let result = Value::try_from(Ok(some))?; + Ok(result) } Err(err) => { - let result = vm_try!(Value::try_from(Err(err.clone()))); - VmResult::Ok(result) + let result = Value::try_from(Err(err.clone()))?; + Ok(result) } } } @@ -368,10 +367,12 @@ fn transpose(this: &Option) -> VmResult { /// assert_eq!(x.unwrap(), "air"); // fails /// ``` #[rune::function(instance)] -fn unwrap(option: &Option) -> VmResult { +fn unwrap(option: &Option) -> Result { match option { - Some(some) => VmResult::Ok(some.clone()), - None => VmResult::err(Panic::custom("Called `Option::unwrap()` on a `None` value")), + Some(some) => Ok(some.clone()), + None => Err(VmError::from(Panic::custom( + "Called `Option::unwrap()` on a `None` value", + ))), } } @@ -407,9 +408,9 @@ fn unwrap_or(this: &Option, default: Value) -> Value { /// assert_eq!(None.unwrap_or_else(|| 2 * k), 20); /// ``` #[rune::function(instance)] -fn unwrap_or_else(this: &Option, default: Function) -> VmResult { +fn unwrap_or_else(this: &Option, default: Function) -> Result { match this { - Some(value) => VmResult::Ok(value.clone()), + Some(value) => Ok(value.clone()), None => default.call(()), } } @@ -460,10 +461,10 @@ fn ok_or(this: &Option, err: Value) -> Result { /// assert_eq!(x.ok_or_else(|| 0), Err(0)); /// ``` #[rune::function(instance)] -fn ok_or_else(this: &Option, err: Function) -> VmResult> { +fn ok_or_else(this: &Option, err: Function) -> Result, VmError> { match this { - Some(value) => VmResult::Ok(Ok(value.clone())), - None => VmResult::Ok(Err(vm_try!(err.call(())))), + Some(value) => Ok(Ok(value.clone())), + None => Ok(Err(err.call(())?)), } } @@ -481,9 +482,9 @@ fn ok_or_else(this: &Option, err: Function) -> VmResult) -> VmResult> { - VmResult::Ok(match this { - Some(value) => Some(vm_try!(value.clone_with(&mut EnvProtocolCaller))), +fn clone(this: &Option) -> Result, VmError> { + Ok(match this { + Some(value) => Some(value.clone_with(&mut EnvProtocolCaller)?), None => None, }) } @@ -511,11 +512,11 @@ fn clone(this: &Option) -> VmResult> { /// ``` #[rune::function(keep, instance, protocol = PARTIAL_EQ)] #[inline] -fn partial_eq(this: &Option, rhs: &Option) -> VmResult { +fn partial_eq(this: &Option, rhs: &Option) -> Result { match (this, rhs) { - (Some(a), Some(b)) => Value::partial_eq(a, b), - (None, None) => VmResult::Ok(true), - _ => VmResult::Ok(false), + (Some(a), Some(b)) => Ok(Value::partial_eq(a, b)?), + (None, None) => Ok(true), + _ => Ok(false), } } @@ -533,11 +534,11 @@ fn partial_eq(this: &Option, rhs: &Option) -> VmResult { /// ``` #[rune::function(keep, instance, protocol = EQ)] #[inline] -fn eq(this: &Option, rhs: &Option) -> VmResult { +fn eq(this: &Option, rhs: &Option) -> Result { match (this, rhs) { - (Some(a), Some(b)) => Value::eq(a, b), - (None, None) => VmResult::Ok(true), - _ => VmResult::Ok(false), + (Some(a), Some(b)) => Ok(Value::eq(a, b)?), + (None, None) => Ok(true), + _ => Ok(false), } } @@ -563,12 +564,12 @@ fn eq(this: &Option, rhs: &Option) -> VmResult { /// ``` #[rune::function(keep, instance, protocol = PARTIAL_CMP)] #[inline] -fn partial_cmp(this: &Option, rhs: &Option) -> VmResult> { +fn partial_cmp(this: &Option, rhs: &Option) -> Result, VmError> { match (this, rhs) { - (Some(a), Some(b)) => Value::partial_cmp(a, b), - (None, None) => VmResult::Ok(Some(Ordering::Equal)), - (Some(..), None) => VmResult::Ok(Some(Ordering::Greater)), - (None, Some(..)) => VmResult::Ok(Some(Ordering::Less)), + (Some(a), Some(b)) => Ok(Value::partial_cmp(a, b)?), + (None, None) => Ok(Some(Ordering::Equal)), + (Some(..), None) => Ok(Some(Ordering::Greater)), + (None, Some(..)) => Ok(Some(Ordering::Less)), } } @@ -586,12 +587,12 @@ fn partial_cmp(this: &Option, rhs: &Option) -> VmResult, rhs: &Option) -> VmResult { +fn cmp(this: &Option, rhs: &Option) -> Result { match (this, rhs) { - (Some(a), Some(b)) => Value::cmp(a, b), - (None, None) => VmResult::Ok(Ordering::Equal), - (Some(..), None) => VmResult::Ok(Ordering::Greater), - (None, Some(..)) => VmResult::Ok(Ordering::Less), + (Some(a), Some(b)) => Ok(Value::cmp(a, b)?), + (None, None) => Ok(Ordering::Equal), + (Some(..), None) => Ok(Ordering::Greater), + (None, Some(..)) => Ok(Ordering::Less), } } @@ -608,18 +609,18 @@ fn cmp(this: &Option, rhs: &Option) -> VmResult { /// assert_eq!(hash(a), hash(b)); /// ``` #[rune::function(keep, instance, protocol = HASH)] -fn hash(this: &Option, hasher: &mut Hasher) -> VmResult<()> { +fn hash(this: &Option, hasher: &mut Hasher) -> Result<(), VmError> { match this { Some(value) => { hasher.write_u64(0); - vm_try!(value.hash(hasher)); + value.hash(hasher)?; } None => { hasher.write_u64(1); } } - VmResult::Ok(()) + Ok(()) } /// Write a debug representation of a result. @@ -632,19 +633,19 @@ fn hash(this: &Option, hasher: &mut Hasher) -> VmResult<()> { /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] #[inline] -fn debug_fmt(this: &Option, f: &mut Formatter) -> VmResult<()> { +fn debug_fmt(this: &Option, f: &mut Formatter) -> Result<(), VmError> { match this { Some(value) => { - vm_try!(f.try_write_str("Some(")); - vm_try!(value.debug_fmt(f)); - vm_try!(f.try_write_str(")")); + f.try_write_str("Some(")?; + value.debug_fmt(f)?; + f.try_write_str(")")?; } None => { - vm_try!(f.try_write_str("None")); + f.try_write_str("None")?; } } - VmResult::Ok(()) + Ok(()) } /// Using [`Option`] with the try protocol. @@ -660,10 +661,10 @@ fn debug_fmt(this: &Option, f: &mut Formatter) -> VmResult<()> { /// assert_eq!(maybe_add_one(None), None); /// ``` #[rune::function(keep, instance, protocol = TRY)] -pub(crate) fn option_try(this: &Option) -> VmResult { - VmResult::Ok(match this { +pub(crate) fn option_try(this: &Option) -> Result { + Ok(match this { Some(value) => ControlFlow::Continue(value.clone()), - None => ControlFlow::Break(vm_try!(Value::try_from(None))), + None => ControlFlow::Break(Value::try_from(None)?), }) } diff --git a/crates/rune/src/modules/result.rs b/crates/rune/src/modules/result.rs index 8f4887936..1de9bfc12 100644 --- a/crates/rune/src/modules/result.rs +++ b/crates/rune/src/modules/result.rs @@ -7,7 +7,7 @@ use crate as rune; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::runtime::{ - ControlFlow, EnvProtocolCaller, Formatter, Function, Hasher, Panic, Protocol, Value, VmResult, + ControlFlow, EnvProtocolCaller, Formatter, Function, Hasher, Panic, Protocol, Value, VmError, }; use crate::{hash_in, ContextError, Hash, Module}; @@ -16,7 +16,7 @@ use crate::{hash_in, ContextError, Hash, Module}; /// This module deals with the fundamental [`Result`] type in Rune. #[rune::module(::std::result)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; // Sorted for ease of finding let mut result = m @@ -49,8 +49,8 @@ pub fn module() -> Result { &Protocol::GET, 0, |this: &Result| match this { - Result::Ok(value) => VmResult::Ok(value.clone()), - Result::Err(value) => VmResult::Ok(value.clone()), + Result::Ok(value) => value.clone(), + Result::Err(value) => value.clone(), }, )?; @@ -163,17 +163,14 @@ fn is_err(result: &Result) -> bool { /// x.unwrap(); // panics with `emergency failure` /// ``` #[rune::function(instance)] -fn unwrap(result: &Result) -> VmResult { +fn unwrap(result: &Result) -> Result { match result { - Ok(value) => VmResult::Ok(value.clone()), + Ok(value) => Ok(value.clone()), Err(err) => { let mut m = String::new(); - vm_try!(vm_write!( - m, - "Called `Result::unwrap()` on an `Err` value: " - )); - vm_try!(Formatter::format_with(&mut m, |f| err.debug_fmt(f))); - VmResult::err(Panic::custom(m)) + write!(m, "Called `Result::unwrap()` on an `Err` value: ")?; + Formatter::format_with(&mut m, |f| err.debug_fmt(f))?; + Err(VmError::from(Panic::custom(m))) } } } @@ -218,9 +215,9 @@ fn unwrap_or(this: &Result, default: Value) -> Value { /// assert_eq!(Err("foo").unwrap_or_else(count), 3); /// ``` #[rune::function(instance)] -fn unwrap_or_else(this: &Result, default: Function) -> VmResult { +fn unwrap_or_else(this: &Result, default: Function) -> Result { match this { - Ok(value) => VmResult::Ok(value.clone()), + Ok(value) => Ok(value.clone()), Err(error) => default.call((error,)), } } @@ -255,18 +252,18 @@ fn unwrap_or_else(this: &Result, default: Function) -> VmResult, message: Value) -> VmResult { +fn expect(result: &Result, message: Value) -> Result { match result { - Ok(value) => VmResult::Ok(value.clone()), + Ok(value) => Ok(value.clone()), Err(err) => { let mut s = String::new(); - vm_try!(Formatter::format_with(&mut s, |f| { - vm_try!(message.display_fmt(f)); - vm_try!(f.try_write_str(": ")); - vm_try!(err.debug_fmt(f)); - VmResult::Ok(()) - })); - VmResult::err(Panic::custom(s)) + Formatter::format_with(&mut s, |f| { + message.display_fmt(f)?; + f.try_write_str(": ")?; + err.debug_fmt(f)?; + Ok::<_, VmError>(()) + })?; + Err(VmError::from(Panic::custom(s))) } } } @@ -287,10 +284,10 @@ fn expect(result: &Result, message: Value) -> VmResult { /// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number")); /// ``` #[rune::function(instance)] -fn and_then(this: &Result, op: Function) -> VmResult> { +fn and_then(this: &Result, op: Function) -> Result, VmError> { match this { - Ok(v) => VmResult::Ok(vm_try!(op.call((v,)))), - Err(e) => VmResult::Ok(Err(e.clone())), + Ok(v) => Ok(op.call((v,))?), + Err(e) => Ok(Err(e.clone())), } } @@ -314,10 +311,10 @@ fn and_then(this: &Result, op: Function) -> VmResult, then: Function) -> VmResult> { +fn map(this: &Result, then: Function) -> Result, VmError> { match this { - Ok(v) => VmResult::Ok(Ok(vm_try!(then.call((v,))))), - Err(e) => VmResult::Ok(Err(e.clone())), + Ok(v) => Ok(Ok(then.call((v,))?)), + Err(e) => Ok(Err(e.clone())), } } @@ -335,10 +332,10 @@ fn map(this: &Result, then: Function) -> VmResult) -> VmResult> { - VmResult::Ok(match this { - Ok(ok) => Ok(vm_try!(ok.clone_with(&mut EnvProtocolCaller))), - Err(err) => Err(vm_try!(err.clone_with(&mut EnvProtocolCaller))), +fn clone(this: &Result) -> Result, VmError> { + Ok(match this { + Ok(ok) => Ok(ok.clone_with(&mut EnvProtocolCaller)?), + Err(err) => Err(err.clone_with(&mut EnvProtocolCaller)?), }) } @@ -363,11 +360,11 @@ fn clone(this: &Result) -> VmResult> { /// ``` #[rune::function(keep, instance, protocol = PARTIAL_EQ)] #[inline] -fn partial_eq(this: &Result, rhs: &Result) -> VmResult { +fn partial_eq(this: &Result, rhs: &Result) -> Result { match (this, rhs) { - (Ok(a), Ok(b)) => Value::partial_eq(a, b), - (Err(a), Err(b)) => Value::partial_eq(a, b), - _ => VmResult::Ok(false), + (Ok(a), Ok(b)) => Ok(Value::partial_eq(a, b)?), + (Err(a), Err(b)) => Ok(Value::partial_eq(a, b)?), + _ => Ok(false), } } @@ -384,11 +381,11 @@ fn partial_eq(this: &Result, rhs: &Result) -> VmResu /// ``` #[rune::function(keep, instance, protocol = EQ)] #[inline] -fn eq(this: &Result, rhs: &Result) -> VmResult { +fn eq(this: &Result, rhs: &Result) -> Result { match (this, rhs) { (Ok(a), Ok(b)) => Value::eq(a, b), (Err(a), Err(b)) => Value::eq(a, b), - _ => VmResult::Ok(false), + _ => Ok(false), } } @@ -417,12 +414,12 @@ fn eq(this: &Result, rhs: &Result) -> VmResult fn partial_cmp( this: &Result, rhs: &Result, -) -> VmResult> { +) -> Result, VmError> { match (this, rhs) { (Ok(a), Ok(b)) => Value::partial_cmp(a, b), (Err(a), Err(b)) => Value::partial_cmp(a, b), - (Ok(..), Err(..)) => VmResult::Ok(Some(Ordering::Greater)), - (Err(..), Ok(..)) => VmResult::Ok(Some(Ordering::Less)), + (Ok(..), Err(..)) => Ok(Some(Ordering::Greater)), + (Err(..), Ok(..)) => Ok(Some(Ordering::Less)), } } @@ -440,12 +437,12 @@ fn partial_cmp( /// ``` #[rune::function(keep, instance, protocol = CMP)] #[inline] -fn cmp(this: &Result, rhs: &Result) -> VmResult { +fn cmp(this: &Result, rhs: &Result) -> Result { match (this, rhs) { (Ok(a), Ok(b)) => Value::cmp(a, b), (Err(a), Err(b)) => Value::cmp(a, b), - (Ok(..), Err(..)) => VmResult::Ok(Ordering::Greater), - (Err(..), Ok(..)) => VmResult::Ok(Ordering::Less), + (Ok(..), Err(..)) => Ok(Ordering::Greater), + (Err(..), Ok(..)) => Ok(Ordering::Less), } } @@ -462,19 +459,19 @@ fn cmp(this: &Result, rhs: &Result) -> VmResult, hasher: &mut Hasher) -> VmResult<()> { +fn hash(this: &Result, hasher: &mut Hasher) -> Result<(), VmError> { match this { Ok(value) => { hasher.write_u64(0); - vm_try!(value.hash(hasher)); + value.hash(hasher)?; } Err(value) => { hasher.write_u64(1); - vm_try!(value.hash(hasher)); + value.hash(hasher)?; } } - VmResult::Ok(()) + Ok(()) } /// Write a debug representation of a result. @@ -487,21 +484,21 @@ fn hash(this: &Result, hasher: &mut Hasher) -> VmResult<()> { /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] #[inline] -fn debug_fmt(this: &Result, f: &mut Formatter) -> VmResult<()> { +fn debug_fmt(this: &Result, f: &mut Formatter) -> Result<(), VmError> { match this { Ok(value) => { - vm_try!(f.try_write_str("Ok(")); - vm_try!(value.debug_fmt(f)); - vm_try!(f.try_write_str(")")); + f.try_write_str("Ok(")?; + value.debug_fmt(f)?; + f.try_write_str(")")?; } Err(value) => { - vm_try!(f.try_write_str("Err(")); - vm_try!(value.debug_fmt(f)); - vm_try!(f.try_write_str(")")); + f.try_write_str("Err(")?; + value.debug_fmt(f)?; + f.try_write_str(")")?; } } - VmResult::Ok(()) + Ok(()) } /// Using [`Result`] with the try protocol. @@ -517,9 +514,9 @@ fn debug_fmt(this: &Result, f: &mut Formatter) -> VmResult<()> { /// assert_eq!(maybe_add_one(Err("not a number")), Err("not a number")); /// ``` #[rune::function(keep, instance, protocol = TRY)] -pub(crate) fn result_try(this: &Result) -> VmResult { - VmResult::Ok(match this { +pub(crate) fn result_try(this: &Result) -> Result { + Ok(match this { Ok(value) => ControlFlow::Continue(value.clone()), - Err(error) => ControlFlow::Break(vm_try!(Value::try_from(Err(error.clone())))), + Err(error) => ControlFlow::Break(Value::try_from(Err(error.clone()))?), }) } diff --git a/crates/rune/src/modules/slice.rs b/crates/rune/src/modules/slice.rs index 37ab3a9cd..7ced725df 100644 --- a/crates/rune/src/modules/slice.rs +++ b/crates/rune/src/modules/slice.rs @@ -17,7 +17,7 @@ use crate::{ContextError, Module}; /// ``` #[rune::module(::std::slice)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(Iter::next__meta)?; diff --git a/crates/rune/src/modules/stream.rs b/crates/rune/src/modules/stream.rs index c576978fb..608fc43bb 100644 --- a/crates/rune/src/modules/stream.rs +++ b/crates/rune/src/modules/stream.rs @@ -7,7 +7,7 @@ use crate::{ContextError, Module}; /// Asynchronous streams. #[rune::module(::std::stream)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; m.function_meta(Stream::next_shared__meta)?; m.function_meta(Stream::resume_shared__meta)?; diff --git a/crates/rune/src/modules/string.rs b/crates/rune/src/modules/string.rs index 0a0abd22b..fb4cbf6af 100644 --- a/crates/rune/src/modules/string.rs +++ b/crates/rune/src/modules/string.rs @@ -5,15 +5,15 @@ use core::cmp::Ordering; use core::num::{ParseFloatError, ParseIntError}; use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::alloc::string::FromUtf8Error; -use crate::alloc::{String, Vec}; use crate::compile::Named; use crate::runtime::{ - Bytes, Formatter, FromValue, Function, Hasher, Inline, MaybeTypeOf, Panic, Range, RangeFrom, + Bytes, Formatter, FromValue, Function, Hasher, Inline, MaybeTypeOf, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Ref, Repr, ToValue, TypeOf, Value, - VmErrorKind, VmResult, + VmError, VmErrorKind, }; use crate::{Any, ContextError, Module, TypeHash}; @@ -31,7 +31,7 @@ use crate::{Any, ContextError, Module, TypeHash}; /// ``` #[rune::module(::std::string)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?; @@ -62,7 +62,7 @@ pub fn module() -> Result { m.function_meta(replace)?; m.function_meta(is_empty)?; m.function_meta(chars)?; - m.function_meta(get)?; + m.function_meta(get__meta)?; m.function_meta(parse_int)?; m.function_meta(parse_float)?; m.function_meta(parse_char)?; @@ -164,9 +164,9 @@ pub fn module() -> Result { /// [`&str`]: prim@str "&str" /// [`into_bytes`]: String::into_bytes #[rune::function(free, path = String::from_utf8)] -fn from_utf8(bytes: &[u8]) -> VmResult> { - let vec = vm_try!(Vec::try_from(bytes)); - VmResult::Ok(String::from_utf8(vec)) +fn from_utf8(bytes: &[u8]) -> Result, VmError> { + let vec = Vec::try_from(bytes)?; + Ok(String::from_utf8(vec)) } /// Returns a byte slice of this `String`'s contents. @@ -185,8 +185,8 @@ fn from_utf8(bytes: &[u8]) -> VmResult> { /// assert!(is_readable(s)); /// ``` #[rune::function(instance)] -fn as_bytes(s: &str) -> VmResult { - VmResult::Ok(Bytes::from_vec(vm_try!(Vec::try_from(s.as_bytes())))) +fn as_bytes(s: &str) -> Result { + Ok(Bytes::from_vec(Vec::try_from(s.as_bytes())?)) } /// Constructs a string from another string. @@ -200,13 +200,13 @@ fn as_bytes(s: &str) -> VmResult { /// assert_eq!(s, "hello"); /// ``` #[rune::function(free, path = String::from)] -fn string_from(value: &str) -> VmResult { - VmResult::Ok(vm_try!(String::try_from(value))) +fn string_from(value: &str) -> Result { + Ok(String::try_from(value)?) } #[rune::function(free, path = String::from_str, deprecated = "Use String::from instead")] -fn string_from_str(value: &str) -> VmResult { - VmResult::Ok(vm_try!(String::try_from(value))) +fn string_from_str(value: &str) -> Result { + Ok(String::try_from(value)?) } /// Creates a new empty `String`. @@ -270,8 +270,8 @@ fn string_new() -> String { /// s.push('a'); /// ``` #[rune::function(free, path = String::with_capacity)] -fn string_with_capacity(capacity: usize) -> VmResult { - VmResult::Ok(vm_try!(String::try_with_capacity(capacity))) +fn string_with_capacity(capacity: usize) -> Result { + Ok(String::try_with_capacity(capacity)?) } /// Returns the length of `self`. @@ -428,9 +428,9 @@ fn contains(this: &str, other: &str) -> bool { /// assert_eq!("abc123", s); /// ``` #[rune::function(instance)] -fn push(this: &mut String, c: char) -> VmResult<()> { - vm_try!(this.try_push(c)); - VmResult::Ok(()) +fn push(this: &mut String, c: char) -> Result<(), VmError> { + this.try_push(c)?; + Ok(()) } /// Appends a given string slice onto the end of this `String`. @@ -447,9 +447,9 @@ fn push(this: &mut String, c: char) -> VmResult<()> { /// assert_eq!("foobar", s); /// ``` #[rune::function(instance)] -fn push_str(this: &mut String, other: &str) -> VmResult<()> { - vm_try!(this.try_push_str(other)); - VmResult::Ok(()) +fn push_str(this: &mut String, other: &str) -> Result<(), VmError> { + this.try_push_str(other)?; + Ok(()) } /// Reserves capacity for at least `additional` bytes more than the current @@ -493,9 +493,9 @@ fn push_str(this: &mut String, other: &str) -> VmResult<()> { /// assert_eq!(capacity, s.capacity()); /// ``` #[rune::function(instance)] -fn reserve(this: &mut String, additional: usize) -> VmResult<()> { - vm_try!(this.try_reserve(additional)); - VmResult::Ok(()) +fn reserve(this: &mut String, additional: usize) -> Result<(), VmError> { + this.try_reserve(additional)?; + Ok(()) } /// Reserves the minimum capacity for at least `additional` bytes more than the @@ -541,9 +541,8 @@ fn reserve(this: &mut String, additional: usize) -> VmResult<()> { /// assert_eq!(capacity, s.capacity()); /// ``` #[rune::function(instance)] -fn reserve_exact(this: &mut String, additional: usize) -> VmResult<()> { - vm_try!(this.try_reserve_exact(additional)); - VmResult::Ok(()) +fn reserve_exact(this: &mut String, additional: usize) -> alloc::Result<()> { + this.try_reserve_exact(additional) } /// Returns a byte slice of this `String`'s contents while moving the string. @@ -635,8 +634,8 @@ fn char_at(s: &str, index: usize) -> Option { /// assert_ne!(a, c); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn clone(this: &String) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn clone(this: &String) -> alloc::Result { + this.try_clone() } /// Test two strings for partial equality. @@ -743,8 +742,8 @@ fn hash(this: &str, hasher: &mut Hasher) { /// ``` #[rune::function(keep, instance, protocol = DISPLAY_FMT)] #[inline] -fn display_fmt(this: &str, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{this}") +fn display_fmt(this: &str, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{this}") } /// Write a debug representation of a string. @@ -756,8 +755,8 @@ fn display_fmt(this: &str, f: &mut Formatter) -> VmResult<()> { /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] #[inline] -fn debug_fmt(this: &str, f: &mut Formatter) -> VmResult<()> { - rune::vm_write!(f, "{this:?}") +fn debug_fmt(this: &str, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{this:?}") } /// Shrinks the capacity of this `String` to match its length. @@ -776,9 +775,8 @@ fn debug_fmt(this: &str, f: &mut Formatter) -> VmResult<()> { /// assert_eq!(3, s.capacity()); /// ``` #[rune::function(instance)] -fn shrink_to_fit(s: &mut String) -> VmResult<()> { - vm_try!(s.try_shrink_to_fit()); - VmResult::Ok(()) +fn shrink_to_fit(s: &mut String) -> alloc::Result<()> { + s.try_shrink_to_fit() } /// An iterator over substrings of this string slice, separated by @@ -888,39 +886,34 @@ fn shrink_to_fit(s: &mut String) -> VmResult<()> { /// /// [`split_whitespace`]: str::split_whitespace #[rune::function(instance, deprecated = "Use String::split instead")] -fn split(this: Ref, value: Value) -> VmResult { +fn split(this: Ref, value: Value) -> Result { match value.as_ref() { - Repr::Inline(Inline::Char(c)) => { - VmResult::Ok(vm_try!(rune::to_value(Split::new(this, *c)))) - } - Repr::Inline(value) => VmResult::err([ + Repr::Inline(Inline::Char(c)) => Ok(rune::to_value(Split::new(this, *c))?), + Repr::Inline(value) => Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]), - Repr::Dynamic(value) => VmResult::err([ + ])), + Repr::Dynamic(value) => Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]), + ])), Repr::Any(value) => match value.type_hash() { String::HASH => { - let s = vm_try!(value.borrow_ref::()); + let s = value.borrow_ref::()?; - let split = vm_try!(rune::to_value(Split::new( - this, - vm_try!(String::try_from(s.as_str())) - ))); + let split = rune::to_value(Split::new(this, String::try_from(s.as_str())?))?; - VmResult::Ok(split) + Ok(split) } Function::HASH => { - let f = vm_try!(value.borrow_ref::()); - let split = vm_try!(rune::to_value(Split::new(this, vm_try!(f.try_clone())))); - VmResult::Ok(split) + let f = value.borrow_ref::()?; + let split = rune::to_value(Split::new(this, f.try_clone()?))?; + Ok(split) } - _ => VmResult::err([ + _ => Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]), + ])), }, } } @@ -937,33 +930,33 @@ fn split(this: Ref, value: Value) -> VmResult { /// assert_eq!("cfg=foo=bar".split_once('='), Some(("cfg", "foo=bar"))); /// ``` #[rune::function(instance)] -fn split_once(this: &str, value: Value) -> VmResult> { +fn split_once(this: &str, value: Value) -> Result, VmError> { let outcome = match value.as_ref() { Repr::Inline(Inline::Char(pat)) => this.split_once(*pat), Repr::Inline(value) => { - return VmResult::err([ + return Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]); + ])); } Repr::Dynamic(value) => { - return VmResult::err([ + return Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]); + ])); } Repr::Any(value) => match value.type_hash() { String::HASH => { - let s = vm_try!(value.borrow_ref::()); + let s = value.borrow_ref::()?; this.split_once(s.as_str()) } Function::HASH => { - let f = vm_try!(value.borrow_ref::()); + let f = value.borrow_ref::()?; let mut err = None; let outcome = this.split_once(|c: char| match f.call::((c,)) { - VmResult::Ok(b) => b, - VmResult::Err(e) => { + Ok(b) => b, + Err(e) => { if err.is_none() { err = Some(e); } @@ -973,25 +966,25 @@ fn split_once(this: &str, value: Value) -> VmResult> { }); if let Some(e) = err.take() { - return VmResult::Err(e); + return Err(e); } outcome } _ => { - return VmResult::err([ + return Err(VmError::from([ VmErrorKind::expected::(value.type_info()), VmErrorKind::bad_argument(0), - ]); + ])); } }, }; let Some((a, b)) = outcome else { - return VmResult::Ok(None); + return Ok(None); }; - VmResult::Ok(Some((vm_try!(a.try_to_owned()), vm_try!(b.try_to_owned())))) + Ok(Some((a.try_to_owned()?, b.try_to_owned()?))) } /// Returns a string slice with leading and trailing whitespace removed. @@ -1009,8 +1002,8 @@ fn split_once(this: &str, value: Value) -> VmResult> { /// assert_eq!("Hello\tworld", s.trim()); /// ``` #[rune::function(instance)] -fn trim(this: &str) -> VmResult { - VmResult::Ok(vm_try!(this.trim().try_to_owned())) +fn trim(this: &str) -> alloc::Result { + this.trim().try_to_owned() } /// Returns a string slice with trailing whitespace removed. @@ -1044,8 +1037,8 @@ fn trim(this: &str) -> VmResult { /// assert!(Some('ת') == s.trim_end().chars().rev().next()); /// ``` #[rune::function(instance)] -fn trim_end(this: &str) -> VmResult { - VmResult::Ok(vm_try!(this.trim_end().try_to_owned())) +fn trim_end(this: &str) -> alloc::Result { + this.trim_end().try_to_owned() } /// Returns `true` if `self` has a length of zero bytes. @@ -1090,8 +1083,8 @@ fn is_empty(this: &str) -> bool { /// assert_eq!(s, s.replace("cookie monster", "little lamb")); /// ``` #[rune::function(instance)] -fn replace(a: &str, from: &str, to: &str) -> VmResult { - VmResult::Ok(vm_try!(String::try_from(a.replace(from, to)))) +fn replace(this: &str, from: &str, to: &str) -> alloc::Result { + alloc::str::replace(this, from, to) } /// Returns an iterator over the [`char`]s of a string slice. @@ -1165,87 +1158,87 @@ fn chars(s: Ref) -> Chars { /// // out of bounds /// assert!(v.get(..42).is_none()); /// ``` -#[rune::function(instance)] -fn get(this: &str, key: Value) -> VmResult> { +#[rune::function(keep, instance)] +fn get(this: &str, key: Value) -> Result, VmError> { use crate::runtime::TypeOf; let slice = match key.as_any() { Some(value) => match value.type_hash() { RangeFrom::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; this.get(start..) } RangeFull::HASH => { - _ = vm_try!(value.borrow_ref::()); + _ = value.borrow_ref::()?; this.get(..) } RangeInclusive::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; + let end = range.end.as_usize()?; this.get(start..=end) } RangeToInclusive::HASH => { - let range = vm_try!(value.borrow_ref::()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let end = range.end.as_usize()?; this.get(..=end) } RangeTo::HASH => { - let range = vm_try!(value.borrow_ref::()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let end = range.end.as_usize()?; this.get(..end) } Range::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; + let end = range.end.as_usize()?; this.get(start..end) } _ => { - return VmResult::err(VmErrorKind::UnsupportedIndexGet { + return Err(VmError::from(VmErrorKind::UnsupportedIndexGet { target: String::type_info(), index: value.type_info(), - }) + })) } }, _ => { - return VmResult::err(VmErrorKind::UnsupportedIndexGet { + return Err(VmError::from(VmErrorKind::UnsupportedIndexGet { target: String::type_info(), index: key.type_info(), - }) + })) } }; let Some(slice) = slice else { - return VmResult::Ok(None); + return Ok(None); }; - VmResult::Ok(Some(vm_try!(slice.try_to_owned()))) + Ok(Some(slice.try_to_owned()?)) } /// The add operation for strings. #[rune::function(instance, protocol = ADD)] -fn add(a: &str, b: &str) -> VmResult { - let mut string = vm_try!(String::try_with_capacity(a.len() + b.len())); - vm_try!(string.try_push_str(a)); - vm_try!(string.try_push_str(b)); - VmResult::Ok(string) +fn add(a: &str, b: &str) -> Result { + let mut string = String::try_with_capacity(a.len() + b.len())?; + string.try_push_str(a)?; + string.try_push_str(b)?; + Ok(string) } /// The add assign operation for strings. #[rune::function(instance, protocol = ADD_ASSIGN)] -fn add_assign(this: &mut String, other: &str) -> VmResult<()> { - vm_try!(this.try_push_str(other)); - VmResult::Ok(()) +fn add_assign(this: &mut String, other: &str) -> Result<(), VmError> { + this.try_push_str(other)?; + Ok(()) } /// Get a specific string index. #[rune::function(instance, protocol = INDEX_GET)] -fn index_get(s: &str, key: Value) -> VmResult { - match vm_try!(__rune_fn__get(s, key)) { - Some(slice) => VmResult::Ok(slice), - None => VmResult::err(Panic::custom("missing string slice")), +fn index_get(s: &str, key: Value) -> Result { + match get(s, key)? { + Some(slice) => Ok(slice), + None => Err(VmError::panic("missing string slice")), } } @@ -1349,20 +1342,21 @@ fn parse_char(s: &str) -> Result { /// assert_eq!(new_year, new_year.to_lowercase()); /// ``` #[rune::function(instance)] -fn to_lowercase(s: &str) -> VmResult { - let mut lowercase = vm_try!(String::try_with_capacity(s.len())); +fn to_lowercase(s: &str) -> Result { + let mut lowercase = String::try_with_capacity(s.len())?; + for (i, c) in s.char_indices() { // Inlined code to from std::str to handle upper-case sigma, // since it is the only Unicode character that is context-dependent // See https://github.com/rust-lang/rust/issues/26035 for more context if c == 'Σ' { - vm_try!(lowercase.try_push_str(map_uppercase_sigma(s, i))); + lowercase.try_push_str(map_uppercase_sigma(s, i))?; } else { - vm_try!(lowercase.try_extend(c.to_lowercase())); + lowercase.try_extend(c.to_lowercase())?; } } - return VmResult::Ok(lowercase); + return Ok(lowercase); fn map_uppercase_sigma(from: &str, i: usize) -> &'static str { // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 @@ -1419,10 +1413,10 @@ fn to_lowercase(s: &str) -> VmResult { /// assert_eq!("TSCHÜSS", s.to_uppercase()); /// ``` #[rune::function(instance)] -fn to_uppercase(s: &str) -> VmResult { - let mut uppercase = vm_try!(String::try_with_capacity(s.len())); - vm_try!(uppercase.try_extend(s.chars().flat_map(|c| c.to_uppercase()))); - VmResult::Ok(uppercase) +fn to_uppercase(s: &str) -> Result { + let mut uppercase = String::try_with_capacity(s.len())?; + uppercase.try_extend(s.chars().flat_map(|c| c.to_uppercase()))?; + Ok(uppercase) } #[derive(Any)] @@ -1461,21 +1455,21 @@ impl Chars { } trait Pattern: 'static + TryClone + Named + FromValue + ToValue + MaybeTypeOf + TypeOf { - fn test(&self, tail: &str) -> VmResult<(bool, usize)>; + fn test(&self, tail: &str) -> Result<(bool, usize), VmError>; fn is_empty(&self) -> bool; } impl Pattern for String { - fn test(&self, tail: &str) -> VmResult<(bool, usize)> { + fn test(&self, tail: &str) -> Result<(bool, usize), VmError> { if tail.starts_with(self.as_str()) { - VmResult::Ok((true, self.len())) + Ok((true, self.len())) } else { let Some(c) = tail.chars().next() else { - return VmResult::Ok((false, 0)); + return Ok((false, 0)); }; - VmResult::Ok((false, c.len_utf8())) + Ok((false, c.len_utf8())) } } @@ -1486,12 +1480,12 @@ impl Pattern for String { } impl Pattern for char { - fn test(&self, tail: &str) -> VmResult<(bool, usize)> { + fn test(&self, tail: &str) -> Result<(bool, usize), VmError> { let Some(c) = tail.chars().next() else { - return VmResult::Ok((false, 0)); + return Ok((false, 0)); }; - VmResult::Ok((c == *self, c.len_utf8())) + Ok((c == *self, c.len_utf8())) } #[inline] @@ -1501,12 +1495,12 @@ impl Pattern for char { } impl Pattern for Function { - fn test(&self, tail: &str) -> VmResult<(bool, usize)> { + fn test(&self, tail: &str) -> Result<(bool, usize), VmError> { let Some(c) = tail.chars().next() else { - return VmResult::Ok((false, 0)); + return Ok((false, 0)); }; - VmResult::Ok((vm_try!(self.call::((c,))), c.len_utf8())) + Ok((self.call((c,))?, c.len_utf8())) } #[inline] @@ -1541,27 +1535,27 @@ where } #[rune::function(keep, protocol = NEXT)] - fn next(&mut self) -> VmResult> { + fn next(&mut self) -> Result, VmError> { let Some(string) = &self.string else { - return VmResult::Ok(None); + return Ok(None); }; if self.from == string.len() && self.from == self.to { self.string = None; - let out = vm_try!("".try_to_owned()); - return VmResult::Ok(Some(out)); + let out = "".try_to_owned()?; + return Ok(Some(out)); } while self.to < string.len() { let Some(tail) = string.get(self.to..) else { - return VmResult::Ok(None); + return Ok(None); }; - let (m, len) = vm_try!(self.pattern.test(tail)); + let (m, len) = self.pattern.test(tail)?; if m { let head = string.get(self.from..self.to).unwrap_or_default(); - let out = vm_try!(head.try_to_owned()); + let out = head.try_to_owned()?; if len == 0 { self.from = self.to; @@ -1571,7 +1565,7 @@ where self.from = self.to; } - return VmResult::Ok(Some(out)); + return Ok(Some(out)); } else { self.to += len; } @@ -1579,13 +1573,13 @@ where let tail = string.get(self.from..self.to).unwrap_or_default(); self.from = self.to; - let out = vm_try!(tail.try_to_owned()); + let out = tail.try_to_owned()?; if !self.pattern.is_empty() { self.string = None; } - VmResult::Ok(Some(out)) + Ok(Some(out)) } #[rune::function(keep, protocol = INTO_ITER)] diff --git a/crates/rune/src/modules/test.rs b/crates/rune/src/modules/test.rs index b4258fb75..747f9634c 100644 --- a/crates/rune/src/modules/test.rs +++ b/crates/rune/src/modules/test.rs @@ -1,18 +1,18 @@ //! Testing and benchmarking. use crate as rune; -use crate::alloc::{try_format, Vec}; +use crate::alloc::{self, try_format, Vec}; use crate::ast; use crate::compile; use crate::macros::{quote, FormatArgs, MacroContext, TokenStream}; use crate::parse::Parser; use crate::runtime::Function; -use crate::{Any, ContextError, Module, T}; +use crate::{docstring, Any, ContextError, Module, T}; /// Testing and benchmarking. #[rune::module(::std::test)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?.with_unique("std::test"); + let mut m = Module::from_meta(self::module__meta)?.with_unique("std::test"); m.macro_meta(assert)?; m.macro_meta(assert_eq)?; @@ -42,9 +42,9 @@ impl Bencher { } /// Run a benchmark using the given closure. - #[rune::function(vm_result)] - fn iter(&mut self, f: Function) { - self.fns.try_push(f).vm?; + #[rune::function] + fn iter(&mut self, f: Function) -> alloc::Result<()> { + self.fns.try_push(f) } } diff --git a/crates/rune/src/modules/tuple.rs b/crates/rune/src/modules/tuple.rs index 215a7d63f..68aa638ff 100644 --- a/crates/rune/src/modules/tuple.rs +++ b/crates/rune/src/modules/tuple.rs @@ -5,7 +5,7 @@ use core::cmp::Ordering; use crate as rune; use crate::runtime::slice::Iter; use crate::runtime::{ - EnvProtocolCaller, Formatter, Hasher, OwnedTuple, Ref, Tuple, Value, Vec, VmResult, + EnvProtocolCaller, Formatter, Hasher, OwnedTuple, Ref, Tuple, Value, Vec, VmError, }; use crate::{docstring, ContextError, Module}; @@ -43,7 +43,7 @@ use crate::{docstring, ContextError, Module}; /// ``` #[rune::module(::std::tuple)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?.docs(docstring! { /// The tuple type. })?; @@ -120,7 +120,7 @@ fn is_empty(this: &Tuple) -> bool { /// assert_eq!(None, v.get(0..4)); /// ``` #[rune::function(instance)] -fn get(this: &Tuple, index: Value) -> VmResult> { +fn get(this: &Tuple, index: Value) -> Result, VmError> { Vec::index_get(this, index) } @@ -171,7 +171,7 @@ fn into_iter(this: Ref) -> Iter { /// assert!(tuple != (2, 3, 4)); /// ``` #[rune::function(keep, instance, protocol = PARTIAL_EQ)] -fn partial_eq(this: &Tuple, other: Value) -> VmResult { +fn partial_eq(this: &Tuple, other: Value) -> Result { Vec::partial_eq_with(this, other, &mut EnvProtocolCaller) } @@ -188,7 +188,7 @@ fn partial_eq(this: &Tuple, other: Value) -> VmResult { /// assert!(!eq(tuple, (2, 3, 4))); /// ``` #[rune::function(keep, instance, protocol = EQ)] -fn eq(this: &Tuple, other: &Tuple) -> VmResult { +fn eq(this: &Tuple, other: &Tuple) -> Result { Vec::eq_with(this, other, Value::eq_with, &mut EnvProtocolCaller) } @@ -203,7 +203,7 @@ fn eq(this: &Tuple, other: &Tuple) -> VmResult { /// assert!(tuple < (2, 2, 3)); /// ``` #[rune::function(keep, instance, protocol = PARTIAL_CMP)] -fn partial_cmp(this: &Tuple, other: &Tuple) -> VmResult> { +fn partial_cmp(this: &Tuple, other: &Tuple) -> Result, VmError> { Vec::partial_cmp_with(this, other, &mut EnvProtocolCaller) } @@ -221,7 +221,7 @@ fn partial_cmp(this: &Tuple, other: &Tuple) -> VmResult> { /// assert_eq!(cmp(tuple, (2, 2, 3)), Ordering::Less); /// ``` #[rune::function(keep, instance, protocol = CMP)] -fn cmp(this: &Tuple, other: &Tuple) -> VmResult { +fn cmp(this: &Tuple, other: &Tuple) -> Result { Vec::cmp_with(this, other, &mut EnvProtocolCaller) } @@ -237,7 +237,7 @@ fn cmp(this: &Tuple, other: &Tuple) -> VmResult { /// assert_eq!(hash((0, 2, 3)), hash([0, 2, 3])); /// ``` #[rune::function(keep, instance, protocol = HASH)] -fn hash(this: &Tuple, hasher: &mut Hasher) -> VmResult<()> { +fn hash(this: &Tuple, hasher: &mut Hasher) -> Result<(), VmError> { Tuple::hash_with(this, hasher, &mut EnvProtocolCaller) } @@ -258,8 +258,8 @@ fn hash(this: &Tuple, hasher: &mut Hasher) -> VmResult<()> { /// assert_eq!(c, (1, 2, 3)); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn clone(this: &Tuple) -> VmResult { - VmResult::Ok(vm_try!(this.clone_with(&mut EnvProtocolCaller))) +fn clone(this: &Tuple) -> Result { + this.clone_with(&mut EnvProtocolCaller) } /// Write a debug representation of a tuple. @@ -272,6 +272,6 @@ fn clone(this: &Tuple) -> VmResult { /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] #[inline] -fn debug_fmt(this: &Tuple, f: &mut Formatter) -> VmResult<()> { +fn debug_fmt(this: &Tuple, f: &mut Formatter) -> Result<(), VmError> { this.debug_fmt_with(f, &mut EnvProtocolCaller) } diff --git a/crates/rune/src/modules/u64.rs b/crates/rune/src/modules/u64.rs index f44705f36..fd6ff594d 100644 --- a/crates/rune/src/modules/u64.rs +++ b/crates/rune/src/modules/u64.rs @@ -4,9 +4,7 @@ use core::cmp::Ordering; use core::num::ParseIntError; use crate as rune; -use crate::alloc; use crate::alloc::string::TryToString; -use crate::runtime::{VmErrorKind, VmResult}; use crate::{ContextError, Module}; /// Unsigned integers. @@ -14,7 +12,7 @@ use crate::{ContextError, Module}; /// This provides methods for computing over and parsing 64-bit unsigned integers. #[rune::module(::std::u64)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; unsigned!(m, u64); Ok(m) } diff --git a/crates/rune/src/modules/vec.rs b/crates/rune/src/modules/vec.rs index cf43f513a..c55075bfb 100644 --- a/crates/rune/src/modules/vec.rs +++ b/crates/rune/src/modules/vec.rs @@ -3,12 +3,13 @@ use core::cmp::Ordering; use crate as rune; +use crate::alloc; use crate::alloc::prelude::*; use crate::runtime::slice::Iter; use crate::runtime::{ - EnvProtocolCaller, Formatter, Function, Hasher, Ref, TypeOf, Value, Vec, VmErrorKind, VmResult, + EnvProtocolCaller, Formatter, Function, Hasher, Ref, TypeOf, Value, Vec, VmError, VmErrorKind, }; -use crate::{ContextError, Module}; +use crate::{docstring, ContextError, Module}; /// The [`Vec`] dynamic vector. /// @@ -43,7 +44,7 @@ use crate::{ContextError, Module}; /// ``` #[rune::module(::std::vec)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta)?; + let mut m = Module::from_meta(self::module__meta)?; m.ty::()?.docs(docstring! { /// A dynamic vector. @@ -159,8 +160,8 @@ fn vec_new() -> Vec { /// assert!(vec.capacity() >= 11); /// ``` #[rune::function(free, path = Vec::with_capacity)] -fn vec_with_capacity(capacity: usize) -> VmResult { - VmResult::Ok(vm_try!(Vec::with_capacity(capacity))) +fn vec_with_capacity(capacity: usize) -> alloc::Result { + Vec::with_capacity(capacity) } /// Returns the number of elements in the vector, also referred to as its @@ -230,7 +231,7 @@ fn capacity(vec: &Vec) -> usize { /// assert_eq!(None, v.get(0..4)); /// ``` #[rune::function(instance)] -fn get(this: &Vec, index: Value) -> VmResult> { +fn get(this: &Vec, index: Value) -> Result, VmError> { Vec::index_get(this, index) } @@ -245,12 +246,12 @@ fn get(this: &Vec, index: Value) -> VmResult> { /// values.sort_by(|a, b| cmp(b, a)) /// ``` #[rune::function(instance)] -fn sort_by(vec: &mut Vec, comparator: &Function) -> VmResult<()> { +fn sort_by(vec: &mut Vec, comparator: &Function) -> Result<(), VmError> { let mut error = None; vec.sort_by(|a, b| match comparator.call::((a, b)) { - VmResult::Ok(ordering) => ordering, - VmResult::Err(e) => { + Ok(ordering) => ordering, + Err(e) => { if error.is_none() { error = Some(e); } @@ -260,9 +261,9 @@ fn sort_by(vec: &mut Vec, comparator: &Function) -> VmResult<()> { }); if let Some(e) = error { - VmResult::Err(e) + Err(e) } else { - VmResult::Ok(()) + Ok(()) } } @@ -302,15 +303,15 @@ fn sort_by(vec: &mut Vec, comparator: &Function) -> VmResult<()> { /// assert_eq!(values, [(1, 1), (2, 1), (3, 1)]); /// ``` #[rune::function(instance)] -fn sort(vec: &mut Vec) -> VmResult<()> { +fn sort(vec: &mut Vec) -> Result<(), VmError> { let mut err = None; vec.sort_by(|a, b| { - let result: VmResult = Value::cmp(a, b); + let result: Result = Value::cmp(a, b); match result { - VmResult::Ok(cmp) => cmp, - VmResult::Err(e) => { + Ok(cmp) => cmp, + Err(e) => { if err.is_none() { err = Some(e); } @@ -322,10 +323,10 @@ fn sort(vec: &mut Vec) -> VmResult<()> { }); if let Some(err) = err { - return VmResult::Err(err); + return Err(err); } - VmResult::Ok(()) + Ok(()) } /// Clears the vector, removing all values. @@ -356,7 +357,7 @@ fn clear(vec: &mut Vec) { /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7, 8]); /// ``` #[rune::function(instance)] -fn extend(this: &mut Vec, value: Value) -> VmResult<()> { +fn extend(this: &mut Vec, value: Value) -> Result<(), VmError> { this.extend(value) } @@ -394,9 +395,9 @@ fn pop(this: &mut Vec) -> Option { /// assert_eq!(vec, [1, 2, 3]); /// ``` #[rune::function(instance)] -fn push(this: &mut Vec, value: Value) -> VmResult<()> { - vm_try!(this.push(value)); - VmResult::Ok(()) +fn push(this: &mut Vec, value: Value) -> Result<(), VmError> { + this.push(value)?; + Ok(()) } /// Removes and returns the element at position `index` within the vector, @@ -428,16 +429,16 @@ fn push(this: &mut Vec, value: Value) -> VmResult<()> { /// assert_eq!(v, [1, 3]); /// ``` #[rune::function(instance)] -fn remove(this: &mut Vec, index: usize) -> VmResult { +fn remove(this: &mut Vec, index: usize) -> Result { if index >= this.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: this.len().into(), - }); + })); } let value = this.remove(index); - VmResult::Ok(value) + Ok(value) } /// Inserts an element at position `index` within the vector, shifting all @@ -457,16 +458,16 @@ fn remove(this: &mut Vec, index: usize) -> VmResult { /// assert_eq!(vec, [1, 4, 2, 3, 5]); /// ``` #[rune::function(instance)] -fn insert(this: &mut Vec, index: usize, value: Value) -> VmResult<()> { +fn insert(this: &mut Vec, index: usize, value: Value) -> Result<(), VmError> { if index > this.len() { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: this.len().into(), - }); + })); } - vm_try!(this.insert(index, value)); - VmResult::Ok(()) + this.insert(index, value)?; + Ok(()) } /// Clone the vector. @@ -483,8 +484,8 @@ fn insert(this: &mut Vec, index: usize, value: Value) -> VmResult<()> { /// assert_eq!(b, [1, 2, 3, 4]); /// ``` #[rune::function(keep, instance, protocol = CLONE)] -fn clone(this: &Vec) -> VmResult { - VmResult::Ok(vm_try!(this.try_clone())) +fn clone(this: &Vec) -> alloc::Result { + this.try_clone() } /// Construct an iterator over the tuple. @@ -536,14 +537,14 @@ fn into_iter(this: Ref) -> Iter { /// assert_eq!([10, 40], v[0..2]); /// ``` #[rune::function(instance, protocol = INDEX_GET)] -fn index_get(this: &Vec, index: Value) -> VmResult { - let Some(value) = vm_try!(Vec::index_get(this, index)) else { - return VmResult::err(VmErrorKind::MissingIndex { +fn index_get(this: &Vec, index: Value) -> Result { + let Some(value) = Vec::index_get(this, index)? else { + return Err(VmError::new(VmErrorKind::MissingIndex { target: Vec::type_info(), - }); + })); }; - VmResult::Ok(value) + Ok(value) } /// Inserts a value into the vector. @@ -556,7 +557,7 @@ fn index_get(this: &Vec, index: Value) -> VmResult { /// assert_eq!(vec, ["a", 2, 3]); /// ``` #[rune::function(instance, protocol = INDEX_SET)] -fn index_set(this: &mut Vec, index: usize, value: Value) -> VmResult<()> { +fn index_set(this: &mut Vec, index: usize, value: Value) -> Result<(), VmError> { Vec::set(this, index, value) } @@ -597,7 +598,7 @@ fn index_set(this: &mut Vec, index: usize, value: Value) -> VmResult<()> { /// assert_eq!(vec, [2, [1, 4], [1]]); /// ``` #[rune::function(instance)] -fn resize(this: &mut Vec, new_len: usize, value: Value) -> VmResult<()> { +fn resize(this: &mut Vec, new_len: usize, value: Value) -> Result<(), VmError> { Vec::resize(this, new_len, value) } @@ -613,7 +614,7 @@ fn resize(this: &mut Vec, new_len: usize, value: Value) -> VmResult<()> { /// assert_eq!(format!("{:?}", vec), "[1, 2, 3]"); /// ``` #[rune::function(keep, instance, protocol = DEBUG_FMT)] -fn debug_fmt(this: &Vec, f: &mut Formatter) -> VmResult<()> { +fn debug_fmt(this: &Vec, f: &mut Formatter) -> Result<(), VmError> { Vec::debug_fmt_with(this, f, &mut EnvProtocolCaller) } @@ -632,7 +633,7 @@ fn debug_fmt(this: &Vec, f: &mut Formatter) -> VmResult<()> { /// assert!(vec != [2, 3, 4]); /// ``` #[rune::function(keep, instance, protocol = PARTIAL_EQ)] -fn partial_eq(this: &Vec, other: Value) -> VmResult { +fn partial_eq(this: &Vec, other: Value) -> Result { Vec::partial_eq_with(this, other, &mut EnvProtocolCaller) } @@ -649,7 +650,7 @@ fn partial_eq(this: &Vec, other: Value) -> VmResult { /// assert!(!eq(vec, [2, 3, 4])); /// ``` #[rune::function(keep, instance, protocol = EQ)] -fn eq(this: &Vec, other: &Vec) -> VmResult { +fn eq(this: &Vec, other: &Vec) -> Result { Vec::eq_with(this, other, Value::eq_with, &mut EnvProtocolCaller) } @@ -664,7 +665,7 @@ fn eq(this: &Vec, other: &Vec) -> VmResult { /// assert!(vec < [2, 2, 3]); /// ``` #[rune::function(keep, instance, protocol = PARTIAL_CMP)] -fn partial_cmp(this: &Vec, other: &Vec) -> VmResult> { +fn partial_cmp(this: &Vec, other: &Vec) -> Result, VmError> { Vec::partial_cmp_with(this, other, &mut EnvProtocolCaller) } @@ -682,7 +683,7 @@ fn partial_cmp(this: &Vec, other: &Vec) -> VmResult> { /// assert_eq!(cmp(vec, [2, 2, 3]), Ordering::Less); /// ``` #[rune::function(keep, instance, protocol = CMP)] -fn cmp(this: &Vec, other: &Vec) -> VmResult { +fn cmp(this: &Vec, other: &Vec) -> Result { Vec::cmp_with(this, other, &mut EnvProtocolCaller) } @@ -696,6 +697,6 @@ fn cmp(this: &Vec, other: &Vec) -> VmResult { /// assert_eq!(hash([0, 2, 3]), hash([0, 2, 3])); /// ``` #[rune::function(instance, protocol = HASH)] -fn hash(this: &Vec, hasher: &mut Hasher) -> VmResult<()> { +fn hash(this: &Vec, hasher: &mut Hasher) -> Result<(), VmError> { Vec::hash_with(this, hasher, &mut EnvProtocolCaller) } diff --git a/crates/rune/src/musli.rs b/crates/rune/src/musli.rs index 3b5b1a80e..d5beeaa1b 100644 --- a/crates/rune/src/musli.rs +++ b/crates/rune/src/musli.rs @@ -3,21 +3,23 @@ pub(crate) mod ordering { use musli::{Context, Decoder, Encoder}; - pub(crate) fn encode(ordering: &Ordering, _: &E::Cx, encoder: E) -> Result + pub(crate) fn encode(value: &Ordering, encoder: E) -> Result<(), E::Error> where E: Encoder, { - match ordering { + match value { Ordering::Less => encoder.encode_i8(-1), Ordering::Equal => encoder.encode_i8(0), Ordering::Greater => encoder.encode_i8(1), } } - pub(crate) fn decode<'de, D>(cx: &D::Cx, decoder: D) -> Result + pub(crate) fn decode<'de, D>(decoder: D) -> Result where D: Decoder<'de>, { + let cx = decoder.cx(); + match decoder.decode_i8()? { -1 => Ok(Ordering::Less), 0 => Ok(Ordering::Equal), diff --git a/crates/rune/src/parse/lexer.rs b/crates/rune/src/parse/lexer.rs index f324a68a7..bcdbe080b 100644 --- a/crates/rune/src/parse/lexer.rs +++ b/crates/rune/src/parse/lexer.rs @@ -591,7 +591,6 @@ impl<'a> Lexer<'a> { } /// Consume the next token from the lexer. - #[allow(clippy::should_implement_trait)] pub(crate) fn next(&mut self) -> compile::Result> { 'outer: loop { if let Some(token) = self.buffer.pop_front() { diff --git a/crates/rune/src/parse/parser.rs b/crates/rune/src/parse/parser.rs index b843a29df..9575a7194 100644 --- a/crates/rune/src/parse/parser.rs +++ b/crates/rune/src/parse/parser.rs @@ -163,7 +163,6 @@ impl<'a> Parser<'a> { } /// Consume the next token from the parser. - #[allow(clippy::should_implement_trait)] pub(crate) fn next(&mut self) -> compile::Result { if let Some(error) = self.peeker.error.take() { return Err(error); diff --git a/crates/rune/src/query/query.rs b/crates/rune/src/query/query.rs index 61951e085..59a07f4a1 100644 --- a/crates/rune/src/query/query.rs +++ b/crates/rune/src/query/query.rs @@ -2,8 +2,8 @@ use core::mem::take; use core::ops::{Deref, DerefMut}; -use ::rust_alloc::rc::Rc; -use ::rust_alloc::sync::Arc; +use rust_alloc::rc::Rc; +use rust_alloc::sync::Arc; use crate::alloc::borrow::Cow; use crate::alloc::prelude::*; @@ -624,36 +624,43 @@ impl<'a, 'arena> Query<'a, 'arena> { } /// Get the item for the given identifier. - pub(crate) fn item_for(&self, what: &'static str, id: ItemId) -> anyhow::Result { + pub(crate) fn item_for( + &self, + what: &'static str, + id: ItemId, + ) -> Result { let Some(item_meta) = self.inner.items.get(&id) else { let m = try_format!( "missing item meta for `{what}` at {} with id {id}", self.pool.item(id) ); - return Err(anyhow::Error::msg(m)); + return Err(compile::ErrorKind::msg(m)); }; Ok(*item_meta) } /// Get the built-in macro matching the given ast. - pub(crate) fn builtin_macro_for(&self, id: NonZeroId) -> anyhow::Result> { + pub(crate) fn builtin_macro_for( + &self, + id: NonZeroId, + ) -> Result, compile::ErrorKind> { let Some(internal_macro) = self.inner.internal_macros.get(&id) else { let m = try_format!("missing built-in macro for id {id}"); - return Err(anyhow::Error::msg(m)); + return Err(compile::ErrorKind::msg(m)); }; Ok(internal_macro.clone()) } /// Get the constant function associated with the opaque. - pub(crate) fn const_fn_for(&self, id: ItemId) -> anyhow::Result>> { + pub(crate) fn const_fn_for(&self, id: ItemId) -> Result>, compile::ErrorKind> { let Some(const_fn) = self.inner.const_fns.get(&id) else { let m = try_format!( "missing constant function {} for id {id}", self.pool.item(id) ); - return Err(anyhow::Error::msg(m)); + return Err(compile::ErrorKind::msg(m)); }; Ok(const_fn.clone()) diff --git a/crates/rune/src/runtime/access.rs b/crates/rune/src/runtime/access.rs index 9f67363ee..07dd30398 100644 --- a/crates/rune/src/runtime/access.rs +++ b/crates/rune/src/runtime/access.rs @@ -3,8 +3,6 @@ use core::fmt; use core::mem::ManuallyDrop; use core::ptr::NonNull; -use super::TypeInfo; - /// Test if exclusively held. const EXCLUSIVE: usize = 1usize.rotate_right(2); /// Sentinel value to indicate that access is taken. @@ -27,13 +25,6 @@ pub struct AccessError { } impl AccessError { - #[inline] - pub(crate) const fn not_owned(type_info: TypeInfo) -> Self { - Self { - kind: AccessErrorKind::NotAccessibleOwned(type_info), - } - } - #[inline] pub(crate) const fn new(kind: AccessErrorKind) -> Self { Self { kind } @@ -41,14 +32,21 @@ impl AccessError { } impl fmt::Display for AccessError { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.kind { - AccessErrorKind::NotAccessibleRef(s) => write!(f, "Cannot read, value is {s}"), - AccessErrorKind::NotAccessibleMut(s) => write!(f, "Cannot write, value is {s}"), - AccessErrorKind::NotAccessibleTake(s) => write!(f, "Cannot take, value is {s}"), - AccessErrorKind::NotAccessibleOwned(type_info) => { - write!(f, "Cannot use owned operations for {type_info}") - } + AccessErrorKind::NotAccessibleRef(s) => write!( + f, + "Cannot read, value has snapshot {s} and is not available for reading" + ), + AccessErrorKind::NotAccessibleMut(s) => write!( + f, + "Cannot write, value has snapshot {s} and is not available for writing" + ), + AccessErrorKind::NotAccessibleTake(s) => write!( + f, + "Cannot take, value has snapshot {s} and is not available for taking" + ), } } } @@ -68,7 +66,6 @@ pub(crate) enum AccessErrorKind { NotAccessibleRef(Snapshot), NotAccessibleMut(Snapshot), NotAccessibleTake(Snapshot), - NotAccessibleOwned(TypeInfo), } /// Snapshot that can be used to indicate how the value was being accessed at diff --git a/crates/rune/src/runtime/any_obj.rs b/crates/rune/src/runtime/any_obj.rs index adf33fd31..19bc86d50 100644 --- a/crates/rune/src/runtime/any_obj.rs +++ b/crates/rune/src/runtime/any_obj.rs @@ -1,140 +1,60 @@ -use core::any::TypeId; use core::cell::Cell; use core::fmt; -use core::mem::{needs_drop, offset_of, replace, ManuallyDrop}; -use core::ptr::{self, addr_of, addr_of_mut, drop_in_place, NonNull}; +use core::mem::{replace, ManuallyDrop}; +use core::ptr::{self, addr_of, NonNull}; -use crate::alloc::alloc::Global; +use crate::alloc::clone::TryClone; use crate::alloc::{self, Box}; use crate::{Any, Hash}; use super::{ - Access, AccessError, AnyTypeInfo, BorrowMut, BorrowRef, Mut, RawAccessGuard, RawAnyGuard, Ref, - RefVtable, Snapshot, TypeInfo, VmErrorKind, + Access, AccessError, AnyObjVtable, AnyTypeInfo, BorrowMut, BorrowRef, FromValue, Mut, + RawAccessGuard, RawAnyGuard, Ref, RefVtable, RuntimeError, Shared, Snapshot, ToValue, TypeInfo, + Value, }; -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub(super) enum AnyObjErrorKind { - Cast(AnyTypeInfo, TypeInfo), - AccessError(AccessError), -} - -/// Errors caused when accessing or coercing an [`AnyObj`]. -#[cfg_attr(test, derive(PartialEq))] -pub struct AnyObjError { - kind: AnyObjErrorKind, -} - -impl AnyObjError { - fn new(kind: AnyObjErrorKind) -> Self { - Self { kind } - } - - #[inline] - pub(super) fn into_kind(self) -> AnyObjErrorKind { - self.kind - } -} - -impl core::error::Error for AnyObjError {} - -impl fmt::Display for AnyObjError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.kind { - AnyObjErrorKind::Cast(expected, actual) => { - write!(f, "Failed to cast `{actual}` to `{expected}`") - } - AnyObjErrorKind::AccessError(error) => error.fmt(f), - } - } -} - -impl fmt::Debug for AnyObjError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.kind.fmt(f) - } +/// A type-erased wrapper for a reference. +pub struct AnyObj { + shared: NonNull, } -impl From for AnyObjError { +impl AnyObj { + /// Construct a new typed object. + /// + /// # Safety + /// + /// Caller must ensure that the type is of the value `T`. #[inline] - fn from(error: AccessError) -> Self { - Self::new(AnyObjErrorKind::AccessError(error)) + pub(super) const unsafe fn from_raw(shared: NonNull) -> Self { + Self { shared } } -} -/// Guard which decrements and releases shared storage for the guarded reference. -struct AnyObjDecShared { - shared: NonNull, -} - -impl Drop for AnyObjDecShared { - fn drop(&mut self) { - // Safety: We know that the inner value is live in this instance. - unsafe { - Shared::dec(self.shared); - } - } -} - -/// Guard which decrements and releases shared storage for the guarded reference. -pub(crate) struct AnyObjDrop { - #[allow(unused)] - shared: NonNull, -} - -impl Drop for AnyObjDrop { - fn drop(&mut self) { - // Safety: We know that the inner value is live in this instance. - unsafe { - self.shared.as_ref().access.take(); - - Shared::dec(self.shared); - } - } -} - -pub(crate) struct RawAnyObjGuard { - #[allow(unused)] - guard: RawAccessGuard, - #[allow(unused)] - dec_shared: AnyObjDecShared, -} - -/// A type-erased wrapper for a reference, whether it is mutable or not. -pub struct AnyObj { - shared: NonNull, -} - -impl AnyObj { /// Construct an Any that wraps an owned object. - pub(crate) fn new(data: T) -> alloc::Result + /// + /// # Examples + /// + /// ``` + /// use rune::Value; + /// use rune::runtime::AnyObj; + /// use rune::alloc::String; + /// + /// let string = String::try_from("Hello World")?; + /// let string = AnyObj::new(string)?; + /// let string = Value::from(string); + /// + /// let string = string.into_shared::()?; + /// assert_eq!(string.borrow_ref()?.as_str(), "Hello World"); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + #[inline] + pub fn new(data: T) -> alloc::Result where T: Any, { - let vtable = &Vtable { - kind: Kind::Own, - type_id: TypeId::of::, - debug: debug_ref_impl::, - type_info: T::ANY_TYPE_INFO, - type_hash: T::HASH, - drop_value: const { - if needs_drop::() { - Some(drop_value::) - } else { - None - } - }, - drop: drop_box::>, - clone: clone_own::, - }; - - let shared = Shared { + let shared = AnyObjData { access: Access::new(), count: Cell::new(1), - vtable, + vtable: AnyObjVtable::owned::(), data, }; @@ -148,25 +68,15 @@ impl AnyObj { /// /// Caller must ensure that the returned `AnyObj` doesn't outlive the /// reference it is wrapping. + #[inline] pub(crate) unsafe fn from_ref(data: *const T) -> alloc::Result where T: Any, { - let vtable = &Vtable { - kind: Kind::Ref, - type_id: TypeId::of::, - debug: debug_ref_impl::, - type_info: T::ANY_TYPE_INFO, - type_hash: T::HASH, - drop_value: None, - drop: drop_box::>, - clone: clone_ref::, - }; - - let shared = Shared { + let shared = AnyObjData { access: Access::new(), count: Cell::new(1), - vtable, + vtable: AnyObjVtable::from_ref::(), data: NonNull::new_unchecked(data.cast_mut()), }; @@ -180,25 +90,15 @@ impl AnyObj { /// /// Caller must ensure that the returned `AnyObj` doesn't outlive the /// reference it is wrapping. + #[inline] pub(crate) unsafe fn from_mut(data: *mut T) -> alloc::Result where T: Any, { - let vtable = &Vtable { - kind: Kind::Mut, - type_id: TypeId::of::, - debug: debug_mut_impl::, - type_info: T::ANY_TYPE_INFO, - type_hash: T::HASH, - drop_value: None, - drop: drop_box::>, - clone: clone_mut::, - }; - - let shared = Shared { + let shared = AnyObjData { access: Access::new(), count: Cell::new(1), - vtable, + vtable: AnyObjVtable::from_mut::(), data: NonNull::new_unchecked(data), }; @@ -206,6 +106,38 @@ impl AnyObj { Ok(Self { shared }) } + /// Coerce into a typed object. + pub(crate) fn into_shared(self) -> Result, AnyObjError> + where + T: Any, + { + let vtable = vtable(&self); + + if !vtable.is::() { + return Err(AnyObjError::new(AnyObjErrorKind::Cast( + T::ANY_TYPE_INFO, + vtable.type_info(), + ))); + } + + // SAFETY: We've typed checked for the appropriate type just above. + unsafe { Ok(self.unsafe_into_shared()) } + } + + /// Coerce into a typed object. + /// + /// # Safety + /// + /// The caller must ensure that the type being convert into is correct. + #[inline] + pub(crate) unsafe fn unsafe_into_shared(self) -> Shared + where + T: Any, + { + let this = ManuallyDrop::new(self); + Shared::from_raw(this.shared.cast()) + } + /// Downcast into an owned value of type `T`. pub(crate) fn downcast(self) -> Result where @@ -213,15 +145,15 @@ impl AnyObj { { let vtable = vtable(&self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), ))); } - if !matches!(vtable.kind, Kind::Own) { - return Err(AnyObjError::from(AccessError::not_owned( + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( vtable.type_info(), ))); } @@ -235,11 +167,13 @@ impl AnyObj { } /// Take the interior value and drop it if necessary. - pub(crate) fn drop(self) -> Result<(), AccessError> { + pub(crate) fn drop(self) -> Result<(), AnyObjError> { let vtable = vtable(&self); - if !matches!(vtable.kind, Kind::Own) { - return Err(AccessError::not_owned(vtable.type_info())); + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( + vtable.type_info(), + ))); } // SAFETY: We've checked for the appropriate type just above. @@ -255,15 +189,9 @@ impl AnyObj { } /// Take the interior value and return a handle to the taken value. - pub(crate) fn take(self) -> Result { + pub fn take(self) -> Result { let vtable = vtable(&self); - if !matches!(vtable.kind, Kind::Own) { - return Err(VmErrorKind::from(AccessError::not_owned( - vtable.type_info(), - ))); - } - // SAFETY: We've checked for the appropriate type just above. unsafe { self.shared.as_ref().access.try_take()?; @@ -283,15 +211,15 @@ impl AnyObj { { let vtable = vtable(&self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), ))); } - if !matches!(vtable.kind, Kind::Own) { - return Err(AnyObjError::from(AccessError::not_owned( + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( vtable.type_info(), ))); } @@ -304,9 +232,9 @@ impl AnyObj { let vtable = &RefVtable { drop: |shared: NonNull<()>| { - let shared = shared.cast::(); + let shared = shared.cast::(); shared.as_ref().access.release(); - Shared::dec(shared) + AnyObjData::dec(shared) }, }; @@ -327,15 +255,15 @@ impl AnyObj { { let vtable = vtable(&self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), ))); } - if !matches!(vtable.kind, Kind::Own) { - return Err(AnyObjError::from(AccessError::not_owned( + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( vtable.type_info(), ))); } @@ -348,9 +276,9 @@ impl AnyObj { let vtable = &RefVtable { drop: |shared: NonNull<()>| { - let shared = shared.cast::(); + let shared = shared.cast::(); shared.as_ref().access.release(); - Shared::dec(shared) + AnyObjData::dec(shared) }, }; @@ -369,7 +297,7 @@ impl AnyObj { { let vtable = vtable(self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), @@ -397,7 +325,7 @@ impl AnyObj { { let vtable = vtable(self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Ok(None); } @@ -422,7 +350,7 @@ impl AnyObj { { let vtable = vtable(self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Ok(None); } @@ -441,14 +369,7 @@ impl AnyObj { { let vtable = vtable(self); - if (vtable.type_id)() != TypeId::of::() { - return Err(AnyObjError::new(AnyObjErrorKind::Cast( - T::ANY_TYPE_INFO, - vtable.type_info(), - ))); - } - - if matches!(vtable.kind, Kind::Ref) { + if !vtable.is::() || !vtable.is_mutable() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), @@ -473,7 +394,7 @@ impl AnyObj { { let vtable = vtable(&self); - if (vtable.type_id)() != TypeId::of::() { + if !vtable.is::() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), @@ -505,14 +426,7 @@ impl AnyObj { { let vtable = vtable(&self); - if (vtable.type_id)() != TypeId::of::() { - return Err(AnyObjError::new(AnyObjErrorKind::Cast( - T::ANY_TYPE_INFO, - vtable.type_info(), - ))); - } - - if matches!(vtable.kind, Kind::Ref) { + if !vtable.is::() || !vtable.is_mutable() { return Err(AnyObjError::new(AnyObjErrorKind::Cast( T::ANY_TYPE_INFO, vtable.type_info(), @@ -547,7 +461,7 @@ impl AnyObj { pub(crate) unsafe fn into_drop_guard(self) -> (Self, AnyObjDrop) { // Increment the reference count by one to account for the guard holding // onto it. - Shared::inc(self.shared); + AnyObjData::inc(self.shared); let guard = AnyObjDrop { shared: self.shared, @@ -567,7 +481,7 @@ impl AnyObj { pub(crate) fn is_writable(&self) -> bool { unsafe { let shared = self.shared.as_ref(); - !matches!(shared.vtable.kind, Kind::Ref) && shared.access.is_exclusive() + shared.vtable.is_mutable() && shared.access.is_exclusive() } } @@ -578,17 +492,17 @@ impl AnyObj { /// Debug format the current any type. pub(crate) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (vtable(self).debug)(f) + vtable(self).debug(f) } - /// Access the underlying type id for the data. - pub(crate) fn type_hash(&self) -> Hash { - vtable(self).type_hash + /// Access the underlying type hash for the data. + pub fn type_hash(&self) -> Hash { + vtable(self).type_hash() } - /// Access full type info for type. - pub(crate) fn type_info(&self) -> TypeInfo { - TypeInfo::any_type_info(vtable(self).type_info) + /// Access full type info for the underlying type. + pub fn type_info(&self) -> TypeInfo { + vtable(self).type_info() } } @@ -597,7 +511,7 @@ impl Clone for AnyObj { fn clone(&self) -> Self { // SAFETY: We know that the inner value is live in this instance. unsafe { - Shared::inc(self.shared); + AnyObjData::inc(self.shared); } Self { @@ -615,12 +529,25 @@ impl Clone for AnyObj { // SAFETY: We know that the inner value is live in both instances. unsafe { - Shared::dec(old); - Shared::inc(self.shared); + AnyObjData::dec(old); + AnyObjData::inc(self.shared); } } } +impl TryClone for AnyObj { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(self.clone()) + } + + #[inline] + fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> { + self.clone_from(source); + Ok(()) + } +} + impl fmt::Debug for AnyObj { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.debug(f) @@ -631,82 +558,41 @@ impl Drop for AnyObj { fn drop(&mut self) { // Safety: We know that the inner value is live in this instance. unsafe { - Shared::dec(self.shared); + AnyObjData::dec(self.shared); } } } -/// The signature of a pointer coercion function. -type TypeIdFn = fn() -> TypeId; - -/// The signature of a descriptive type name function. -type DebugFn = fn(&mut fmt::Formatter<'_>) -> fmt::Result; - -/// The kind of the stored value in the `AnyObj`. -enum Kind { - /// Underlying access is shared. - Ref, - /// Underlying access is exclusive. - Mut, - /// Underlying access is owned. - Own, -} - -struct Vtable { - /// The statically known kind of reference being stored. - kind: Kind, - /// Punt the inner pointer to the type corresponding to the type hash. - type_id: TypeIdFn, - /// Type information for diagnostics. - debug: DebugFn, - /// Type information. - type_info: AnyTypeInfo, - /// Type hash of the interior type. - type_hash: Hash, - /// Value drop implementation. Set to `None` if the underlying value does - /// not need to be dropped. - drop_value: Option)>, - /// Only drop the box implementation. - drop: unsafe fn(NonNull), - /// Clone the literal content of the shared value. - clone: unsafe fn(NonNull) -> alloc::Result, +impl FromValue for AnyObj { + #[inline] + fn from_value(value: Value) -> Result { + value.into_any_obj() + } } -impl Vtable { +impl ToValue for AnyObj { #[inline] - fn type_info(&self) -> TypeInfo { - TypeInfo::any_type_info(self.type_info) - } - - fn as_ptr(&self, base: NonNull) -> NonNull { - if matches!(self.kind, Kind::Own) { - unsafe { base.byte_add(offset_of!(Shared, data)).cast() } - } else { - unsafe { - base.byte_add(offset_of!(Shared>, data)) - .cast() - .read() - } - } + fn to_value(self) -> Result { + Ok(Value::from(self)) } } #[repr(C)] -struct Shared { +pub(super) struct AnyObjData { /// The currently handed out access to the shared data. - access: Access, + pub(super) access: Access, /// The number of strong references to the shared data. - count: Cell, + pub(super) count: Cell, /// Vtable of the shared value. - vtable: &'static Vtable, + pub(super) vtable: &'static AnyObjVtable, /// Data of the shared reference. - data: T, + pub(super) data: T, } -impl Shared { +impl AnyObjData { /// Increment the reference count of the inner value. #[inline] - unsafe fn inc(this: NonNull) { + pub(super) unsafe fn inc(this: NonNull) { let count_ref = &*addr_of!((*this.as_ptr()).count); let count = count_ref.get(); @@ -729,7 +615,7 @@ impl Shared { /// /// ProtocolCaller needs to ensure that `this` is a valid pointer. #[inline] - unsafe fn dec(this: NonNull) { + pub(super) unsafe fn dec(this: NonNull) { let count_ref = &*addr_of!((*this.as_ptr()).count); let count = count_ref.get(); @@ -757,56 +643,112 @@ impl Shared { } } -fn debug_ref_impl(f: &mut fmt::Formatter<'_>) -> fmt::Result -where - T: ?Sized + Any, -{ - write!(f, "&{}", T::ITEM) +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub(super) enum AnyObjErrorKind { + Alloc(alloc::Error), + Cast(AnyTypeInfo, TypeInfo), + AccessError(AccessError), + NotOwned(TypeInfo), +} + +/// Errors caused when accessing or coercing an [`AnyObj`]. +#[cfg_attr(test, derive(PartialEq))] +pub struct AnyObjError { + kind: AnyObjErrorKind, +} + +impl AnyObjError { + #[inline] + pub(super) fn new(kind: AnyObjErrorKind) -> Self { + Self { kind } + } + + #[inline] + pub(super) fn into_kind(self) -> AnyObjErrorKind { + self.kind + } +} + +impl core::error::Error for AnyObjError {} + +impl fmt::Display for AnyObjError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.kind { + AnyObjErrorKind::Alloc(error) => error.fmt(f), + AnyObjErrorKind::Cast(expected, actual) => { + write!(f, "Failed to cast `{actual}` to `{expected}`") + } + AnyObjErrorKind::AccessError(error) => error.fmt(f), + AnyObjErrorKind::NotOwned(type_info) => { + write!(f, "Cannot use owned operations for {type_info}") + } + } + } +} + +impl fmt::Debug for AnyObjError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.kind.fmt(f) + } } -fn debug_mut_impl(f: &mut fmt::Formatter<'_>) -> fmt::Result -where - T: ?Sized + Any, -{ - write!(f, "&mut {}", T::ITEM) +impl From for AnyObjError { + #[inline] + fn from(error: alloc::Error) -> Self { + Self::new(AnyObjErrorKind::Alloc(error)) + } } -unsafe fn drop_value(this: NonNull) { - let data = addr_of_mut!((*this.cast::>().as_ptr()).data); - drop_in_place(data); +impl From for AnyObjError { + #[inline] + fn from(error: AccessError) -> Self { + Self::new(AnyObjErrorKind::AccessError(error)) + } +} + +/// Guard which decrements and releases shared storage for the guarded reference. +pub(super) struct AnyObjDecShared { + pub(super) shared: NonNull, } -unsafe fn drop_box(this: NonNull) { - drop(Box::from_raw_in(this.cast::>().as_ptr(), Global)) +impl Drop for AnyObjDecShared { + fn drop(&mut self) { + // Safety: We know that the inner value is live in this instance. + unsafe { + AnyObjData::dec(self.shared); + } + } } -unsafe fn clone_own(this: NonNull) -> alloc::Result -where - T: Any, -{ - // NB: We read the value without deallocating it from the previous location, - // since that would cause the returned value to be invalid. - let value = addr_of_mut!((*this.cast::>().as_ptr()).data).read(); - AnyObj::new(value) +/// Guard which decrements and releases shared storage for the guarded reference. +pub(crate) struct AnyObjDrop { + #[allow(unused)] + pub(super) shared: NonNull, } -unsafe fn clone_ref(this: NonNull) -> alloc::Result -where - T: Any, -{ - let value = addr_of_mut!((*this.cast::>>().as_ptr()).data).read(); - AnyObj::from_ref(value.as_ptr().cast_const()) +impl Drop for AnyObjDrop { + #[inline] + fn drop(&mut self) { + // Safety: We know that the inner value is live in this instance. + unsafe { + self.shared.as_ref().access.take(); + AnyObjData::dec(self.shared); + } + } } -unsafe fn clone_mut(this: NonNull) -> alloc::Result -where - T: Any, -{ - let value = addr_of_mut!((*this.cast::>>().as_ptr()).data).read(); - AnyObj::from_mut(value.as_ptr()) +/// The guard returned when dealing with raw pointers. +pub(crate) struct RawAnyObjGuard { + #[allow(unused)] + pub(super) guard: RawAccessGuard, + #[allow(unused)] + pub(super) dec_shared: AnyObjDecShared, } #[inline] -fn vtable(any: &AnyObj) -> &'static Vtable { +fn vtable(any: &AnyObj) -> &'static AnyObjVtable { unsafe { addr_of!((*any.shared.as_ptr()).vtable).read() } } diff --git a/crates/rune/src/runtime/any_obj_vtable.rs b/crates/rune/src/runtime/any_obj_vtable.rs new file mode 100644 index 000000000..5471a95a7 --- /dev/null +++ b/crates/rune/src/runtime/any_obj_vtable.rs @@ -0,0 +1,201 @@ +use core::any::TypeId; +use core::fmt; +use core::mem::{needs_drop, offset_of, ManuallyDrop}; +use core::ptr::{addr_of_mut, drop_in_place, NonNull}; + +use crate::alloc::alloc::Global; +use crate::alloc::{self, Box}; +use crate::{Any, Hash}; + +use super::{AnyObj, AnyObjData, AnyTypeInfo, TypeInfo}; + +/// The signature of a pointer coercion function. +type TypeIdFn = fn() -> TypeId; + +/// The signature of a descriptive type name function. +type DebugFn = fn(&mut fmt::Formatter<'_>) -> fmt::Result; + +/// The kind of the stored value in the `AnyObj`. +enum Kind { + /// Underlying access is shared. + Shared, + /// Underlying access is exclusively accessible. + Exclusive, + /// The underlying type is owned. + Owned, +} + +pub(super) struct AnyObjVtable { + /// The statically known kind of reference being stored. + kind: Kind, + /// Punt the inner pointer to the type corresponding to the type hash. + type_id: TypeIdFn, + /// Static type information. + type_info: AnyTypeInfo, + /// Type hash of the interior type. + type_hash: Hash, + /// Type information for diagnostics. + debug: DebugFn, + /// Value drop implementation. Set to `None` if the underlying value does + /// not need to be dropped. + pub(super) drop_value: Option)>, + /// Only drop the box implementation. + pub(super) drop: unsafe fn(NonNull), + /// Clone the literal content of the shared value. + pub(super) clone: unsafe fn(NonNull) -> alloc::Result, +} + +impl AnyObjVtable { + #[inline] + pub(super) const fn owned() -> &'static Self + where + T: Any, + { + &Self { + kind: Kind::Owned, + type_id: TypeId::of::, + debug: debug_ref_impl::, + type_info: T::ANY_TYPE_INFO, + type_hash: T::HASH, + drop_value: const { + if needs_drop::() { + Some(drop_value::) + } else { + None + } + }, + drop: drop_box::>, + clone: clone_own::, + } + } + + #[inline] + pub(super) const fn from_ref() -> &'static Self + where + T: Any, + { + &Self { + kind: Kind::Shared, + type_id: TypeId::of::, + debug: debug_ref_impl::, + type_info: T::ANY_TYPE_INFO, + type_hash: T::HASH, + drop_value: None, + drop: drop_box::>, + clone: clone_ref::, + } + } + + #[inline] + pub(super) const fn from_mut() -> &'static Self + where + T: Any, + { + &Self { + kind: Kind::Exclusive, + type_id: TypeId::of::, + debug: debug_mut_impl::, + type_info: T::ANY_TYPE_INFO, + type_hash: T::HASH, + drop_value: None, + drop: drop_box::>, + clone: clone_mut::, + } + } + + #[inline] + pub(super) fn is(&self) -> bool + where + T: 'static, + { + (self.type_id)() == TypeId::of::() + } + + #[inline] + pub(super) fn type_info(&self) -> TypeInfo { + TypeInfo::any_type_info(self.type_info) + } + + #[inline] + pub(super) fn type_hash(&self) -> Hash { + self.type_hash + } + + #[inline] + pub(super) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.debug)(f) + } + + #[inline] + pub(super) fn as_ptr(&self, base: NonNull) -> NonNull { + if matches!(self.kind, Kind::Owned) { + unsafe { base.byte_add(offset_of!(AnyObjData, data)).cast() } + } else { + unsafe { + base.byte_add(offset_of!(AnyObjData>, data)) + .cast() + .read() + } + } + } + + #[inline] + pub(super) fn is_mutable(&self) -> bool { + matches!(self.kind, Kind::Exclusive | Kind::Owned) + } + + #[inline] + pub(super) fn is_owned(&self) -> bool { + matches!(self.kind, Kind::Owned) + } +} + +fn debug_ref_impl(f: &mut fmt::Formatter<'_>) -> fmt::Result +where + T: ?Sized + Any, +{ + write!(f, "&{}", T::ITEM) +} + +fn debug_mut_impl(f: &mut fmt::Formatter<'_>) -> fmt::Result +where + T: ?Sized + Any, +{ + write!(f, "&mut {}", T::ITEM) +} + +unsafe fn drop_value(this: NonNull) { + let data = addr_of_mut!((*this.cast::>().as_ptr()).data); + drop_in_place(data); +} + +unsafe fn drop_box(this: NonNull) { + let data = Box::from_raw_in(this.cast::>().as_ptr(), Global); + drop(data) +} + +unsafe fn clone_own(this: NonNull) -> alloc::Result +where + T: Any, +{ + // NB: We read the value without deallocating it from the previous location, + // since that would cause the returned value to be invalid. + let value = addr_of_mut!((*this.cast::>().as_ptr()).data).read(); + AnyObj::new(value) +} + +unsafe fn clone_ref(this: NonNull) -> alloc::Result +where + T: Any, +{ + let value = addr_of_mut!((*this.cast::>>().as_ptr()).data).read(); + AnyObj::from_ref(value.as_ptr().cast_const()) +} + +unsafe fn clone_mut(this: NonNull) -> alloc::Result +where + T: Any, +{ + let value = addr_of_mut!((*this.cast::>>().as_ptr()).data).read(); + AnyObj::from_mut(value.as_ptr()) +} diff --git a/crates/rune/src/runtime/args.rs b/crates/rune/src/runtime/args.rs index 4c387b9f8..8d5d2aea1 100644 --- a/crates/rune/src/runtime/args.rs +++ b/crates/rune/src/runtime/args.rs @@ -1,7 +1,7 @@ use core::fmt; use crate::alloc::Vec; -use crate::runtime::{GuardedArgs, Stack, ToValue, Value, VmResult}; +use crate::runtime::{GuardedArgs, Stack, ToValue, Value, VmError}; #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] @@ -16,17 +16,19 @@ impl fmt::Display for DynArgsUsed { /// Object safe variant of args which errors instead of consumed itself. pub(crate) trait DynArgs { /// Encode arguments onto a stack. - fn push_to_stack(&mut self, stack: &mut Stack) -> VmResult<()>; + fn push_to_stack(&mut self, stack: &mut Stack) -> Result<(), VmError>; /// Get the number of arguments. fn count(&self) -> usize; } impl DynArgs for () { - fn push_to_stack(&mut self, _: &mut Stack) -> VmResult<()> { - VmResult::Ok(()) + #[inline] + fn push_to_stack(&mut self, _: &mut Stack) -> Result<(), VmError> { + Ok(()) } + #[inline] fn count(&self) -> usize { 0 } @@ -36,13 +38,13 @@ impl DynArgs for Option where T: Args, { - fn push_to_stack(&mut self, stack: &mut Stack) -> VmResult<()> { + fn push_to_stack(&mut self, stack: &mut Stack) -> Result<(), VmError> { let Some(args) = self.take() else { - return VmResult::err(DynArgsUsed); + return Err(VmError::new(DynArgsUsed)); }; - vm_try!(args.into_stack(stack)); - VmResult::Ok(()) + args.into_stack(stack)?; + Ok(()) } fn count(&self) -> usize { @@ -74,15 +76,14 @@ impl DynArgs for DynGuardedArgs where T: GuardedArgs, { - fn push_to_stack(&mut self, stack: &mut Stack) -> VmResult<()> { + fn push_to_stack(&mut self, stack: &mut Stack) -> Result<(), VmError> { let Some(value) = self.value.take() else { - return VmResult::err(DynArgsUsed); + return Err(VmError::new(DynArgsUsed)); }; // SAFETY: We've setup the type so that the caller cannot ignore the guard. - self.guard = unsafe { Some(vm_try!(GuardedArgs::guarded_into_stack(value, stack))) }; - - VmResult::Ok(()) + self.guard = unsafe { Some(GuardedArgs::guarded_into_stack(value, stack)?) }; + Ok(()) } fn count(&self) -> usize { @@ -93,16 +94,16 @@ where /// Trait for converting arguments into an array. pub trait FixedArgs { /// Encode arguments as array. - fn into_array(self) -> VmResult<[Value; N]>; + fn into_array(self) -> Result<[Value; N], VmError>; } /// Trait for converting arguments onto the stack. pub trait Args { /// Encode arguments onto a stack. - fn into_stack(self, stack: &mut Stack) -> VmResult<()>; + fn into_stack(self, stack: &mut Stack) -> Result<(), VmError>; /// Convert arguments into a vector. - fn try_into_vec(self) -> VmResult>; + fn try_into_vec(self) -> Result, VmError>; /// The number of arguments. fn count(&self) -> usize; @@ -115,10 +116,10 @@ macro_rules! impl_into_args { $($ty: ToValue,)* { #[allow(unused)] - fn into_array(self) -> VmResult<[Value; $count]> { + fn into_array(self) -> Result<[Value; $count], VmError> { let ($($value,)*) = self; - $(let $value = vm_try!($value.to_value());)* - VmResult::Ok([$($value),*]) + $(let $value = $value.to_value()?;)* + Ok([$($value),*]) } } @@ -127,18 +128,18 @@ macro_rules! impl_into_args { $($ty: ToValue,)* { #[allow(unused)] - fn into_stack(self, stack: &mut Stack) -> VmResult<()> { + fn into_stack(self, stack: &mut Stack) -> Result<(), VmError> { let ($($value,)*) = self; - $(vm_try!(stack.push(vm_try!($value.to_value())));)* - VmResult::Ok(()) + $(stack.push($value.to_value()?)?;)* + Ok(()) } #[allow(unused)] - fn try_into_vec(self) -> VmResult> { + fn try_into_vec(self) -> Result, VmError> { let ($($value,)*) = self; - let mut vec = vm_try!(Vec::try_with_capacity($count)); - $(vm_try!(vec.try_push(vm_try!(<$ty>::to_value($value))));)* - VmResult::Ok(vec) + let mut vec = Vec::try_with_capacity($count)?; + $(vec.try_push(<$ty>::to_value($value)?)?;)* + Ok(vec) } #[inline] @@ -152,17 +153,18 @@ macro_rules! impl_into_args { repeat_macro!(impl_into_args); impl Args for Vec { - fn into_stack(self, stack: &mut Stack) -> VmResult<()> { + #[inline] + fn into_stack(self, stack: &mut Stack) -> Result<(), VmError> { for value in self { - vm_try!(stack.push(value)); + stack.push(value)?; } - VmResult::Ok(()) + Ok(()) } #[inline] - fn try_into_vec(self) -> VmResult> { - VmResult::Ok(self) + fn try_into_vec(self) -> Result, VmError> { + Ok(self) } #[inline] @@ -171,19 +173,19 @@ impl Args for Vec { } } -#[cfg(feature = "alloc")] -impl Args for ::rust_alloc::vec::Vec { - fn into_stack(self, stack: &mut Stack) -> VmResult<()> { +impl Args for rust_alloc::vec::Vec { + #[inline] + fn into_stack(self, stack: &mut Stack) -> Result<(), VmError> { for value in self { - vm_try!(stack.push(value)); + stack.push(value)?; } - VmResult::Ok(()) + Ok(()) } #[inline] - fn try_into_vec(self) -> VmResult> { - VmResult::Ok(vm_try!(Vec::try_from(self))) + fn try_into_vec(self) -> Result, VmError> { + Ok(Vec::try_from(self)?) } #[inline] diff --git a/crates/rune/src/runtime/awaited.rs b/crates/rune/src/runtime/awaited.rs index 137730077..9740c3214 100644 --- a/crates/rune/src/runtime/awaited.rs +++ b/crates/rune/src/runtime/awaited.rs @@ -1,4 +1,9 @@ -use crate::runtime::{Future, Output, Select, Vm, VmResult}; +use core::future::Future as _; +use core::pin::Pin; +use core::task::{ready, Context, Poll}; + +use crate::async_vm_try; +use crate::runtime::{Future, Output, Select, Vm, VmError}; /// A stored await task. #[derive(Debug)] @@ -10,20 +15,29 @@ pub(crate) enum Awaited { } impl Awaited { - /// Wait for the given awaited into the specified virtual machine. - pub(crate) async fn into_vm(self, vm: &mut Vm) -> VmResult<()> { - match self { + pub(crate) fn poll( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + vm: &mut Vm, + ) -> Poll> { + let this = unsafe { Pin::get_unchecked_mut(self) }; + + match this { Self::Future(future, out) => { - let value = vm_try!(future.await.with_vm(vm)); - vm_try!(out.store(vm.stack_mut(), value)); + let future = unsafe { Pin::new_unchecked(future) }; + let result = ready!(future.poll(cx)); + let value = async_vm_try!(VmError::with_vm(result, vm)); + async_vm_try!(out.store(vm.stack_mut(), value)); } Self::Select(select, value_addr) => { - let (ip, value) = vm_try!(select.await.with_vm(vm)); + let select = unsafe { Pin::new_unchecked(select) }; + let result = ready!(select.poll(cx)); + let (ip, value) = async_vm_try!(VmError::with_vm(result, vm)); vm.set_ip(ip); - vm_try!(value_addr.store(vm.stack_mut(), || value)); + async_vm_try!(value_addr.store(vm.stack_mut(), || value)); } } - VmResult::Ok(()) + Poll::Ready(Ok(())) } } diff --git a/crates/rune/src/runtime/budget.rs b/crates/rune/src/runtime/budget.rs index 2017bc9aa..d971a93c9 100644 --- a/crates/rune/src/runtime/budget.rs +++ b/crates/rune/src/runtime/budget.rs @@ -88,6 +88,14 @@ pub fn with(budget: usize, value: T) -> Budget { Budget { budget, value } } +/// Replace the current budget returning a guard that will release it. +/// +/// Use [`BudgetGuard::take`] to take permites from the returned budget. +#[inline(never)] +pub fn replace(budget: usize) -> BudgetGuard { + BudgetGuard(self::no_std::rune_budget_replace(budget)) +} + /// Acquire the current budget. /// /// Use [`BudgetGuard::take`] to take permites from the returned budget. @@ -106,6 +114,7 @@ pub struct BudgetGuard(usize); impl BudgetGuard { /// Take a ticker from the budget. + #[inline] pub fn take(&mut self) -> bool { if self.0 == usize::MAX { return true; @@ -121,6 +130,7 @@ impl BudgetGuard { } impl Drop for BudgetGuard { + #[inline] fn drop(&mut self) { let _ = self::no_std::rune_budget_replace(self.0); } @@ -131,6 +141,7 @@ where T: Callable, { /// Call the budgeted function. + #[inline] pub fn call(self) -> T::Output { Callable::call(self) } @@ -155,6 +166,7 @@ where { type Output = T::Output; + #[inline] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); diff --git a/crates/rune/src/runtime/bytes.rs b/crates/rune/src/runtime/bytes.rs index ba9a056b1..9e9e83d05 100644 --- a/crates/rune/src/runtime/bytes.rs +++ b/crates/rune/src/runtime/bytes.rs @@ -5,25 +5,30 @@ use core::fmt; use core::ops; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::de; +#[cfg(feature = "serde")] use serde::ser; use crate as rune; use crate::alloc::prelude::*; use crate::alloc::{self, Box, Vec}; -use crate::runtime::VmResult; use crate::TypeHash as _; use crate::{Any, FromValue}; use super::{ IntoOutput, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, - RawAnyGuard, Ref, RuntimeError, UnsafeToRef, Value, VmErrorKind, + RawAnyGuard, Ref, RuntimeError, UnsafeToRef, Value, VmError, VmErrorKind, }; /// A vector of bytes. #[derive(Any, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "musli", derive(Encode, Decode), musli(transparent))] #[rune(item = ::std::bytes)] pub struct Bytes { + #[cfg_attr(feature = "musli", musli(bytes))] bytes: Vec, } @@ -74,8 +79,7 @@ impl Bytes { /// /// let bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// assert_eq!(bytes.into_vec(), [b'a', b'b', b'c', b'd']); - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn into_vec(self) -> Vec { @@ -92,8 +96,7 @@ impl Bytes { /// /// let bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// assert_eq!(bytes.as_slice(), &[b'a', b'b', b'c', b'd']); - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn as_slice(&self) -> &[u8] { @@ -152,8 +155,7 @@ impl Bytes { /// let mut bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// bytes.extend(b"efgh"); /// assert_eq!(bytes, b"abcdefgh"); - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn extend(&mut self, other: O) -> alloc::Result<()> where @@ -229,7 +231,7 @@ impl Bytes { /// let mut bytes = Bytes::from_slice(b"abcd")?; /// assert_eq!(bytes.pop(), Some(b'd')); /// assert_eq!(bytes, b"abc"); - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn pop(&mut self) -> Option { self.bytes.pop() @@ -245,7 +247,7 @@ impl Bytes { /// let mut bytes = Bytes::from_slice(b"abcd")?; /// bytes.push(b'e'); /// assert_eq!(bytes, b"abcde"); - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn push(&mut self, value: u8) -> alloc::Result<()> { self.bytes.try_push(value) @@ -265,7 +267,7 @@ impl Bytes { /// let mut bytes = Bytes::from_slice(b"abcd")?; /// bytes.remove(2); /// assert_eq!(bytes, b"abd"); - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn remove(&mut self, index: usize) -> u8 { self.bytes.remove(index) @@ -286,7 +288,7 @@ impl Bytes { /// let mut bytes = Bytes::from_slice(b"abcd")?; /// bytes.insert(2, b'e'); /// assert_eq!(bytes, b"abecd"); - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn insert(&mut self, index: usize, value: u8) -> alloc::Result<()> { self.bytes.try_insert(index, value) @@ -298,7 +300,7 @@ impl Bytes { /// out of bounds. /// - If given a range, returns the subslice corresponding to that range, or /// `None` if out of bounds. - pub(crate) fn index_get(&self, index: Value) -> VmResult> { + pub(crate) fn index_get(&self, index: Value) -> Result, VmError> { bytes_slice_index_get(&self.bytes, index) } @@ -312,18 +314,18 @@ impl Bytes { /// let mut bytes = Bytes::from_slice(b"abcd")?; /// bytes.set(0, b'A'); /// assert_eq!(bytes, b"Abcd"); - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn set(&mut self, index: usize, value: u8) -> VmResult<()> { + pub fn set(&mut self, index: usize, value: u8) -> Result<(), VmError> { let Some(v) = self.bytes.get_mut(index) else { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: self.len().into(), - }); + })); }; *v = value; - VmResult::Ok(()) + Ok(()) } /// Get the first byte. @@ -335,8 +337,7 @@ impl Bytes { /// /// let bytes = Bytes::from_slice(b"abcd")?; /// assert_eq!(bytes.first(), Some(b'a')); - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn first(&self) -> Option { self.bytes.first().copied() @@ -351,8 +352,7 @@ impl Bytes { /// /// let bytes = Bytes::from_slice(b"abcd")?; /// assert_eq!(bytes.last(), Some(b'd')); - /// - /// Ok::<_, rune::support::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn last(&self) -> Option { self.bytes.last().copied() @@ -375,7 +375,6 @@ impl From> for Bytes { } } -#[cfg(feature = "alloc")] impl TryFrom<&[u8]> for Bytes { type Error = alloc::Error; @@ -387,12 +386,11 @@ impl TryFrom<&[u8]> for Bytes { } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::vec::Vec> for Bytes { +impl TryFrom> for Bytes { type Error = alloc::Error; #[inline] - fn try_from(bytes: ::rust_alloc::vec::Vec) -> Result { + fn try_from(bytes: rust_alloc::vec::Vec) -> Result { Ok(Self { bytes: Vec::try_from(bytes)?, }) @@ -408,12 +406,11 @@ impl From> for Bytes { } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::boxed::Box<[u8]>> for Bytes { +impl TryFrom> for Bytes { type Error = alloc::Error; #[inline] - fn try_from(bytes: ::rust_alloc::boxed::Box<[u8]>) -> Result { + fn try_from(bytes: rust_alloc::boxed::Box<[u8]>) -> Result { Ok(Self { bytes: Vec::try_from(bytes.as_ref())?, }) @@ -502,7 +499,9 @@ impl PartialEq for [u8] { } } +#[cfg(feature = "serde")] impl ser::Serialize for Bytes { + #[inline] fn serialize(&self, serializer: S) -> Result where S: ser::Serializer, @@ -511,7 +510,9 @@ impl ser::Serialize for Bytes { } } +#[cfg(feature = "serde")] impl<'de> de::Deserialize<'de> for Bytes { + #[inline] fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, @@ -556,57 +557,58 @@ impl IntoOutput for &[u8] { } /// This is a common index get implementation that is helpfull for custom type to impl `INDEX_GET` protocol. -pub fn bytes_slice_index_get(this: &[u8], index: Value) -> VmResult> { +pub fn bytes_slice_index_get(this: &[u8], index: Value) -> Result, VmError> { let slice: Option<&[u8]> = 'out: { if let Some(value) = index.as_any() { match value.type_hash() { RangeFrom::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; break 'out this.get(start..); } RangeFull::HASH => { - _ = vm_try!(value.borrow_ref::()); + _ = value.borrow_ref::()?; break 'out this.get(..); } RangeInclusive::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; + let end = range.end.as_usize()?; break 'out this.get(start..=end); } RangeToInclusive::HASH => { - let range = vm_try!(value.borrow_ref::()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let end = range.end.as_usize()?; break 'out this.get(..=end); } RangeTo::HASH => { - let range = vm_try!(value.borrow_ref::()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let end = range.end.as_usize()?; break 'out this.get(..end); } Range::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; + let end = range.end.as_usize()?; break 'out this.get(start..end); } _ => {} } }; - let index = vm_try!(usize::from_value(index)); + let index = usize::from_value(index)?; + let Some(value) = this.get(index) else { - return VmResult::Ok(None); + return Ok(None); }; - return VmResult::Ok(Some((*value).into())); + return Ok(Some((*value).into())); }; let Some(values) = slice else { - return VmResult::Ok(None); + return Ok(None); }; - let bytes = vm_try!(Bytes::try_from(values)); - VmResult::Ok(Some(vm_try!(bytes.try_into()))) + let bytes = Bytes::try_from(values)?; + Ok(Some(bytes.try_into()?)) } diff --git a/crates/rune/src/runtime/call.rs b/crates/rune/src/runtime/call.rs index 770e99c60..0f064af8d 100644 --- a/crates/rune/src/runtime/call.rs +++ b/crates/rune/src/runtime/call.rs @@ -1,14 +1,18 @@ use core::fmt; +#[cfg(feature = "musli")] use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; use crate::alloc::prelude::*; -use crate::runtime::{Future, Generator, Stream, Value, Vm, VmResult}; +use crate::runtime::{Future, Generator, Stream, Value, Vm, VmError}; /// The calling convention of a function. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] #[try_clone(copy)] #[non_exhaustive] pub enum Call { @@ -26,37 +30,36 @@ pub enum Call { impl Call { /// Perform the call with the given virtual machine. #[inline] - pub(crate) fn call_with_vm(self, vm: Vm) -> VmResult { - VmResult::Ok(match self { - Call::Stream => vm_try!(Value::try_from(Stream::new(vm))), - Call::Generator => vm_try!(Value::try_from(Generator::new(vm))), - Call::Immediate => vm_try!(vm.complete()), + pub(crate) fn call_with_vm(self, vm: Vm) -> Result { + Ok(match self { + Call::Stream => Value::try_from(Stream::new(vm))?, + Call::Generator => Value::try_from(Generator::new(vm))?, + Call::Immediate => vm.complete()?, Call::Async => { let mut execution = vm.into_execution(); - let future = vm_try!(Future::new(async move { execution.async_complete().await })); - vm_try!(Value::try_from(future)) + let future = Future::new(async move { execution.resume().await?.into_complete() })?; + Value::try_from(future)? } }) } } impl fmt::Display for Call { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Immediate => { - write!(fmt, "immediate")?; + write!(f, "immediate") } Self::Async => { - write!(fmt, "async")?; + write!(f, "async") } Self::Stream => { - write!(fmt, "stream")?; + write!(f, "stream") } Self::Generator => { - write!(fmt, "generator")?; + write!(f, "generator") } } - - Ok(()) } } diff --git a/crates/rune/src/runtime/const_value.rs b/crates/rune/src/runtime/const_value.rs index 2adc18b30..19b727000 100644 --- a/crates/rune/src/runtime/const_value.rs +++ b/crates/rune/src/runtime/const_value.rs @@ -7,6 +7,9 @@ use core::fmt; use rust_alloc::sync::Arc; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; @@ -20,7 +23,77 @@ use super::{ VmErrorKind, }; -/// Derive for the [`ToConstValue`](trait@ToConstValue) trait. +/// Derive for the [`ToConstValue`] trait. +/// +/// This is principally used for associated constants in native modules, since +/// Rune has to be provided a constant-compatible method for constructing values +/// of the given type. +/// +/// [`ToConstValue`]: trait@crate::ToConstValue +/// +/// # Examples +/// +/// ``` +/// use rune::{docstring, Any, ContextError, Module, ToConstValue}; +/// +/// #[derive(Any, ToConstValue)] +/// pub struct Duration { +/// #[const_value(with = const_duration)] +/// inner: std::time::Duration, +/// } +/// +/// mod const_duration { +/// use rune::runtime::{ConstValue, RuntimeError, Value}; +/// use std::time::Duration; +/// +/// #[inline] +/// pub(super) fn to_const_value(duration: Duration) -> Result { +/// let secs = duration.as_secs(); +/// let nanos = duration.subsec_nanos(); +/// rune::to_const_value((secs, nanos)) +/// } +/// +/// #[inline] +/// pub(super) fn from_const_value(value: &ConstValue) -> Result { +/// let (secs, nanos) = rune::from_const_value::<(u64, u32)>(value)?; +/// Ok(Duration::new(secs, nanos)) +/// } +/// +/// #[inline] +/// pub(super) fn from_value(value: Value) -> Result { +/// let (secs, nanos) = rune::from_value::<(u64, u32)>(value)?; +/// Ok(Duration::new(secs, nanos)) +/// } +/// } +/// +/// #[rune::module(::time)] +/// pub fn module() -> Result { +/// let mut m = Module::from_meta(module__meta)?; +/// m.ty::()?; +/// +/// m +/// .constant( +/// "SECOND", +/// Duration { +/// inner: std::time::Duration::from_secs(1), +/// }, +/// ) +/// .build_associated::()? +/// .docs(docstring! { +/// /// The duration of one second. +/// /// +/// /// # Examples +/// /// +/// /// ```rune +/// /// use time::Duration; +/// /// +/// /// let duration = Duration::SECOND; +/// /// ``` +/// })?; +/// +/// Ok(m) +/// } +/// ``` pub use rune_macros::ToConstValue; use super::{AnyTypeInfo, RuntimeError, VmIntegerRepr}; @@ -81,13 +154,14 @@ pub fn to_const_value(value: impl ToConstValue) -> Result Result; /// Return the constant constructor for the given type. #[inline] + #[doc(hidden)] fn construct() -> Option> { None } @@ -107,7 +181,9 @@ impl ToConstValue for Value { } } -#[derive(Debug, TryClone, Deserialize, Serialize)] +#[derive(Debug, TryClone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] pub(crate) enum ConstValueKind { /// An inline constant value. Inline(#[try_clone(copy)] Inline), @@ -149,8 +225,8 @@ impl ConstValueKind { } /// A constant value. -#[derive(Deserialize, Serialize)] -#[serde(transparent)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Encode, Decode), musli(transparent))] pub struct ConstValue { kind: ConstValueKind, } @@ -455,7 +531,7 @@ impl fmt::Debug for ConstValue { } } -/// Convert a value from a constant value. +/// Trait to perform a conversion from a [`ConstValue`]. pub trait FromConstValue: Sized { /// Convert from a constant value. fn from_const_value(value: ConstValue) -> Result; @@ -468,10 +544,40 @@ impl FromConstValue for ConstValue { } } +impl FromConstValue for bool { + #[inline] + fn from_const_value(value: ConstValue) -> Result { + value.as_bool() + } +} + +impl FromConstValue for char { + #[inline] + fn from_const_value(value: ConstValue) -> Result { + value.as_char() + } +} + +macro_rules! impl_integer { + ($($ty:ty),* $(,)?) => { + $( + impl FromConstValue for $ty { + #[inline] + fn from_const_value(value: ConstValue) -> Result { + value.as_integer() + } + } + )* + }; +} + +impl_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + /// Implementation of a constant constructor. /// -/// Do not implement manually, this is provided when deriving -/// [`ToConstValue`](derive@ToConstValue). +/// Do not implement manually, this is provided when deriving [`ToConstValue`]. +/// +/// [`ToConstValue`]: derive@ToConstValue pub trait ConstConstruct: 'static + Send + Sync { /// Construct from values. #[doc(hidden)] diff --git a/crates/rune/src/runtime/control_flow.rs b/crates/rune/src/runtime/control_flow.rs index 636b9feed..3db20941d 100644 --- a/crates/rune/src/runtime/control_flow.rs +++ b/crates/rune/src/runtime/control_flow.rs @@ -1,12 +1,13 @@ use core::ops; use crate as rune; +use crate::alloc; use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::Any; use super::{ - EnvProtocolCaller, Formatter, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmResult, + EnvProtocolCaller, Formatter, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmError, }; /// Used to tell an operation whether it should exit early or go on as usual. @@ -58,7 +59,7 @@ impl ControlFlow { /// }; /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub(crate) fn partial_eq(&self, other: &Self) -> VmResult { + pub(crate) fn partial_eq(&self, other: &Self) -> Result { Self::partial_eq_with(self, other, &mut EnvProtocolCaller) } @@ -66,13 +67,13 @@ impl ControlFlow { &self, other: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { match (self, other) { (ControlFlow::Continue(a), ControlFlow::Continue(b)) => { Value::partial_eq_with(a, b, caller) } (ControlFlow::Break(a), ControlFlow::Break(b)) => Value::partial_eq_with(a, b, caller), - _ => VmResult::Ok(false), + _ => Ok(false), } } @@ -97,7 +98,7 @@ impl ControlFlow { /// }; /// ``` #[rune::function(keep, protocol = EQ)] - pub(crate) fn eq(&self, other: &ControlFlow) -> VmResult { + pub(crate) fn eq(&self, other: &ControlFlow) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } @@ -105,11 +106,11 @@ impl ControlFlow { &self, other: &ControlFlow, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { match (self, other) { (ControlFlow::Continue(a), ControlFlow::Continue(b)) => Value::eq_with(a, b, caller), (ControlFlow::Break(a), ControlFlow::Break(b)) => Value::eq_with(a, b, caller), - _ => VmResult::Ok(false), + _ => Ok(false), } } @@ -123,7 +124,7 @@ impl ControlFlow { /// let string = format!("{:?}", ControlFlow::Continue(true)); /// ``` #[rune::function(keep, protocol = DEBUG_FMT)] - pub(crate) fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { + pub(crate) fn debug_fmt(&self, f: &mut Formatter) -> Result<(), VmError> { Self::debug_fmt_with(self, f, &mut EnvProtocolCaller) } @@ -131,21 +132,21 @@ impl ControlFlow { &self, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { match self { ControlFlow::Continue(value) => { - vm_try!(vm_write!(f, "Continue(")); - vm_try!(Value::debug_fmt_with(value, f, caller)); - vm_try!(vm_write!(f, ")")); + write!(f, "Continue(")?; + Value::debug_fmt_with(value, f, caller)?; + write!(f, ")")?; } ControlFlow::Break(value) => { - vm_try!(vm_write!(f, "Break(")); - vm_try!(Value::debug_fmt_with(value, f, caller)); - vm_try!(vm_write!(f, ")")); + write!(f, "Break(")?; + Value::debug_fmt_with(value, f, caller)?; + write!(f, ")")?; } } - VmResult::Ok(()) + Ok(()) } /// Clone the control flow. @@ -161,8 +162,8 @@ impl ControlFlow { /// assert_eq!(flow, flow2); /// ``` #[rune::function(keep, protocol = CLONE)] - pub(crate) fn clone(&self) -> VmResult { - VmResult::Ok(vm_try!(self.try_clone())) + pub(crate) fn clone(&self) -> alloc::Result { + self.try_clone() } } diff --git a/crates/rune/src/runtime/debug.rs b/crates/rune/src/runtime/debug.rs index dc11b2efa..0fd093d36 100644 --- a/crates/rune/src/runtime/debug.rs +++ b/crates/rune/src/runtime/debug.rs @@ -2,6 +2,9 @@ use core::fmt; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; @@ -12,7 +15,9 @@ use crate::runtime::DebugLabel; use crate::{Hash, ItemBuf, SourceId}; /// Debug information about a unit. -#[derive(Debug, TryClone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[non_exhaustive] pub struct DebugInfo { /// Debug information on each instruction. @@ -45,7 +50,9 @@ impl DebugInfo { } /// Debug information for every instruction. -#[derive(Debug, TryClone, Serialize, Deserialize)] +#[derive(Debug, TryClone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[non_exhaustive] pub struct DebugInst { /// The file by id the instruction belongs to. @@ -76,7 +83,10 @@ impl DebugInst { } /// Debug information on function arguments. -#[derive(Debug, TryClone, Serialize, Deserialize)] +#[derive(Debug, TryClone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] +#[non_exhaustive] pub enum DebugArgs { /// An empty, with not arguments. EmptyArgs, @@ -87,7 +97,9 @@ pub enum DebugArgs { } /// A description of a function signature. -#[derive(Debug, TryClone, Serialize, Deserialize)] +#[derive(Debug, TryClone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[non_exhaustive] pub struct DebugSignature { /// The path of the function. @@ -98,6 +110,7 @@ pub struct DebugSignature { impl DebugSignature { /// Construct a new function signature. + #[inline] pub fn new(path: ItemBuf, args: DebugArgs) -> Self { Self { path, args } } @@ -116,11 +129,11 @@ impl fmt::Display for DebugSignature { let last = it.next_back(); for arg in it { - write!(fmt, "{}, ", arg)?; + write!(fmt, "{arg}, ")?; } if let Some(arg) = last { - write!(fmt, "{}", arg)?; + write!(fmt, "{arg}")?; } write!(fmt, ")")?; @@ -132,11 +145,11 @@ impl fmt::Display for DebugSignature { let last = it.next_back(); for arg in it { - write!(fmt, "{}, ", arg)?; + write!(fmt, "{arg}, ")?; } if let Some(arg) = last { - write!(fmt, "{}", arg)?; + write!(fmt, "{arg}")?; } write!(fmt, ")")?; diff --git a/crates/rune/src/runtime/env.rs b/crates/rune/src/runtime/env.rs index fd6cfbdb5..e58f2c190 100644 --- a/crates/rune/src/runtime/env.rs +++ b/crates/rune/src/runtime/env.rs @@ -13,18 +13,18 @@ use core::ptr::NonNull; #[cfg_attr(feature = "std", path = "env/std.rs")] mod no_std; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate::runtime::vm_diagnostics::VmDiagnosticsObj; -use crate::runtime::{RuntimeContext, Unit, VmErrorKind, VmResult}; +use crate::runtime::{RuntimeContext, Unit, VmError, VmErrorKind}; /// Access shared parts of the environment. /// /// This does not take ownership of the environment, so the environment can be /// recursively accessed. -pub(crate) fn shared(c: F) -> VmResult +pub(crate) fn shared(c: F) -> Result where - F: FnOnce(&Arc, &Arc) -> VmResult, + F: FnOnce(&Arc, &Arc) -> Result, { let env = self::no_std::rune_env_get(); @@ -34,7 +34,7 @@ where .. } = env else { - return VmResult::err(VmErrorKind::MissingInterfaceEnvironment); + return Err(VmError::new(VmErrorKind::MissingInterfaceEnvironment)); }; // Safety: context and unit can only be registered publicly through @@ -50,9 +50,13 @@ where /// /// This takes ownership of the environment, so recursive calls are not /// supported. -pub(crate) fn exclusive(c: F) -> VmResult +pub(crate) fn exclusive(c: F) -> Result where - F: FnOnce(&Arc, &Arc, Option<&mut VmDiagnosticsObj>) -> VmResult, + F: FnOnce( + &Arc, + &Arc, + Option<&mut VmDiagnosticsObj>, + ) -> Result, { let guard = Guard { env: self::no_std::rune_env_replace(Env::null()), @@ -64,7 +68,7 @@ where .. } = guard.env else { - return VmResult::err(VmErrorKind::MissingInterfaceEnvironment); + return Err(VmError::new(VmErrorKind::MissingInterfaceEnvironment)); }; // Safety: context and unit can only be registered publicly through diff --git a/crates/rune/src/runtime/fmt.rs b/crates/rune/src/runtime/fmt.rs index 8a8236968..45bfd7dd6 100644 --- a/crates/rune/src/runtime/fmt.rs +++ b/crates/rune/src/runtime/fmt.rs @@ -2,7 +2,6 @@ use core::ptr::NonNull; use crate::alloc::fmt::TryWrite; use crate::alloc::{self, String}; -use crate::runtime::VmResult; use crate::Any; /// A formatter for the rune virtual machine. @@ -21,10 +20,10 @@ pub struct Formatter { impl Formatter { /// Format onto the given trywrite. - pub(crate) fn format_with( + pub(crate) fn format_with( out: &mut String, - f: impl FnOnce(&mut Self) -> VmResult<()>, - ) -> VmResult<()> { + f: impl FnOnce(&mut Self) -> Result<(), E>, + ) -> Result<(), E> { // SAFETY: Call to this function ensures that the formatter does not // outlive the passed in reference. let mut fmt = Formatter { diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index ec7778952..929a655aa 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -6,14 +6,16 @@ use core::mem::take; use core::num::NonZeroUsize; use core::str; +#[cfg(feature = "musli")] use musli::{Decode, Encode}; +#[cfg(feature = "serde")] 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, Inline, ProtocolCaller, Repr, Value, VmErrorKind, VmResult}; +use crate::alloc::{self, String}; +use crate::runtime::{Formatter, Inline, ProtocolCaller, Repr, Value, VmError, VmErrorKind}; use crate::{Any, TypeHash}; /// Error raised when trying to parse a type string and it fails. @@ -51,7 +53,9 @@ pub struct Format { } /// A format specification. -#[derive(Debug, Clone, Copy, TryClone, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, Clone, Copy, TryClone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] #[non_exhaustive] pub struct FormatSpec { @@ -120,22 +124,22 @@ impl FormatSpec { } /// Format the given number. - fn format_number(&self, buf: &mut String, n: i64) -> VmResult<()> { + fn format_number(&self, buf: &mut String, n: i64) -> alloc::Result<()> { let mut buffer = itoa::Buffer::new(); - vm_try!(buf.try_push_str(buffer.format(n))); - VmResult::Ok(()) + buf.try_push_str(buffer.format(n))?; + Ok(()) } /// Format the given float. - fn format_float(&self, buf: &mut String, n: f64) -> VmResult<()> { + fn format_float(&self, buf: &mut String, n: f64) -> alloc::Result<()> { if let Some(precision) = self.precision { - vm_try!(vm_write!(buf, "{:.*}", precision.get(), n)); + write!(buf, "{:.*}", precision.get(), n)?; } else { let mut buffer = ryu::Buffer::new(); - vm_try!(buf.try_push_str(buffer.format(n))); + buf.try_push_str(buffer.format(n))?; } - VmResult::Ok(()) + Ok(()) } /// Format fill. @@ -145,18 +149,18 @@ impl FormatSpec { align: Alignment, fill: char, sign: Option, - ) -> VmResult<()> { + ) -> alloc::Result<()> { let (f, buf) = f.parts_mut(); if let Some(sign) = sign { - vm_try!(f.try_write_char(sign)); + f.try_write_char(sign)?; } let mut w = self.width.map(|n| n.get()).unwrap_or_default(); if w == 0 { - vm_try!(f.try_write_str(buf)); - return VmResult::Ok(()); + f.try_write_str(buf)?; + return Ok(()); } w = w @@ -164,41 +168,41 @@ impl FormatSpec { .saturating_sub(sign.map(|_| 1).unwrap_or_default()); if w == 0 { - vm_try!(f.try_write_str(buf)); - return VmResult::Ok(()); + f.try_write_str(buf)?; + return Ok(()); } - let mut filler = iter::repeat(fill).take(w); + let mut filler = iter::repeat_n(fill, w); match align { Alignment::Left => { - vm_try!(f.try_write_str(buf)); + f.try_write_str(buf)?; for c in filler { - vm_try!(f.try_write_char(c)); + f.try_write_char(c)?; } } Alignment::Center => { for c in (&mut filler).take(w / 2) { - vm_try!(f.try_write_char(c)); + f.try_write_char(c)?; } - vm_try!(f.try_write_str(buf)); + f.try_write_str(buf)?; for c in filler { - vm_try!(f.try_write_char(c)); + f.try_write_char(c)?; } } Alignment::Right => { for c in filler { - vm_try!(f.try_write_char(c)); + f.try_write_char(c)?; } - vm_try!(f.try_write_str(buf)); + f.try_write_str(buf)?; } } - VmResult::Ok(()) + Ok(()) } fn format_display( @@ -206,23 +210,23 @@ impl FormatSpec { value: &Value, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { 'fallback: { match value.as_ref() { Repr::Inline(value) => match value { Inline::Char(c) => { - vm_try!(f.buf_mut().try_push(*c)); - vm_try!(self.format_fill(f, self.align, self.fill, None)); + f.buf_mut().try_push(*c)?; + self.format_fill(f, self.align, self.fill, None)?; } Inline::Signed(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)); + self.format_number(f.buf_mut(), n)?; + self.format_fill(f, align, fill, sign)?; } Inline::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)); + self.format_float(f.buf_mut(), n)?; + self.format_fill(f, align, fill, sign)?; } _ => { break 'fallback; @@ -233,9 +237,9 @@ impl FormatSpec { } Repr::Any(value) => match value.type_hash() { String::HASH => { - let s = vm_try!(value.borrow_ref::()); - vm_try!(f.buf_mut().try_push_str(&s)); - vm_try!(self.format_fill(f, self.align, self.fill, None)); + let s = value.borrow_ref::()?; + f.buf_mut().try_push_str(&s)?; + self.format_fill(f, self.align, self.fill, None)?; } _ => { break 'fallback; @@ -243,7 +247,7 @@ impl FormatSpec { }, } - return VmResult::Ok(()); + return Ok(()); } value.display_fmt_with(f, caller) @@ -254,19 +258,19 @@ impl FormatSpec { value: &Value, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { 'fallback: { match value.as_ref() { Repr::Inline(value) => match value { Inline::Signed(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)); + self.format_number(f.buf_mut(), n)?; + self.format_fill(f, align, fill, sign)?; } Inline::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)); + self.format_float(f.buf_mut(), n)?; + self.format_fill(f, align, fill, sign)?; } _ => { break 'fallback; @@ -277,8 +281,8 @@ impl FormatSpec { } Repr::Any(value) => match value.type_hash() { String::HASH => { - let s = vm_try!(value.borrow_ref::()); - vm_try!(vm_write!(f, "{s:?}")); + let s = value.borrow_ref::()?; + write!(f, "{s:?}")?; } _ => { break 'fallback; @@ -286,70 +290,70 @@ impl FormatSpec { }, } - return VmResult::Ok(()); + return Ok(()); }; value.debug_fmt_with(f, caller) } - fn format_upper_hex(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { + fn format_upper_hex(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> { match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_try!(vm_write!(f.buf_mut(), "{:X}", n)); - vm_try!(self.format_fill(f, align, fill, sign)); + write!(f.buf_mut(), "{:X}", n)?; + self.format_fill(f, align, fill, sign)?; } _ => { - return VmResult::err(VmErrorKind::IllegalFormat); + return Err(VmError::new(VmErrorKind::IllegalFormat)); } } - VmResult::Ok(()) + Ok(()) } - fn format_lower_hex(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { + fn format_lower_hex(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> { match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_try!(vm_write!(f.buf_mut(), "{:x}", n)); - vm_try!(self.format_fill(f, align, fill, sign)); + write!(f.buf_mut(), "{:x}", n)?; + self.format_fill(f, align, fill, sign)?; } _ => { - return VmResult::err(VmErrorKind::IllegalFormat); + return Err(VmError::new(VmErrorKind::IllegalFormat)); } } - VmResult::Ok(()) + Ok(()) } - fn format_binary(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { + fn format_binary(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> { match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_try!(vm_write!(f.buf_mut(), "{:b}", n)); - vm_try!(self.format_fill(f, align, fill, sign)); + write!(f.buf_mut(), "{:b}", n)?; + self.format_fill(f, align, fill, sign)?; } _ => { - return VmResult::err(VmErrorKind::IllegalFormat); + return Err(VmError::new(VmErrorKind::IllegalFormat)); } } - VmResult::Ok(()) + Ok(()) } - fn format_pointer(&self, value: &Value, f: &mut Formatter) -> VmResult<()> { + fn format_pointer(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> { match value.as_inline() { Some(Inline::Signed(n)) => { let (n, align, fill, sign) = self.int_traits(*n); - vm_try!(vm_write!(f.buf_mut(), "{:p}", n as *const ())); - vm_try!(self.format_fill(f, align, fill, sign)); + write!(f.buf_mut(), "{:p}", n as *const ())?; + self.format_fill(f, align, fill, sign)?; } _ => { - return VmResult::err(VmErrorKind::IllegalFormat); + return Err(VmError::new(VmErrorKind::IllegalFormat)); } } - VmResult::Ok(()) + Ok(()) } /// Format the given value to the out buffer `out`, using `buf` for @@ -359,23 +363,24 @@ impl FormatSpec { value: &Value, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { f.buf_mut().clear(); match self.format_type { - Type::Display => vm_try!(self.format_display(value, f, caller)), - Type::Debug => vm_try!(self.format_debug(value, f, caller)), - Type::UpperHex => vm_try!(self.format_upper_hex(value, f)), - Type::LowerHex => vm_try!(self.format_lower_hex(value, f)), - Type::Binary => vm_try!(self.format_binary(value, f)), - Type::Pointer => vm_try!(self.format_pointer(value, f)), + Type::Display => self.format_display(value, f, caller)?, + Type::Debug => self.format_debug(value, f, caller)?, + Type::UpperHex => self.format_upper_hex(value, f)?, + Type::LowerHex => self.format_lower_hex(value, f)?, + Type::Binary => self.format_binary(value, f)?, + Type::Pointer => self.format_pointer(value, f)?, } - VmResult::Ok(()) + Ok(()) } } impl fmt::Display for FormatSpec { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -396,6 +401,7 @@ impl fmt::Display for OptionDebug<'_, T> where T: fmt::Display, { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { Some(value) => write!(f, "{}", value), @@ -405,10 +411,13 @@ where } /// The type of formatting requested. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[non_exhaustive] pub enum Type { /// Display type (default). + #[default] Display, /// Debug type. Debug, @@ -425,6 +434,7 @@ pub enum Type { impl str::FromStr for Type { type Err = TypeFromStrError; + #[inline] fn from_str(s: &str) -> Result { match s { "display" => Ok(Self::Display), @@ -438,13 +448,8 @@ impl str::FromStr for Type { } } -impl Default for Type { - fn default() -> Self { - Self::Display - } -} - impl fmt::Display for Type { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Display => { @@ -472,7 +477,9 @@ impl fmt::Display for Type { } /// The alignment requested. -#[derive(Debug, Clone, Copy, TryClone, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, Clone, Copy, TryClone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] #[non_exhaustive] pub enum Alignment { @@ -493,6 +500,7 @@ impl Default for Alignment { impl str::FromStr for Alignment { type Err = AlignmentFromStrError; + #[inline] fn from_str(s: &str) -> Result { match s { "left" => Ok(Self::Left), @@ -504,6 +512,7 @@ impl str::FromStr for Alignment { } impl fmt::Display for Alignment { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Left => { @@ -537,20 +546,23 @@ pub enum Flag { } /// Format specification flags. -#[derive(Clone, Copy, TryClone, Default, PartialEq, Eq, Serialize, Deserialize, Decode, Encode)] +#[derive(Clone, Copy, TryClone, Default, PartialEq, Eq)] #[repr(transparent)] -#[musli(transparent)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] #[try_clone(copy)] pub struct Flags(u32); impl Flags { /// Check if the set of flags is empty. + #[inline] pub fn is_empty(self) -> bool { self.0 == 0 } /// Get the flags as a number. This representation is not guaranteed to be /// stable. + #[inline] pub fn into_u32(self) -> u32 { self.0 } diff --git a/crates/rune/src/runtime/from_value.rs b/crates/rune/src/runtime/from_value.rs index c46e29d0b..ae37857ca 100644 --- a/crates/rune/src/runtime/from_value.rs +++ b/crates/rune/src/runtime/from_value.rs @@ -4,9 +4,7 @@ use crate::alloc::{self, String}; use crate::any::AnyMarker; use crate::hash::Hash; -use super::{ - AnyObj, ConstValue, FromConstValue, Mut, RawAnyGuard, Ref, RuntimeError, Value, VmResult, -}; +use super::{Mut, RawAnyGuard, Ref, RuntimeError, Value}; /// Derive macro for the [`FromValue`] trait for converting types from the /// dynamic `Value` container. @@ -211,46 +209,6 @@ pub trait UnsafeToRef { unsafe fn unsafe_to_ref<'a>(value: Value) -> Result<(&'a Self, Self::Guard), RuntimeError>; } -/// A potentially unsafe conversion for value conversion. -/// -/// This trait is used to convert values to references, which can be safely used -/// while an external function call is used. That sort of use is safe because we -/// hold onto the guard returned by the conversion during external function -/// calls. -#[deprecated = "Rune: Implementing this trait will no longer work. Use UnsafeToRef and UnsafeToMut instead."] -pub trait UnsafeFromValue: Sized { - /// The output type from the unsafe coercion. - type Output: 'static; - - /// The raw guard returned. - /// - /// Must only be dropped *after* the value returned from this function is - /// no longer live. - type Guard: 'static; - - /// Convert the given reference using unsafe assumptions to a value. - /// - /// # Safety - /// - /// The return value of this function may only be used while a virtual - /// machine is not being modified. - /// - /// You must also make sure that the returned value does not outlive the - /// guard. - fn unsafe_from_value(value: Value) -> VmResult<(Self::Output, Self::Guard)>; - - /// Coerce the output of an unsafe from value into the final output type. - /// - /// # Safety - /// - /// The return value of this function may only be used while a virtual - /// machine is not being modified. - /// - /// You must also make sure that the returned value does not outlive the - /// guard. - unsafe fn unsafe_coerce(output: Self::Output) -> Self; -} - impl FromValue for T where T: AnyMarker, @@ -261,33 +219,6 @@ where } } -impl FromValue for Mut -where - T: AnyMarker, -{ - #[inline] - fn from_value(value: Value) -> Result { - value.into_mut() - } -} - -impl FromValue for Ref -where - T: AnyMarker, -{ - #[inline] - fn from_value(value: Value) -> Result { - value.into_ref() - } -} - -impl FromValue for AnyObj { - #[inline] - fn from_value(value: Value) -> Result { - value.into_any_obj() - } -} - impl FromValue for Value { #[inline] fn from_value(value: Value) -> Result { @@ -310,11 +241,11 @@ where } } -impl FromValue for ::rust_alloc::string::String { +impl FromValue for rust_alloc::string::String { #[inline] fn from_value(value: Value) -> Result { let string = String::from_value(value)?; - let string = ::rust_alloc::string::String::from(string); + let string = rust_alloc::string::String::from(string); Ok(string) } } @@ -328,12 +259,11 @@ impl FromValue for alloc::Box { } } -#[cfg(feature = "alloc")] -impl FromValue for ::rust_alloc::boxed::Box { +impl FromValue for rust_alloc::boxed::Box { #[inline] fn from_value(value: Value) -> Result { let string = value.borrow_string_ref()?; - let string = ::rust_alloc::boxed::Box::::from(string.as_ref()); + let string = rust_alloc::boxed::Box::::from(string.as_ref()); Ok(string) } } @@ -388,13 +318,6 @@ impl FromValue for bool { } } -impl FromConstValue for bool { - #[inline] - fn from_const_value(value: ConstValue) -> Result { - value.as_bool() - } -} - impl FromValue for char { #[inline] fn from_value(value: Value) -> Result { @@ -402,13 +325,6 @@ impl FromValue for char { } } -impl FromConstValue for char { - #[inline] - fn from_const_value(value: ConstValue) -> Result { - value.as_char() - } -} - macro_rules! impl_integer { ($($ty:ty),* $(,)?) => { $( @@ -418,13 +334,6 @@ macro_rules! impl_integer { value.as_integer() } } - - impl FromConstValue for $ty { - #[inline] - fn from_const_value(value: ConstValue) -> Result { - value.as_integer() - } - } )* }; } @@ -470,7 +379,7 @@ cfg_std! { } impl_map!(::std::collections::HashMap, String); - impl_map!(::std::collections::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::string::String); + impl_map!(::std::collections::HashMap, rust_alloc::string::String); } macro_rules! impl_try_map { @@ -497,8 +406,7 @@ macro_rules! impl_try_map { } impl_try_map!(alloc::HashMap, String); -#[cfg(feature = "alloc")] -impl_try_map!(alloc::HashMap<::rust_alloc::string::String, T>, ::rust_alloc::string::String); +impl_try_map!(alloc::HashMap, rust_alloc::string::String); impl FromValue for Ordering { #[inline] diff --git a/crates/rune/src/runtime/function.rs b/crates/rune/src/runtime/function.rs index 6c35f371c..592c591b2 100644 --- a/crates/rune/src/runtime/function.rs +++ b/crates/rune/src/runtime/function.rs @@ -1,7 +1,7 @@ use core::fmt; use core::future::Future; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc::fmt::TryWrite; @@ -11,13 +11,12 @@ use crate::function; use crate::runtime; use crate::runtime::vm::Isolated; use crate::shared::AssertSend; -use crate::Any; -use crate::Hash; +use crate::{Any, Hash}; use super::{ - Args, Call, ConstValue, Dynamic, Formatter, FromValue, FunctionHandler, GuardedArgs, - InstAddress, Output, OwnedTuple, Rtti, RuntimeContext, RuntimeError, Stack, Unit, Value, Vm, - VmCall, VmErrorKind, VmHalt, VmResult, + Address, AnySequence, Args, Call, ConstValue, Formatter, FromValue, FunctionHandler, + GuardedArgs, Output, OwnedTuple, Rtti, RuntimeContext, RuntimeError, Stack, Unit, Value, Vm, + VmCall, VmError, VmErrorKind, VmHalt, }; /// The type of a function in Rune. @@ -71,7 +70,7 @@ impl Function { /// let unit = rune::prepare(&mut sources).build()?; /// let mut vm = Vm::without_runtime(Arc::new(unit)); /// - /// let function = Function::new(|value: u32| value + 1); + /// let function = Function::new(|value: u32| value + 1)?; /// /// assert_eq!(function.type_hash(), Hash::EMPTY); /// @@ -100,7 +99,7 @@ impl Function { /// let unit = rune::prepare(&mut sources).build()?; /// let mut vm = Vm::without_runtime(Arc::new(unit)); /// - /// let function = Function::new(|value: u32| async move { value + 1 }); + /// let function = Function::new(|value: u32| async move { value + 1 })?; /// /// assert_eq!(function.type_hash(), Hash::EMPTY); /// @@ -111,43 +110,24 @@ impl Function { /// # })?; /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn new(f: F) -> Self + pub fn new(f: F) -> alloc::Result where F: function::Function, K: function::FunctionKind, { - Self(FunctionImpl { + Ok(Self(FunctionImpl { inner: Inner::FnHandler(FnHandler { - handler: Arc::new(move |stack, addr, args, output| { - f.fn_call(stack, addr, args, output) - }), + handler: FunctionHandler::new(move |stack, addr, args, output| { + f.call(stack, addr, args, output) + })?, hash: Hash::EMPTY, }), - }) - } - - /// See [`Function::new`]. - #[deprecated = "Use Function::new() instead"] - pub fn function(f: F) -> Self - where - F: function::Function, - K: function::FunctionKind, - { - Self::new(f) - } - - /// See [`Function::function`]. - #[deprecated = "Use Function::new() instead"] - pub fn async_function(f: F) -> Self - where - F: function::Function, - { - Self::new(f) + })) } /// Perform an asynchronous call over the function which also implements /// [Send]. - pub async fn async_send_call(&self, args: A) -> VmResult + pub async fn async_send_call(&self, args: A) -> Result where A: Send + GuardedArgs, T: Send + FromValue, @@ -179,10 +159,10 @@ impl Function { /// let value = vm.call(["main"], ())?; /// /// let value: Function = rune::from_value(value)?; - /// assert_eq!(value.call::((1, 2)).into_result()?, 3); + /// assert_eq!(value.call::((1, 2))?, 3); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn call(&self, args: impl GuardedArgs) -> VmResult + pub fn call(&self, args: impl GuardedArgs) -> Result where T: FromValue, { @@ -198,15 +178,15 @@ impl Function { pub(crate) fn call_with_vm( &self, vm: &mut Vm, - addr: InstAddress, + addr: Address, args: usize, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { self.0.call_with_vm(vm, addr, args, out) } /// Create a function pointer from a handler. - pub(crate) fn from_handler(handler: Arc, hash: Hash) -> Self { + pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self { Self(FunctionImpl::from_handler(handler, hash)) } @@ -371,8 +351,8 @@ impl Function { /// assert_eq!(a(), b()); /// ``` #[rune::function(keep, protocol = CLONE)] - fn clone(&self) -> VmResult { - VmResult::Ok(vm_try!(self.try_clone())) + fn clone(&self) -> Result { + Ok(self.try_clone()?) } /// Debug format a function. @@ -387,8 +367,8 @@ impl Function { /// println!("{function:?}"); /// `` #[rune::function(keep, protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{self:?}") + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{self:?}") } } @@ -426,13 +406,13 @@ impl SyncFunction { /// let add = vm.call(["main"], ())?; /// let add: SyncFunction = rune::from_value(add)?; /// - /// let value = add.async_send_call::((1, 2)).await.into_result()?; + /// let value = add.async_send_call::((1, 2)).await?; /// assert_eq!(value, 3); /// # Ok::<_, rune::support::Error>(()) /// # })?; /// # Ok::<_, rune::support::Error>(()) /// ``` - pub async fn async_send_call(&self, args: impl GuardedArgs + Send) -> VmResult + pub async fn async_send_call(&self, args: impl GuardedArgs + Send) -> Result where T: Send + FromValue, { @@ -463,10 +443,10 @@ impl SyncFunction { /// let add = vm.call(["main"], ())?; /// let add: SyncFunction = rune::from_value(add)?; /// - /// assert_eq!(add.call::((1, 2)).into_result()?, 3); + /// assert_eq!(add.call::((1, 2))?, 3); /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn call(&self, args: impl GuardedArgs) -> VmResult + pub fn call(&self, args: impl GuardedArgs) -> Result where T: FromValue, { @@ -535,7 +515,7 @@ where OwnedTuple: TryFrom>, VmErrorKind: From<>>::Error>, { - fn call(&self, args: impl GuardedArgs) -> VmResult + fn call(&self, args: impl GuardedArgs) -> Result where T: FromValue, { @@ -544,54 +524,52 @@ where let count = args.count(); let size = count.max(1); // Ensure we have space for the return value. - let mut stack = vm_try!(Stack::with_capacity(size)); - let _guard = vm_try!(unsafe { args.guarded_into_stack(&mut stack) }); - vm_try!(stack.resize(size)); - vm_try!((handler.handler)( - &mut stack, - InstAddress::ZERO, - count, - InstAddress::ZERO.output() - )); - stack.at(InstAddress::ZERO).clone() - } - Inner::FnOffset(fn_offset) => { - vm_try!(fn_offset.call(args, ())) + let mut stack = Stack::with_capacity(size)?; + let _guard = unsafe { args.guarded_into_stack(&mut stack) }?; + stack.resize(size)?; + handler + .handler + .call(&mut stack, Address::ZERO, count, Address::ZERO.output())?; + stack.at(Address::ZERO).clone() } + Inner::FnOffset(fn_offset) => fn_offset.call(args, ())?, Inner::FnClosureOffset(closure) => { - let environment = vm_try!(closure.environment.try_clone()); - let environment = vm_try!(OwnedTuple::try_from(environment)); - vm_try!(closure.fn_offset.call(args, (environment,))) + let environment = closure.environment.try_clone()?; + let environment = OwnedTuple::try_from(environment)?; + closure.fn_offset.call(args, (environment,))? } Inner::FnUnitStruct(empty) => { - vm_try!(check_args(args.count(), 0)); - vm_try!(Value::empty_struct(empty.rtti.clone())) + check_args(args.count(), 0)?; + Value::empty_struct(empty.rtti.clone())? } Inner::FnTupleStruct(tuple) => { - vm_try!(check_args(args.count(), tuple.args)); + check_args(args.count(), tuple.args)?; // SAFETY: We don't let the guard outlive the value. - let (args, _guard) = vm_try!(unsafe { args.guarded_into_vec() }); - vm_try!(Value::tuple_struct(tuple.rtti.clone(), args)) + let (args, _guard) = unsafe { args.guarded_into_vec()? }; + Value::tuple_struct(tuple.rtti.clone(), args)? } }; - VmResult::Ok(vm_try!(T::from_value(value))) + Ok(T::from_value(value)?) } - fn async_send_call<'a, A, T>(&'a self, args: A) -> impl Future> + Send + 'a + fn async_send_call<'a, A, T>( + &'a self, + args: A, + ) -> impl Future> + Send + 'a where A: 'a + Send + GuardedArgs, T: 'a + Send + FromValue, { let future = async move { - let value: Value = vm_try!(self.call(args)); + let value: Value = self.call(args)?; - let value = match vm_try!(value.try_borrow_mut::()) { - Some(future) => vm_try!(future.await), + let value = match value.try_borrow_mut::()? { + Some(future) => future.await?, None => value, }; - VmResult::Ok(vm_try!(T::from_value(value))) + Ok(T::from_value(value)?) }; // Safety: Future is send because there is no way to call this @@ -610,57 +588,57 @@ where pub(crate) fn call_with_vm( &self, vm: &mut Vm, - addr: InstAddress, + addr: Address, args: usize, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { let reason = match &self.inner { Inner::FnHandler(handler) => { - vm_try!((handler.handler)(vm.stack_mut(), addr, args, out)); + handler.handler.call(vm.stack_mut(), addr, args, out)?; None } Inner::FnOffset(fn_offset) => { - if let Some(vm_call) = vm_try!(fn_offset.call_with_vm(vm, addr, args, (), out)) { - return VmResult::Ok(Some(VmHalt::VmCall(vm_call))); + if let Some(vm_call) = fn_offset.call_with_vm(vm, addr, args, (), out)? { + return Ok(Some(VmHalt::VmCall(vm_call))); } None } Inner::FnClosureOffset(closure) => { - let environment = vm_try!(closure.environment.try_clone()); - let environment = vm_try!(OwnedTuple::try_from(environment)); + let environment = closure.environment.try_clone()?; + let environment = OwnedTuple::try_from(environment)?; if let Some(vm_call) = - vm_try!(closure + closure .fn_offset - .call_with_vm(vm, addr, args, (environment,), out)) + .call_with_vm(vm, addr, args, (environment,), out)? { - return VmResult::Ok(Some(VmHalt::VmCall(vm_call))); + return Ok(Some(VmHalt::VmCall(vm_call))); } None } Inner::FnUnitStruct(empty) => { - vm_try!(check_args(args, 0)); - vm_try!(out.store(vm.stack_mut(), || Value::empty_struct(empty.rtti.clone()))); + check_args(args, 0)?; + out.store(vm.stack_mut(), || Value::empty_struct(empty.rtti.clone()))?; None } Inner::FnTupleStruct(tuple) => { - vm_try!(check_args(args, tuple.args)); + check_args(args, tuple.args)?; - let seq = vm_try!(vm.stack().slice_at(addr, args)); + let seq = vm.stack().slice_at(addr, args)?; let data = seq.iter().cloned(); - let value = vm_try!(Dynamic::new(tuple.rtti.clone(), data)); - vm_try!(out.store(vm.stack_mut(), value)); + let value = AnySequence::new(tuple.rtti.clone(), data)?; + out.store(vm.stack_mut(), value)?; None } }; - VmResult::Ok(reason) + Ok(reason) } /// Create a function pointer from a handler. - pub(crate) fn from_handler(handler: Arc, hash: Hash) -> Self { + pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self { Self { inner: Inner::FnHandler(FnHandler { handler, hash }), } @@ -769,7 +747,7 @@ impl fmt::Debug for Function { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0.inner { Inner::FnHandler(handler) => { - write!(f, "native function ({:p})", handler.handler.as_ref())?; + write!(f, "native function ({:p})", handler.handler)?; } Inner::FnOffset(offset) => { write!(f, "{} function (at: 0x{:x})", offset.call, offset.offset)?; @@ -832,7 +810,7 @@ where #[derive(Clone, TryClone)] struct FnHandler { /// The function handler. - handler: Arc, + handler: FunctionHandler, /// Hash for the function type hash: Hash, } @@ -861,17 +839,14 @@ struct FnOffset { impl FnOffset { /// Perform a call into the specified offset and return the produced value. #[tracing::instrument(skip_all, fields(args = args.count(), extra = extra.count(), ?self.offset, ?self.call, ?self.args, ?self.hash))] - fn call(&self, args: impl GuardedArgs, extra: impl Args) -> VmResult { - vm_try!(check_args( - args.count().wrapping_add(extra.count()), - self.args - )); + fn call(&self, args: impl GuardedArgs, extra: impl Args) -> Result { + check_args(args.count().wrapping_add(extra.count()), self.args)?; let mut vm = Vm::new(self.context.clone(), self.unit.clone()); vm.set_ip(self.offset); - let _guard = vm_try!(unsafe { args.guarded_into_stack(vm.stack_mut()) }); - vm_try!(extra.into_stack(vm.stack_mut())); + let _guard = unsafe { args.guarded_into_stack(vm.stack_mut())? }; + extra.into_stack(vm.stack_mut())?; self.call.call_with_vm(vm) } @@ -884,32 +859,34 @@ impl FnOffset { fn call_with_vm( &self, vm: &mut Vm, - addr: InstAddress, + addr: Address, args: usize, extra: impl Args, out: Output, - ) -> VmResult> { - vm_try!(check_args(args.wrapping_add(extra.count()), self.args)); + ) -> Result, VmError> { + check_args(args.wrapping_add(extra.count()), self.args)?; let same_unit = matches!(self.call, Call::Immediate if vm.is_same_unit(&self.unit)); let same_context = matches!(self.call, Call::Immediate if vm.is_same_context(&self.context)); - vm_try!(vm.push_call_frame(self.offset, addr, args, Isolated::new(!same_context), out)); - vm_try!(extra.into_stack(vm.stack_mut())); + vm.push_call_frame(self.offset, addr, args, Isolated::new(!same_context), out)?; + extra.into_stack(vm.stack_mut())?; // Fast path, just allocate a call frame and keep running. if same_context && same_unit { tracing::trace!("same context and unit"); - return VmResult::Ok(None); + return Ok(None); } - VmResult::Ok(Some(VmCall::new( + let call = VmCall::new( self.call, (!same_context).then(|| self.context.clone()), (!same_unit).then(|| self.unit.clone()), out, - ))) + ); + + Ok(Some(call)) } } @@ -967,10 +944,14 @@ impl FromValue for SyncFunction { } } -fn check_args(actual: usize, expected: usize) -> VmResult<()> { +#[inline] +fn check_args(actual: usize, expected: usize) -> Result<(), VmError> { if actual != expected { - return VmResult::err(VmErrorKind::BadArgumentCount { expected, actual }); + return Err(VmError::new(VmErrorKind::BadArgumentCount { + expected, + actual, + })); } - VmResult::Ok(()) + Ok(()) } diff --git a/crates/rune/src/runtime/function_handler.rs b/crates/rune/src/runtime/function_handler.rs new file mode 100644 index 000000000..cfe99f1d6 --- /dev/null +++ b/crates/rune/src/runtime/function_handler.rs @@ -0,0 +1,132 @@ +use core::fmt; +use core::mem::ManuallyDrop; +use core::ptr::NonNull; + +use crate::alloc; +use crate::alloc::alloc::Global; +use crate::alloc::clone::TryClone; +use crate::alloc::sync::Arc; +use crate::runtime::{Address, Memory, Output, VmError}; + +/// The vtable for a function handler. +struct FunctionHandlerVTable { + call: unsafe fn(ptr: *const (), &mut dyn Memory, Address, usize, Output) -> Result<(), VmError>, + drop: unsafe fn(ptr: *const ()), + clone: unsafe fn(ptr: *const ()) -> *const (), +} + +/// A raw function handler in the rune virtual machine. +pub struct FunctionHandler { + ptr: NonNull<()>, + vtable: &'static FunctionHandlerVTable, +} + +impl FunctionHandler { + #[inline] + pub(crate) fn new(f: F) -> alloc::Result + where + F: Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError> + + Send + + Sync + + 'static, + { + let arc = Arc::try_new(f)?; + let (ptr, Global) = Arc::into_raw_with_allocator(arc); + let ptr = unsafe { NonNull::new_unchecked(ptr.cast_mut().cast()) }; + let vtable = &FunctionHandlerVTable { + call: call_impl::, + drop: drop_impl::, + clone: clone_impl::, + }; + + Ok(Self { ptr, vtable }) + } + + /// Call the function handler through the raw type-erased API. + #[inline] + pub fn call( + &self, + memory: &mut dyn Memory, + addr: Address, + count: usize, + out: Output, + ) -> Result<(), VmError> { + // SAFETY: The pointer is guaranteed to be valid and the vtable is static. + unsafe { (self.vtable.call)(self.ptr.as_ptr().cast_const(), memory, addr, count, out) } + } +} + +unsafe impl Send for FunctionHandler {} +unsafe impl Sync for FunctionHandler {} + +impl Drop for FunctionHandler { + #[inline] + fn drop(&mut self) { + // SAFETY: The pointer is guaranteed to be valid and the vtable is static. + unsafe { (self.vtable.drop)(self.ptr.as_ptr().cast_const()) } + } +} + +fn call_impl( + ptr: *const (), + memory: &mut dyn Memory, + addr: Address, + count: usize, + out: Output, +) -> Result<(), VmError> +where + F: Fn(&mut dyn Memory, Address, usize, Output) -> Result<(), VmError> + Send + Sync + 'static, +{ + // SAFETY: We've ensured the interior value is a valid pointer to `F` due to construction. + unsafe { (*ptr.cast::())(memory, addr, count, out) } +} + +fn clone_impl(ptr: *const ()) -> *const () { + // SAFETY: We've ensured the interior value is a valid pointer to `F` due to construction. + unsafe { + let ptr = ptr.cast::(); + // Prevent the constructed Arc from being dropped, which would decrease + // its reference count. + let arc = ManuallyDrop::new(Arc::::from_raw_in(ptr, Global)); + let arc = (*arc).clone(); + let (ptr, Global) = Arc::into_raw_with_allocator(arc); + ptr.cast() + } +} + +fn drop_impl(ptr: *const ()) { + // SAFETY: We've ensured the interior value is a valid pointer to `F` due to construction. + unsafe { + let ptr = ptr.cast::(); + drop(Arc::::from_raw_in(ptr, Global)); + } +} + +impl Clone for FunctionHandler { + #[inline] + fn clone(&self) -> Self { + // SAFETY: The pointer is valid and the vtable is static. + let ptr = unsafe { + NonNull::new_unchecked((self.vtable.clone)(self.ptr.as_ptr().cast_const()).cast_mut()) + }; + + Self { + ptr, + vtable: self.vtable, + } + } +} + +impl TryClone for FunctionHandler { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(self.clone()) + } +} + +impl fmt::Pointer for FunctionHandler { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&self.ptr, f) + } +} diff --git a/crates/rune/src/runtime/future.rs b/crates/rune/src/runtime/future.rs index 486603965..7f0ac51d4 100644 --- a/crates/rune/src/runtime/future.rs +++ b/crates/rune/src/runtime/future.rs @@ -6,14 +6,14 @@ use core::task::{Context, Poll}; use crate::alloc::alloc::Global; use crate::alloc::{self, Box}; -use crate::runtime::{ToValue, Value, VmErrorKind, VmResult}; +use crate::runtime::{ToValue, Value, VmError, VmErrorKind}; use crate::Any; use pin_project::pin_project; /// A virtual table for a type-erased future. struct Vtable { - poll: unsafe fn(*mut (), cx: &mut Context<'_>) -> Poll>, + poll: unsafe fn(*mut (), cx: &mut Context<'_>) -> Poll>, drop: unsafe fn(*mut ()), } @@ -31,7 +31,7 @@ impl Future { /// Construct a new wrapped future. pub(crate) fn new(future: T) -> alloc::Result where - T: 'static + future::Future>, + T: 'static + future::Future>, O: ToValue, { let (future, Global) = Box::into_raw_with_allocator(Box::try_new(future)?); @@ -44,11 +44,13 @@ impl Future { poll: |future, cx| unsafe { match Pin::new_unchecked(&mut *future.cast::()).poll(cx) { Poll::Pending => Poll::Pending, - Poll::Ready(VmResult::Ok(result)) => match result.to_value() { - Ok(value) => Poll::Ready(VmResult::Ok(value)), - Err(err) => Poll::Ready(VmResult::Err(err.into())), + Poll::Ready(result) => match result { + Ok(result) => match result.to_value() { + Ok(value) => Poll::Ready(Ok(value)), + Err(err) => Poll::Ready(Err(err.into())), + }, + Err(err) => Poll::Ready(Err(err)), }, - Poll::Ready(VmResult::Err(err)) => Poll::Ready(VmResult::Err(err)), } }, drop: |future| unsafe { @@ -67,14 +69,14 @@ impl Future { } impl future::Future for Future { - type Output = VmResult; + type Output = Result; - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { unsafe { let this = self.get_unchecked_mut(); let Some(future) = this.future else { - return Poll::Ready(VmResult::err(VmErrorKind::FutureCompleted)); + return Poll::Ready(Err(VmError::new(VmErrorKind::FutureCompleted))); }; match (this.vtable.poll)(future.as_ptr(), cx) { @@ -125,9 +127,9 @@ impl SelectFuture { impl future::Future for SelectFuture where T: Copy, - F: future::Future>, + F: future::Future>, { - type Output = VmResult<(T, Value)>; + type Output = Result<(T, Value), VmError>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); @@ -135,8 +137,8 @@ where match result { Poll::Ready(result) => match result { - VmResult::Ok(value) => Poll::Ready(VmResult::Ok((*this.data, value))), - VmResult::Err(error) => Poll::Ready(VmResult::Err(error)), + Ok(value) => Poll::Ready(Ok((*this.data, value))), + Err(error) => Poll::Ready(Err(error)), }, Poll::Pending => Poll::Pending, } diff --git a/crates/rune/src/runtime/generator.rs b/crates/rune/src/runtime/generator.rs index dc9ee71fd..0e9ae9745 100644 --- a/crates/rune/src/runtime/generator.rs +++ b/crates/rune/src/runtime/generator.rs @@ -3,7 +3,9 @@ use core::iter; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{GeneratorState, Value, Vm, VmError, VmErrorKind, VmExecution, VmResult}; +use crate::runtime::{ + GeneratorState, Value, Vm, VmError, VmErrorKind, VmExecution, VmHaltInfo, VmOutcome, +}; use crate::Any; /// A generator produced by a generator function. @@ -25,80 +27,57 @@ use crate::Any; /// assert!(g is Generator); /// ``` #[derive(Any)] -#[rune(crate, impl_params = [Vm], item = ::std::ops::generator)] -pub struct Generator -where - T: AsRef + AsMut, -{ - execution: Option>, +#[rune(crate, item = ::std::ops::generator)] +pub struct Generator { + execution: Option>, } -impl Generator -where - T: AsRef + AsMut, -{ +impl Generator { /// Construct a generator from a virtual machine. - pub(crate) fn new(vm: T) -> Self { + pub(crate) fn new(vm: Vm) -> Self { Self { execution: Some(VmExecution::new(vm)), } } - /// Construct a generator from a complete execution. - pub(crate) fn from_execution(execution: VmExecution) -> Self { - Self { - execution: Some(execution), - } - } - /// Get the next value produced by this stream. - #[allow(clippy::should_implement_trait)] - pub fn next(&mut self) -> VmResult> { + pub fn next(&mut self) -> Result, VmError> { let Some(execution) = self.execution.as_mut() else { - return VmResult::Ok(None); + return Ok(None); }; - let state = if execution.is_resumed() { - vm_try!(execution.resume_with(Value::empty())) - } else { - vm_try!(execution.resume()) - }; + let state = execution.resume().complete()?; - VmResult::Ok(match state { - GeneratorState::Yielded(value) => Some(value), - GeneratorState::Complete(_) => { + match state { + VmOutcome::Complete(_) => { self.execution = None; - None + Ok(None) } - }) + VmOutcome::Yielded(value) => Ok(Some(value)), + VmOutcome::Limited => Err(VmError::from(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } } - /// Resume the generator with a value and get the next generator state. - pub fn resume(&mut self, value: Value) -> VmResult { - let execution = vm_try!(self + /// Resume the generator with a value and get the next [`GeneratorState`]. + pub fn resume(&mut self, value: Value) -> Result { + let execution = self .execution .as_mut() - .ok_or(VmErrorKind::GeneratorComplete)); + .ok_or(VmErrorKind::GeneratorComplete)?; - let state = if execution.is_resumed() { - vm_try!(execution.resume_with(value)) - } else { - vm_try!(execution.resume()) - }; - - if state.is_complete() { - self.execution = None; - } - - VmResult::Ok(state) - } -} + let outcome = execution.resume().with_value(value).complete()?; -impl Generator<&mut Vm> { - /// Convert the current generator into one which owns its virtual machine. - pub fn into_owned(self) -> Generator { - Generator { - execution: self.execution.map(|e| e.into_owned()), + match outcome { + VmOutcome::Complete(value) => { + self.execution = None; + Ok(GeneratorState::Complete(value)) + } + VmOutcome::Yielded(value) => Ok(GeneratorState::Yielded(value)), + VmOutcome::Limited => Err(VmError::from(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), } } } @@ -128,7 +107,7 @@ pub struct Iter { impl Iter { #[rune::function(instance, keep, protocol = NEXT)] - pub(crate) fn next(&mut self) -> VmResult> { + pub(crate) fn next(&mut self) -> Result, VmError> { self.generator.next() } } @@ -139,17 +118,14 @@ impl iter::Iterator for Iter { #[inline] fn next(&mut self) -> Option> { match Iter::next(self) { - VmResult::Ok(Some(value)) => Some(Ok(value)), - VmResult::Ok(None) => None, - VmResult::Err(error) => Some(Err(error)), + Ok(Some(value)) => Some(Ok(value)), + Ok(None) => None, + Err(error) => Some(Err(error)), } } } -impl fmt::Debug for Generator -where - T: AsRef + AsMut, -{ +impl fmt::Debug for Generator { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Generator") .field("completed", &self.execution.is_none()) @@ -157,10 +133,7 @@ where } } -impl TryClone for Generator -where - T: TryClone + AsRef + AsMut, -{ +impl TryClone for Generator { #[inline] fn try_clone(&self) -> Result { Ok(Self { diff --git a/crates/rune/src/runtime/generator_state.rs b/crates/rune/src/runtime/generator_state.rs index cb6c90320..9488a5f3d 100644 --- a/crates/rune/src/runtime/generator_state.rs +++ b/crates/rune/src/runtime/generator_state.rs @@ -1,15 +1,19 @@ use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{ProtocolCaller, Value, VmResult}; use crate::Any; +use super::{ProtocolCaller, Value, VmError}; + /// The state of a generator. /// +/// # Examples +/// /// ``` -/// use rune::{Value, Vm}; -/// use rune::runtime::{Generator, GeneratorState}; /// use std::sync::Arc; /// +/// use rune::{Value, Vm}; +/// use rune::runtime::GeneratorState; +/// /// let mut sources = rune::sources! { /// entry => { /// pub fn main() { @@ -23,10 +27,10 @@ use crate::Any; /// let unit = rune::prepare(&mut sources).build()?; /// /// let mut vm = Vm::without_runtime(Arc::new(unit)); -/// let mut execution = vm.execute(["main"], ())?; +/// let mut generator = vm.execute(["main"], ())?.into_generator(); /// /// // Initial resume doesn't take a value. -/// let first = match execution.resume().into_result()? { +/// let first = match generator.resume(Value::empty())? { /// GeneratorState::Yielded(first) => rune::from_value::(first)?, /// GeneratorState::Complete(..) => panic!("generator completed"), /// }; @@ -34,14 +38,14 @@ use crate::Any; /// assert_eq!(first, 1); /// /// // Additional resumes require a value. -/// let second = match execution.resume_with(rune::to_value(2i64)?).into_result()? { +/// let second = match generator.resume(rune::to_value(2i64)?)? { /// GeneratorState::Yielded(second) => rune::from_value::(second)?, /// GeneratorState::Complete(..) => panic!("generator completed"), /// }; /// /// assert_eq!(second, 3); /// -/// let ret = match execution.resume_with(rune::to_value(42i64)?).into_result()? { +/// let ret = match generator.resume(rune::to_value(42i64)?)? { /// GeneratorState::Complete(ret) => rune::from_value::(ret)?, /// GeneratorState::Yielded(..) => panic!("generator yielded"), /// }; @@ -49,6 +53,57 @@ use crate::Any; /// assert_eq!(ret, 42); /// # Ok::<_, rune::support::Error>(()) /// ``` +/// +/// An asynchronous generator, also known as a stream: +/// +/// ``` +/// use std::sync::Arc; +/// +/// use rune::{Value, Vm}; +/// use rune::runtime::GeneratorState; +/// +/// let mut sources = rune::sources! { +/// entry => { +/// pub async fn main() { +/// let n = yield 1; +/// let out = yield n + 1; +/// out +/// } +/// } +/// }; +/// +/// # futures_executor::block_on(async move { +/// let unit = rune::prepare(&mut sources).build()?; +/// +/// let mut vm = Vm::without_runtime(Arc::new(unit)); +/// let mut stream = vm.execute(["main"], ())?.into_stream(); +/// +/// // Initial resume doesn't take a value. +/// let first = match stream.resume(Value::empty()).await? { +/// GeneratorState::Yielded(first) => rune::from_value::(first)?, +/// GeneratorState::Complete(..) => panic!("stream completed"), +/// }; +/// +/// assert_eq!(first, 1); +/// +/// // Additional resumes require a value. +/// let second = match stream.resume(rune::to_value(2i64)?).await? { +/// GeneratorState::Yielded(second) => rune::from_value::(second)?, +/// GeneratorState::Complete(..) => panic!("stream completed"), +/// }; +/// +/// assert_eq!(second, 3); +/// +/// let ret = match stream.resume(rune::to_value(42i64)?).await? { +/// GeneratorState::Complete(ret) => rune::from_value::(ret)?, +/// GeneratorState::Yielded(..) => panic!("stream yielded"), +/// }; +/// +/// assert_eq!(ret, 42); +/// # Ok::<_, rune::support::Error>(()) +/// # })?; +/// # Ok::<_, rune::support::Error>(()) +/// ``` #[derive(Any, Debug, TryClone)] #[rune(item = ::std::ops::generator)] pub enum GeneratorState { @@ -75,7 +130,7 @@ impl GeneratorState { &self, other: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { match (self, other) { (GeneratorState::Yielded(a), GeneratorState::Yielded(b)) => { Value::partial_eq_with(a, b, caller) @@ -83,11 +138,15 @@ impl GeneratorState { (GeneratorState::Complete(a), GeneratorState::Complete(b)) => { Value::partial_eq_with(a, b, caller) } - _ => VmResult::Ok(false), + _ => Ok(false), } } - pub(crate) fn eq_with(&self, other: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn eq_with( + &self, + other: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { match (self, other) { (GeneratorState::Yielded(a), GeneratorState::Yielded(b)) => { Value::eq_with(a, b, caller) @@ -95,7 +154,7 @@ impl GeneratorState { (GeneratorState::Complete(a), GeneratorState::Complete(b)) => { Value::eq_with(a, b, caller) } - _ => VmResult::Ok(false), + _ => Ok(false), } } } diff --git a/crates/rune/src/runtime/guarded_args.rs b/crates/rune/src/runtime/guarded_args.rs index d6864e506..67cfd2cd0 100644 --- a/crates/rune/src/runtime/guarded_args.rs +++ b/crates/rune/src/runtime/guarded_args.rs @@ -1,6 +1,6 @@ use crate::alloc::Vec; use crate::runtime::Args; -use crate::runtime::{Stack, UnsafeToValue, Value, VmResult}; +use crate::runtime::{Stack, UnsafeToValue, Value, VmError}; /// Trait for converting arguments onto the stack. /// @@ -18,7 +18,7 @@ pub trait GuardedArgs { /// This can encode references onto the stack. The caller must ensure that /// the guard is dropped before any references which have been encoded are /// no longer alive. - unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult; + unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result; /// Encode arguments into a vector. /// @@ -27,7 +27,7 @@ pub trait GuardedArgs { /// This can encode references into the vector. The caller must ensure that /// the guard is dropped before any references which have been encoded are /// no longer alive. - unsafe fn guarded_into_vec(self) -> VmResult<(Vec, Self::Guard)>; + unsafe fn guarded_into_vec(self) -> Result<(Vec, Self::Guard), VmError>; /// The number of arguments. fn count(&self) -> usize; @@ -43,21 +43,21 @@ macro_rules! impl_into_args { #[allow(unused)] #[inline] - unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult { + unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result { let ($($value,)*) = self; - $(let $value = vm_try!($value.unsafe_to_value());)* - $(vm_try!(stack.push($value.0));)* - VmResult::Ok(($($value.1,)*)) + $(let $value = $value.unsafe_to_value()?;)* + $(stack.push($value.0)?;)* + Ok(($($value.1,)*)) } #[allow(unused)] #[inline] - unsafe fn guarded_into_vec(self) -> VmResult<(Vec, Self::Guard)> { + unsafe fn guarded_into_vec(self) -> Result<(Vec, Self::Guard), VmError> { let ($($value,)*) = self; - $(let $value = vm_try!($value.unsafe_to_value());)* - let mut out = vm_try!(Vec::try_with_capacity($count)); - $(vm_try!(out.try_push($value.0));)* - VmResult::Ok((out, ($($value.1,)*))) + $(let $value = $value.unsafe_to_value()?;)* + let mut out = Vec::try_with_capacity($count)?; + $(out.try_push($value.0)?;)* + Ok((out, ($($value.1,)*))) } #[inline] @@ -74,13 +74,13 @@ impl GuardedArgs for Vec { type Guard = (); #[inline] - unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult { + unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result { self.into_stack(stack) } #[inline] - unsafe fn guarded_into_vec(self) -> VmResult<(Vec, Self::Guard)> { - VmResult::Ok((self, ())) + unsafe fn guarded_into_vec(self) -> Result<(Vec, Self::Guard), VmError> { + Ok((self, ())) } #[inline] @@ -89,18 +89,17 @@ impl GuardedArgs for Vec { } } -#[cfg(feature = "alloc")] -impl GuardedArgs for ::rust_alloc::vec::Vec { +impl GuardedArgs for rust_alloc::vec::Vec { type Guard = (); #[inline] - unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult { + unsafe fn guarded_into_stack(self, stack: &mut Stack) -> Result { self.into_stack(stack) } #[inline] - unsafe fn guarded_into_vec(self) -> VmResult<(Vec, Self::Guard)> { - VmResult::Ok((vm_try!(Vec::try_from(self)), ())) + unsafe fn guarded_into_vec(self) -> Result<(Vec, Self::Guard), VmError> { + Ok((Vec::try_from(self)?, ())) } #[inline] diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index c84d78059..6c6f53491 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -1,39 +1,75 @@ use core::cmp::Ordering; use core::fmt; +#[cfg(feature = "musli")] use musli::{Decode, Encode}; use rune_macros::InstDisplay; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; +use crate::alloc; use crate::alloc::prelude::*; use crate::Hash; use super::{Call, FormatSpec, Memory, RuntimeError, Type, Value}; +/// An instruction in the virtual machine. +#[derive(Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] +pub struct Inst { + pub(crate) kind: Kind, +} + +impl Inst { + #[inline] + pub(crate) fn new(kind: Kind) -> Self { + Self { kind } + } +} + +impl fmt::Display for Inst { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.kind.fmt(fmt) + } +} + +impl fmt::Debug for Inst { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.kind.fmt(fmt) + } +} + +impl TryClone for Inst { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(Self { + kind: self.kind.try_clone()?, + }) + } +} + /// Pre-canned panic reasons. /// /// To formulate a custom reason, use /// [`VmError::panic`][crate::runtime::VmError::panic]. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -#[non_exhaustive] -pub enum PanicReason { - /// Not implemented. - NotImplemented, +pub(crate) enum PanicReason { /// A pattern didn't match where it unconditionally has to. UnmatchedPattern, - /// Tried to poll a future that has already been completed. - FutureCompleted, } impl PanicReason { /// The identifier of the panic. fn ident(&self) -> &'static str { match *self { - Self::NotImplemented => "not implemented", Self::UnmatchedPattern => "unmatched pattern", - Self::FutureCompleted => "future completed", } } } @@ -41,11 +77,7 @@ impl PanicReason { impl fmt::Display for PanicReason { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - Self::NotImplemented => write!(fmt, "functionality has not been implemented yet")?, Self::UnmatchedPattern => write!(fmt, "pattern did not match")?, - Self::FutureCompleted => { - write!(fmt, "tried to poll future that has already been completed")? - } } Ok(()) @@ -53,10 +85,11 @@ impl fmt::Display for PanicReason { } /// Type checks for built-in types. -#[derive(Debug, TryClone, Clone, Copy, PartialEq, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -#[non_exhaustive] -pub enum TypeCheck { +pub(crate) enum TypeCheck { /// Matches a unit type. Unit, /// Matches an anonymous tuple. @@ -68,6 +101,7 @@ pub enum TypeCheck { } impl fmt::Display for TypeCheck { + #[inline] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Unit => write!(fmt, "Unit"), @@ -78,10 +112,12 @@ impl fmt::Display for TypeCheck { } } -/// An operation in the stack-based virtual machine. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode, InstDisplay)] +/// The kind of an instruction in the virtual machine. +#[derive(Debug, TryClone, Clone, Copy, InstDisplay)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum Inst { +pub(crate) enum Kind { /// Make sure that the memory region has `size` slots of memory available. Allocate { /// The size of the memory region to allocate. @@ -98,7 +134,7 @@ pub enum Inst { /// ``` Not { /// The operand to negate. - addr: InstAddress, + addr: Address, /// Whether the produced value from the not should be kept or not. out: Output, }, @@ -112,7 +148,7 @@ pub enum Inst { /// ``` Neg { /// The operand to negate. - addr: InstAddress, + addr: Address, /// Whether the produced value from the negation should be kept or not. out: Output, }, @@ -125,12 +161,12 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Closure { /// The hash of the internally stored closure function. hash: Hash, /// Where to load captured values from. - addr: InstAddress, + addr: Address, /// The number of captured values to store in the environment. count: usize, /// Where to store the produced closure. @@ -140,14 +176,14 @@ pub enum Inst { /// /// It will construct a new stack frame which includes the last `args` /// number of entries. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] CallOffset { /// The offset of the function being called in the same unit. offset: usize, /// The calling convention to use. call: Call, /// The address where the arguments are stored. - addr: InstAddress, + addr: Address, /// The number of arguments passed in at `addr`. args: usize, /// Whether the return value should be kept or not. @@ -160,12 +196,12 @@ pub enum Inst { /// determines the number of arguments. The arguments will be dropped. /// /// The return value of the function call will be written to `out`. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Call { /// The hash of the function to call. hash: Hash, /// The address of the arguments being passed. - addr: InstAddress, + addr: Address, /// The number of arguments passed in at `addr`. args: usize, /// Whether the return value should be kept or not. @@ -177,12 +213,12 @@ pub enum Inst { /// The number of arguments specified should include this object. /// /// The return value of the function call will be written to `out`. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] CallAssociated { /// The hash of the name of the function to call. hash: Hash, /// The address of arguments being passed. - addr: InstAddress, + addr: Address, /// The number of arguments passed in at `addr`. args: usize, /// Whether the return value should be kept or not. @@ -191,10 +227,10 @@ pub enum Inst { /// Look up an instance function. /// /// The instance being used is stored at `addr`, and the function hash to look up is `hash`. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] LoadInstanceFn { /// The address of the instance for which the function is being loaded. - addr: InstAddress, + addr: Address, /// The name hash of the instance function. hash: Hash, /// Where to store the loaded instance function. @@ -209,12 +245,12 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] CallFn { /// The address of the function being called. - function: InstAddress, + function: Address, /// The address of the arguments being passed. - addr: InstAddress, + addr: Address, /// The number of arguments passed in at `addr`. args: usize, /// Whether the returned value from calling the function should be kept @@ -230,12 +266,12 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] IndexGet { /// How the target is addressed. - target: InstAddress, + target: Address, /// How the index is addressed. - index: InstAddress, + index: Address, /// Whether the produced value should be kept or not. out: Output, }, @@ -248,14 +284,14 @@ pub enum Inst { /// /// => *nothing* /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] TupleIndexSet { /// The object being assigned to. - target: InstAddress, + target: Address, /// The index to set. index: usize, /// The value being assigned. - value: InstAddress, + value: Address, }, /// Get the given index out of a tuple from the given variable slot. /// Errors if the item doesn't exist or the item is not a tuple. @@ -265,10 +301,10 @@ pub enum Inst { /// ```text /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] TupleIndexGetAt { /// The address where the tuple we are getting from is stored. - addr: InstAddress, + addr: Address, /// The index to fetch. index: usize, /// Whether the produced value should be kept or not. @@ -287,14 +323,14 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] ObjectIndexSet { /// The object being assigned to. - target: InstAddress, + target: Address, /// The static string slot corresponding to the index to set. slot: usize, /// The value being assigned. - value: InstAddress, + value: Address, }, /// Get the given index out of an object from the given variable slot. /// Errors if the item doesn't exist or the item is not an object. @@ -307,10 +343,10 @@ pub enum Inst { /// ```text /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] ObjectIndexGetAt { /// The address where the object is stored. - addr: InstAddress, + addr: Address, /// The static string slot corresponding to the index to fetch. slot: usize, /// Where to store the fetched value. @@ -328,11 +364,11 @@ pub enum Inst { /// ``` IndexSet { /// The object being assigned to. - target: InstAddress, + target: Address, /// The index to set. - index: InstAddress, + index: Address, /// The value being assigned. - value: InstAddress, + value: Address, }, /// Await the future that is on the stack and push the value that it /// produces. @@ -345,7 +381,7 @@ pub enum Inst { /// ``` Await { /// Address of the future being awaited. - addr: InstAddress, + addr: Address, /// Whether the produced value from the await should be kept or not. out: Output, }, @@ -357,10 +393,10 @@ pub enum Inst { /// /// Will also store the output if the future into `value`. If no branch /// matched, the empty value will be stored. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Select { /// The base address of futures being waited on. - addr: InstAddress, + addr: Address, /// The number of futures to poll. len: usize, /// Where to store the value produced by the future that completed. @@ -373,7 +409,7 @@ pub enum Inst { /// ```text /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] LoadFn { /// The hash of the function to push. hash: Hash, @@ -387,7 +423,7 @@ pub enum Inst { /// ```text /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Store { /// The value to push. value: InstValue, @@ -398,45 +434,45 @@ pub enum Inst { /// frame. /// /// A copy is very cheap. It simply means pushing a reference to the stack. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Copy { /// Address of the value being copied. - addr: InstAddress, + addr: Address, /// Where the value is being copied to. out: Output, }, /// Move a variable from a location `offset` relative to the current call /// frame. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Move { /// Address of the value being moved. - addr: InstAddress, + addr: Address, /// Where the value is being moved to. out: Output, }, /// Drop the given value set. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Drop { /// An indicator of the set of addresses to drop. set: usize, }, /// Swap two values on the stack using their offsets relative to the current /// stack frame. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Swap { /// Offset to the first value. - a: InstAddress, + a: Address, /// Offset to the second value. - b: InstAddress, + b: Address, }, /// Pop the current stack frame and restore the instruction pointer from it. /// /// The stack frame will be cleared, and the value on the top of the stack /// will be left on top of it. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Return { /// The address of the value to return. - addr: InstAddress, + addr: Address, }, /// Pop the current stack frame and restore the instruction pointer from it. /// @@ -452,7 +488,7 @@ pub enum Inst { /// *nothing* /// => *nothing* /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Jump { /// Offset to jump to. jump: usize, @@ -466,10 +502,10 @@ pub enum Inst { /// /// => *nothing* /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] JumpIf { /// The address of the condition for the jump. - cond: InstAddress, + cond: Address, /// Offset to jump to. jump: usize, }, @@ -481,10 +517,10 @@ pub enum Inst { /// /// => *noop* /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] JumpIfNot { /// The address of the condition for the jump. - cond: InstAddress, + cond: Address, /// The offset to jump if the condition is true. jump: usize, }, @@ -492,10 +528,10 @@ pub enum Inst { /// `addr`. /// /// The values at `addr` are dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Vec { /// Where the arguments to the vector are stored. - addr: InstAddress, + addr: Address, /// The number of elements in the vector. count: usize, /// Where to store the produced vector. @@ -505,11 +541,11 @@ pub enum Inst { /// elements from `addr`. /// /// The values at `addr` are not dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Tuple1 { /// Tuple arguments. #[inst_display(display_with = DisplayArray::new)] - addr: [InstAddress; 1], + addr: [Address; 1], /// Where to store the produced tuple. out: Output, }, @@ -517,11 +553,11 @@ pub enum Inst { /// elements from `addr`. /// /// The values at `addr` are not dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Tuple2 { /// Tuple arguments. #[inst_display(display_with = DisplayArray::new)] - addr: [InstAddress; 2], + addr: [Address; 2], /// Where to store the produced tuple. out: Output, }, @@ -529,11 +565,11 @@ pub enum Inst { /// elements from `addr`. /// /// The values at `addr` are not dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Tuple3 { /// Tuple arguments. #[inst_display(display_with = DisplayArray::new)] - addr: [InstAddress; 3], + addr: [Address; 3], /// Where to store the produced tuple. out: Output, }, @@ -541,11 +577,11 @@ pub enum Inst { /// elements from `addr`. /// /// The values at `addr` are not dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Tuple4 { /// Tuple arguments. #[inst_display(display_with = DisplayArray::new)] - addr: [InstAddress; 4], + addr: [Address; 4], /// Where to store the produced tuple. out: Output, }, @@ -553,10 +589,10 @@ pub enum Inst { /// `addr`. /// /// Unlike `TupleN` variants, values at `addr` are dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Tuple { /// Where the arguments to the tuple are stored. - addr: InstAddress, + addr: Address, /// The number of elements in the tuple. count: usize, /// Where to store the produced tuple. @@ -576,7 +612,7 @@ pub enum Inst { /// ``` Environment { /// The tuple to push. - addr: InstAddress, + addr: Address, /// The expected size of the tuple. count: usize, /// Where to unpack the environment. @@ -594,10 +630,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Object { /// Where the arguments to the tuple are stored. - addr: InstAddress, + addr: Address, /// The static slot of the object keys. slot: usize, /// Where to store the produced tuple. @@ -606,7 +642,7 @@ pub enum Inst { /// Construct a range. /// /// The arguments loaded are determined by the range being constructed. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Range { /// The kind of the range, which determines the number arguments on the /// stack. @@ -619,10 +655,10 @@ pub enum Inst { /// `slot` being referenced. /// /// The values at `addr` are dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Struct { /// The address to load fields from. - addr: InstAddress, + addr: Address, /// The type of the struct to construct. hash: Hash, /// Where to write the constructed struct. @@ -631,10 +667,10 @@ pub enum Inst { /// Construct a struct from a constant. /// /// The values at `addr` are dropped. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] ConstConstruct { /// Where constructor arguments are stored. - addr: InstAddress, + addr: Address, /// The type of the struct to construct. hash: Hash, /// The number of constructor arguments. @@ -649,7 +685,7 @@ pub enum Inst { /// ```text /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] String { /// The static string slot to load the string from. slot: usize, @@ -663,7 +699,7 @@ pub enum Inst { /// ```text /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Bytes { /// The static byte string slot to load the string from. slot: usize, @@ -681,10 +717,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] StringConcat { /// Where the strings to concatenate are stored. - addr: InstAddress, + addr: Address, /// The number of items to pop from the stack. len: usize, /// The minimum string size used. @@ -694,10 +730,10 @@ pub enum Inst { }, /// Push a combined format specification and value onto the stack. The value /// used is the last value on the stack. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Format { /// Address of the value being formatted. - addr: InstAddress, + addr: Address, /// The format specification to use. spec: FormatSpec, /// Where to store the produced format. @@ -713,7 +749,7 @@ pub enum Inst { /// ``` IsUnit { /// The address of the value to test. - addr: InstAddress, + addr: Address, /// Where to store the output. out: Output, }, @@ -726,10 +762,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Try { /// Address of value to try. - addr: InstAddress, + addr: Address, /// Where to store the value in case there is a continuation. out: Output, }, @@ -741,10 +777,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] EqChar { /// Address of the value to compare. - addr: InstAddress, + addr: Address, /// The character to test against. #[inst_display(display_with = DisplayDebug::new)] value: char, @@ -752,20 +788,20 @@ pub enum Inst { out: Output, }, /// Test if the specified value is a specific signed integer. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] EqSigned { /// Address of the value to compare. - addr: InstAddress, + addr: Address, /// The value to test against. value: i64, /// Where to store the result of the comparison. out: Output, }, /// Test if the specified value is a specific unsigned integer. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] EqUnsigned { /// Address of the value to compare. - addr: InstAddress, + addr: Address, /// The value to test against. value: u64, /// Where to store the result of the comparison. @@ -779,10 +815,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] EqBool { /// Address of the value to compare. - addr: InstAddress, + addr: Address, /// The value to test against. value: bool, /// Where to store the result of the comparison. @@ -796,10 +832,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] EqString { /// Address of the value to compare. - addr: InstAddress, + addr: Address, /// The slot to test against. slot: usize, /// Where to store the result of the comparison. @@ -813,10 +849,10 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] EqBytes { /// Address of the value to compare. - addr: InstAddress, + addr: Address, /// The slot to test against. slot: usize, /// Where to store the result of the comparison. @@ -830,12 +866,12 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] MatchType { /// The type hash to match against. hash: Hash, /// The address of the value to test. - addr: InstAddress, + addr: Address, /// Where to store the output. out: Output, }, @@ -850,14 +886,14 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] MatchVariant { /// The type hash of the containing enum. enum_hash: Hash, /// The type hash of the variant. variant_hash: Hash, /// The address of the value to test. - addr: InstAddress, + addr: Address, /// Where to store the output. out: Output, }, @@ -869,12 +905,12 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] MatchBuiltIn { /// The type to check for. type_check: TypeCheck, /// The address of the value to test. - addr: InstAddress, + addr: Address, /// Where to store the output. out: Output, }, @@ -887,7 +923,7 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] MatchSequence { /// Type constraints that the sequence must match. type_check: TypeCheck, @@ -897,7 +933,7 @@ pub enum Inst { /// `false`. exact: bool, /// The address of the value to test. - addr: InstAddress, + addr: Address, /// Where to store the output. out: Output, }, @@ -910,7 +946,7 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] MatchObject { /// The slot of object keys to use. slot: usize, @@ -918,7 +954,7 @@ pub enum Inst { /// `false`. exact: bool, /// The address of the value to test. - addr: InstAddress, + addr: Address, /// Where to store the output. out: Output, }, @@ -935,7 +971,7 @@ pub enum Inst { /// ``` Yield { /// Address of the value being yielded. - addr: InstAddress, + addr: Address, /// Where to store the produced resume value. out: Output, }, @@ -963,98 +999,98 @@ pub enum Inst { /// /// => /// ``` - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Variant { /// Where the arguments to construct the variant are stored. - addr: InstAddress, + addr: Address, /// The kind of built-in variant to construct. variant: InstVariant, /// Where to store the variant. out: Output, }, /// An operation. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Op { /// The kind of operation. op: InstOp, /// The address of the first argument. - a: InstAddress, + a: Address, /// The address of the second argument. - b: InstAddress, + b: Address, /// Whether the produced value from the operation should be kept or not. out: Output, }, /// An arithmetic operation. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Arithmetic { /// The kind of operation. op: InstArithmeticOp, /// The address of the first argument. - a: InstAddress, + a: Address, /// The address of the second argument. - b: InstAddress, + b: Address, /// Whether the produced value from the operation should be kept or not. out: Output, }, /// A bitwise operation. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Bitwise { /// The kind of operation. op: InstBitwiseOp, /// The address of the first argument. - a: InstAddress, + a: Address, /// The address of the second argument. - b: InstAddress, + b: Address, /// Whether the produced value from the operation should be kept or not. out: Output, }, /// A shift operation. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Shift { /// The kind of operation. op: InstShiftOp, /// The address of the first argument. - a: InstAddress, + a: Address, /// The address of the second argument. - b: InstAddress, + b: Address, /// Whether the produced value from the operation should be kept or not. out: Output, }, /// Instruction for assigned arithmetic operations. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] AssignArithmetic { /// The kind of operation. op: InstArithmeticOp, /// The target of the operation. target: InstTarget, /// The value being assigned. - rhs: InstAddress, + rhs: Address, }, /// Instruction for assigned bitwise operations. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] AssignBitwise { /// The kind of operation. op: InstBitwiseOp, /// The target of the operation. target: InstTarget, /// The value being assigned. - rhs: InstAddress, + rhs: Address, }, /// Instruction for assigned shift operations. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] AssignShift { /// The kind of operation. op: InstShiftOp, /// The target of the operation. target: InstTarget, /// The value being assigned. - rhs: InstAddress, + rhs: Address, }, /// Advance an iterator at the given position. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] IterNext { /// The address of the iterator to advance. - addr: InstAddress, + addr: Address, /// A relative jump to perform if the iterator could not be advanced. jump: usize, /// Where to store the produced value from the iterator. @@ -1064,7 +1100,7 @@ pub enum Inst { /// /// This should only be used during testing or extreme scenarios that are /// completely unrecoverable. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Panic { /// The reason for the panic. #[inst_display(display_with = PanicReason::ident)] @@ -1072,9 +1108,9 @@ pub enum Inst { }, } -impl Inst { +impl Kind { /// Construct an instruction to push a unit. - pub fn unit(out: Output) -> Self { + pub(crate) fn unit(out: Output) -> Self { Self::Store { value: InstValue::Unit, out, @@ -1082,7 +1118,7 @@ impl Inst { } /// Construct an instruction to push a boolean. - pub fn bool(b: bool, out: Output) -> Self { + pub(crate) fn bool(b: bool, out: Output) -> Self { Self::Store { value: InstValue::Bool(b), out, @@ -1090,7 +1126,7 @@ impl Inst { } /// Construct an instruction to push a character. - pub fn char(c: char, out: Output) -> Self { + pub(crate) fn char(c: char, out: Output) -> Self { Self::Store { value: InstValue::Char(c), out, @@ -1098,7 +1134,7 @@ impl Inst { } /// Construct an instruction to push an integer. - pub fn signed(v: i64, out: Output) -> Self { + pub(crate) fn signed(v: i64, out: Output) -> Self { Self::Store { value: InstValue::Integer(v), out, @@ -1106,7 +1142,7 @@ impl Inst { } /// Construct an instruction to push an unsigned integer. - pub fn unsigned(v: u64, out: Output) -> Self { + pub(crate) fn unsigned(v: u64, out: Output) -> Self { Self::Store { value: InstValue::Unsigned(v), out, @@ -1114,7 +1150,7 @@ impl Inst { } /// Construct an instruction to push a float. - pub fn float(v: f64, out: Output) -> Self { + pub(crate) fn float(v: f64, out: Output) -> Self { Self::Store { value: InstValue::Float(v), out, @@ -1122,7 +1158,7 @@ impl Inst { } /// Construct an instruction to push a type. - pub fn ty(ty: Type, out: Output) -> Self { + pub(crate) fn ty(ty: Type, out: Output) -> Self { Self::Store { value: InstValue::Type(ty), out, @@ -1130,7 +1166,7 @@ impl Inst { } /// Construct an instruction to push an ordering. - pub fn ordering(ordering: Ordering, out: Output) -> Self { + pub(crate) fn ordering(ordering: Ordering, out: Output) -> Self { Self::Store { value: InstValue::Ordering(ordering), out, @@ -1138,7 +1174,7 @@ impl Inst { } /// Construct an instruction to push a type hash. - pub fn hash(hash: Hash, out: Output) -> Self { + pub(crate) fn hash(hash: Hash, out: Output) -> Self { Self::Store { value: InstValue::Hash(hash), out, @@ -1147,11 +1183,10 @@ impl Inst { } /// What to do with the output of an instruction. -#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Encode, Decode)] +#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash)] #[try_clone(copy)] -#[non_exhaustive] -#[musli(transparent)] -#[serde(transparent)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] pub struct Output { offset: usize, } @@ -1172,11 +1207,11 @@ impl Output { /// Check if the output is a keep. #[inline(always)] - pub(crate) fn as_addr(&self) -> Option { + pub(crate) fn as_addr(&self) -> Option
{ if self.offset == usize::MAX { None } else { - Some(InstAddress::new(self.offset)) + Some(Address::new(self.offset)) } } @@ -1191,18 +1226,18 @@ impl Output { /// # Examples /// /// ``` - /// use rune::runtime::{Output, Memory, ToValue, VmResult, InstAddress}; + /// use rune::runtime::{Output, Memory, ToValue, VmError, Address}; /// use rune::vm_try; /// - /// fn sum(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + /// fn sum(stack: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { /// let mut number = 0; /// - /// for value in vm_try!(stack.slice_at(addr, args)) { - /// number += vm_try!(value.as_integer::()); + /// for value in stack.slice_at(addr, args)? { + /// number += value.as_integer::()?; /// } /// - /// out.store(stack, number); - /// VmResult::Ok(()) + /// out.store(stack, number)?; + /// Ok(()) /// } #[inline(always)] pub fn store(self, stack: &mut M, o: O) -> Result<(), RuntimeError> @@ -1271,33 +1306,21 @@ impl IntoOutput for Value { } /// How an instruction addresses a value. -#[derive( - Default, - TryClone, - Clone, - Copy, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - Serialize, - Deserialize, - Decode, - Encode, -)] +#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[repr(transparent)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] #[try_clone(copy)] -pub struct InstAddress { +pub struct Address { offset: usize, } -impl InstAddress { +impl Address { /// The first possible address. - pub const ZERO: InstAddress = InstAddress { offset: 0 }; + pub const ZERO: Address = Address { offset: 0 }; /// An invalid address. - pub const INVALID: InstAddress = InstAddress { offset: usize::MAX }; + pub const INVALID: Address = Address { offset: usize::MAX }; /// Construct a new address. #[inline] @@ -1318,7 +1341,7 @@ impl InstAddress { } } -impl fmt::Display for InstAddress { +impl fmt::Display for Address { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.offset == usize::MAX { @@ -1329,7 +1352,7 @@ impl fmt::Display for InstAddress { } } -impl fmt::Debug for InstAddress { +impl fmt::Debug for Address { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) @@ -1337,40 +1360,41 @@ impl fmt::Debug for InstAddress { } /// Range limits of a range expression. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -#[non_exhaustive] -pub enum InstRange { +pub(crate) enum InstRange { /// `start..`. RangeFrom { /// The start address of the range. - start: InstAddress, + start: Address, }, /// `..`. RangeFull, /// `start..=end`. RangeInclusive { /// The start address of the range. - start: InstAddress, + start: Address, /// The end address of the range. - end: InstAddress, + end: Address, }, /// `..=end`. RangeToInclusive { /// The end address of the range. - end: InstAddress, + end: Address, }, /// `..end`. RangeTo { /// The end address of the range. - end: InstAddress, + end: Address, }, /// `start..end`. Range { /// The start address of the range. - start: InstAddress, + start: Address, /// The end address of the range. - end: InstAddress, + end: Address, }, } @@ -1388,18 +1412,20 @@ impl fmt::Display for InstRange { } /// The target of an operation. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum InstTarget { +pub(crate) enum InstTarget { /// Target is an offset to the current call frame. - #[musli(packed)] - Address(InstAddress), + #[cfg_attr(feature = "musli", musli(packed))] + Address(Address), /// Target the field of an object. - #[musli(packed)] - Field(InstAddress, usize), + #[cfg_attr(feature = "musli", musli(packed))] + Field(Address, usize), /// Target a tuple field. - #[musli(packed)] - TupleField(InstAddress, usize), + #[cfg_attr(feature = "musli", musli(packed))] + TupleField(Address, usize), } impl fmt::Display for InstTarget { @@ -1413,9 +1439,11 @@ impl fmt::Display for InstTarget { } /// An operation between two values on the machine. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum InstArithmeticOp { +pub(crate) enum InstArithmeticOp { /// The add operation. `a + b`. Add, /// The sub operation. `a - b`. @@ -1454,9 +1482,11 @@ impl fmt::Display for InstArithmeticOp { } /// An operation between two values on the machine. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum InstBitwiseOp { +pub(crate) enum InstBitwiseOp { /// The bitwise and operation. `a & b`. BitAnd, /// The bitwise xor operation. `a ^ b`. @@ -1485,9 +1515,11 @@ impl fmt::Display for InstBitwiseOp { } /// An operation between two values on the machine. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum InstShiftOp { +pub(crate) enum InstShiftOp { /// The shift left operation. `a << b`. Shl, /// The shift right operation. `a << b`. @@ -1511,9 +1543,11 @@ impl fmt::Display for InstShiftOp { } /// An operation between two values on the machine. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum InstOp { +pub(crate) enum InstOp { /// Compare two values on the stack for lt and push the result as a /// boolean on the stack. Lt, @@ -1604,6 +1638,7 @@ pub enum InstOp { } impl fmt::Display for InstOp { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Lt => { @@ -1646,44 +1681,45 @@ impl fmt::Display for InstOp { } /// A literal value that can be pushed. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -#[non_exhaustive] -pub enum InstValue { +pub(crate) enum InstValue { /// An empty tuple. Unit, /// A boolean. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Bool(bool), /// A character. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Char(char), /// An unsigned integer. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Unsigned(u64), /// An integer. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Integer(i64), /// A float. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Float(f64), /// A type hash. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Type(Type), /// An ordering. Ordering( - #[musli(with = crate::musli::ordering)] - #[serde(with = "crate::serde::ordering")] + #[cfg_attr(feature = "musli", musli(with = crate::musli::ordering))] + #[cfg_attr(feature = "serde", serde(with = "crate::serde::ordering"))] Ordering, ), /// A hash. - #[musli(packed)] + #[cfg_attr(feature = "musli", musli(packed))] Hash(Hash), } impl InstValue { /// Convert into a value that can be pushed onto the stack. - pub fn into_value(self) -> Value { + pub(crate) fn into_value(self) -> Value { match self { Self::Unit => Value::unit(), Self::Bool(v) => Value::from(v), @@ -1717,17 +1753,15 @@ impl fmt::Display for InstValue { } /// A variant that can be constructed. -#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] #[try_clone(copy)] -pub enum InstVariant { +pub(crate) enum InstVariant { /// `Option::Some`, which uses one value. Some, /// `Option::None`, which uses no values. None, - /// `Result::Ok`, which uses one value. - Ok, - /// `Result::Err`, which uses one value. - Err, } impl fmt::Display for InstVariant { @@ -1739,12 +1773,6 @@ impl fmt::Display for InstVariant { Self::None => { write!(f, "None")?; } - Self::Ok => { - write!(f, "Ok")?; - } - Self::Err => { - write!(f, "Err")?; - } } Ok(()) diff --git a/crates/rune/src/runtime/iterator.rs b/crates/rune/src/runtime/iterator.rs index 76a360f7d..3c6f8ef54 100644 --- a/crates/rune/src/runtime/iterator.rs +++ b/crates/rune/src/runtime/iterator.rs @@ -1,7 +1,7 @@ use crate::alloc; use crate::compile::meta; -use super::{FromValue, MaybeTypeOf, RuntimeError, Value, VmResult}; +use super::{FromValue, MaybeTypeOf, RuntimeError, Value, VmError}; /// An owning iterator. #[derive(Debug)] @@ -15,12 +15,12 @@ impl Iterator { } #[inline] - pub(crate) fn size_hint(&self) -> VmResult<(usize, Option)> { + pub(crate) fn size_hint(&self) -> Result<(usize, Option), VmError> { self.iter.protocol_size_hint() } #[inline] - pub(crate) fn next(&mut self) -> VmResult> { + pub(crate) fn next(&mut self) -> Result, VmError> { self.iter.protocol_next() } } @@ -28,7 +28,7 @@ impl Iterator { impl FromValue for Iterator { #[inline] fn from_value(value: Value) -> Result { - value.into_iter().into_result().map_err(RuntimeError::from) + value.into_iter().map_err(RuntimeError::from) } } diff --git a/crates/rune/src/runtime/label.rs b/crates/rune/src/runtime/label.rs index 2823c8e2e..bb5d4e718 100644 --- a/crates/rune/src/runtime/label.rs +++ b/crates/rune/src/runtime/label.rs @@ -7,8 +7,11 @@ use core::num::NonZeroUsize; use crate as rune; use crate::alloc::borrow::Cow; use crate::alloc::prelude::*; -use ::rust_alloc::rc::Rc; +use rust_alloc::rc::Rc; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// A label that can be jumped to. @@ -22,6 +25,7 @@ pub(crate) struct Label { impl Label { /// Construct a new label. + #[inline] pub(crate) fn new(name: &'static str, index: usize) -> Self { Self { name, @@ -31,11 +35,13 @@ impl Label { } /// Get jump. + #[inline] pub(crate) fn jump(&self) -> Option { Some(self.jump.get()?.get().wrapping_sub(1)) } /// Set jump. + #[inline] pub(crate) fn set_jump(&self, jump: usize) -> bool { let Some(jump) = NonZeroUsize::new(jump.wrapping_add(1)) else { return false; @@ -46,6 +52,7 @@ impl Label { } /// Convert into owned label. + #[inline] pub(crate) fn to_debug_label(&self) -> DebugLabel { DebugLabel { name: self.name.into(), @@ -56,6 +63,7 @@ impl Label { } impl fmt::Display for Label { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(jump) = self.jump() { write!(f, "{}_{} ({jump})", self.name, self.index) @@ -66,7 +74,9 @@ impl fmt::Display for Label { } /// A label that can be jumped to. -#[derive(Debug, TryClone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, TryClone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] pub struct DebugLabel { /// The name of the label. name: Cow<'static, str>, @@ -78,12 +88,14 @@ pub struct DebugLabel { impl DebugLabel { /// Get jump. + #[inline] pub(crate) fn jump(&self) -> Option { Some(self.jump?.get().wrapping_sub(1)) } } impl fmt::Display for DebugLabel { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}_{}", self.name, self.index)?; diff --git a/crates/rune/src/runtime/mod.rs b/crates/rune/src/runtime/mod.rs index d9e7b864b..50f7fae32 100644 --- a/crates/rune/src/runtime/mod.rs +++ b/crates/rune/src/runtime/mod.rs @@ -22,11 +22,17 @@ pub use self::borrow_mut::BorrowMut; mod borrow_ref; pub use self::borrow_ref::BorrowRef; +mod any_obj_vtable; +use self::any_obj_vtable::AnyObjVtable; + mod any_obj; -use self::any_obj::AnyObjErrorKind; pub use self::any_obj::{AnyObj, AnyObjError}; +use self::any_obj::{AnyObjData, AnyObjErrorKind}; pub(crate) use self::any_obj::{AnyObjDrop, RawAnyObjGuard}; +mod shared; +pub use self::shared::Shared; + mod args; pub use self::args::{Args, FixedArgs}; pub(crate) use self::args::{DynArgs, DynArgsUsed, DynGuardedArgs}; @@ -43,8 +49,10 @@ mod call; pub use self::call::Call; mod const_value; +#[doc(hidden)] +pub use self::const_value::ToConstValue; pub use self::const_value::{ - from_const_value, to_const_value, ConstConstruct, ConstValue, FromConstValue, ToConstValue, + from_const_value, to_const_value, ConstConstruct, ConstValue, FromConstValue, }; pub(crate) use self::const_value::{ConstContext, ConstValueKind, EmptyConstContext}; @@ -57,8 +65,6 @@ pub mod format; pub use self::format::{Format, FormatSpec}; mod from_value; -#[allow(deprecated)] -pub use self::from_value::UnsafeFromValue; pub use self::from_value::{from_value, FromValue, UnsafeToMut, UnsafeToRef}; mod function; @@ -77,17 +83,18 @@ pub use self::generator_state::GeneratorState; mod guarded_args; pub use self::guarded_args::GuardedArgs; -mod inst; -pub use self::inst::{ - Inst, InstAddress, InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, InstShiftOp, InstTarget, - InstValue, InstVariant, IntoOutput, Output, PanicReason, TypeCheck, +pub(crate) mod inst; +pub use self::inst::{Address, Inst, IntoOutput, Output}; +pub(crate) use self::inst::{ + InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, InstShiftOp, InstTarget, InstValue, + InstVariant, PanicReason, TypeCheck, }; mod iterator; pub use self::iterator::Iterator; -mod type_; -pub use self::type_::Type; +mod r#type; +pub use self::r#type::Type; mod label; pub use self::label::DebugLabel; @@ -124,9 +131,11 @@ pub(crate) mod range; pub use self::range::Range; mod runtime_context; -pub(crate) use self::runtime_context::FunctionHandler; pub use self::runtime_context::RuntimeContext; +mod function_handler; +pub(crate) use self::function_handler::FunctionHandler; + mod select; pub(crate) use self::select::Select; @@ -145,7 +154,9 @@ mod stream; pub use self::stream::Stream; mod to_value; -pub use self::to_value::{to_value, ToReturn, ToValue, UnsafeToValue}; +#[doc(hidden)] +pub use self::to_value::ToValue; +pub use self::to_value::{to_value, IntoReturn, UnsafeToValue}; mod tuple; pub use self::tuple::{OwnedTuple, Tuple}; @@ -165,7 +176,7 @@ pub use self::value::{ Accessor, EmptyStruct, Inline, RawValueGuard, Rtti, Struct, TupleStruct, TypeValue, Value, ValueMutGuard, ValueRefGuard, }; -pub(crate) use self::value::{Dynamic, DynamicTakeError, Repr, RttiKind}; +pub(crate) use self::value::{AnySequence, AnySequenceTakeError, Repr, RttiKind}; pub mod slice; @@ -183,17 +194,19 @@ mod vm_call; pub(crate) use self::vm_call::VmCall; pub(crate) mod vm_diagnostics; -pub(crate) use self::vm_diagnostics::{VmDiagnostics, VmDiagnosticsObj}; +pub use self::vm_diagnostics::VmDiagnostics; +pub(crate) use self::vm_diagnostics::VmDiagnosticsObj; mod vm_error; #[cfg(feature = "emit")] pub(crate) use self::vm_error::VmErrorAt; -pub use self::vm_error::{try_result, RuntimeError, TryFromResult, VmError, VmResult}; +#[allow(deprecated)] +pub use self::vm_error::{RuntimeError, VmError, VmResult}; pub(crate) use self::vm_error::{VmErrorKind, VmIntegerRepr}; mod vm_execution; pub(crate) use self::vm_execution::ExecutionState; -pub use self::vm_execution::{VmExecution, VmSendExecution}; +pub use self::vm_execution::{VmExecution, VmOutcome, VmResume, VmSendExecution}; mod vm_halt; pub(crate) use self::vm_halt::{VmHalt, VmHaltInfo}; @@ -204,9 +217,7 @@ pub use self::fmt::Formatter; mod control_flow; pub use self::control_flow::ControlFlow; -#[cfg(feature = "alloc")] mod hasher; -#[cfg(feature = "alloc")] pub use self::hasher::Hasher; pub(crate) type FieldMap = crate::alloc::HashMap; diff --git a/crates/rune/src/runtime/object.rs b/crates/rune/src/runtime/object.rs index 6a1bbf8b3..f70dba101 100644 --- a/crates/rune/src/runtime/object.rs +++ b/crates/rune/src/runtime/object.rs @@ -10,7 +10,7 @@ use crate::alloc::hashbrown::raw::RawIter; use crate::alloc::prelude::*; use crate::alloc::{self, String}; use crate::runtime::{ - FieldMap, FromValue, ProtocolCaller, RawAnyGuard, Ref, ToValue, Value, VmError, VmResult, + FieldMap, FromValue, ProtocolCaller, RawAnyGuard, Ref, ToValue, Value, VmError, }; use crate::Any; @@ -69,13 +69,13 @@ pub type Values<'a> = hash_map::Values<'a, String, Value>; /// let mut object = rune::runtime::Object::new(); /// assert!(object.is_empty()); /// -/// object.insert_value(String::try_from("foo")?, 42).into_result()?; -/// object.insert_value(String::try_from("bar")?, true).into_result()?; +/// object.insert_value(String::try_from("foo")?, 42)?; +/// object.insert_value(String::try_from("bar")?, true)?; /// assert_eq!(2, object.len()); /// -/// assert_eq!(Some(42), object.get_value("foo").into_result()?); -/// assert_eq!(Some(true), object.get_value("bar").into_result()?); -/// assert_eq!(None::, object.get_value("baz").into_result()?); +/// assert_eq!(Some(42), object.get_value("foo")?); +/// assert_eq!(Some(true), object.get_value("bar")?); +/// assert_eq!(None::, object.get_value("baz")?); /// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Default)] @@ -111,15 +111,8 @@ impl Object { /// object.insert("Hello", "World"); /// ``` #[inline] - #[rune::function(path = Self::with_capacity)] - pub(crate) fn rune_with_capacity(capacity: usize) -> VmResult { - VmResult::Ok(vm_try!(Self::with_capacity(capacity))) - } - - /// Construct a new object with the given capacity. + #[rune::function(keep, path = Self::with_capacity)] pub fn with_capacity(capacity: usize) -> alloc::Result { - // BTreeMap doesn't support setting capacity on creation but we keep - // this here in case we want to switch store later. Ok(Self { inner: crate::runtime::new_field_hash_map_with_capacity(capacity)?, }) @@ -167,7 +160,7 @@ impl Object { } /// Get the given value at the given index. - pub fn get_value(&self, k: &Q) -> VmResult> + pub fn get_value(&self, k: &Q) -> Result, VmError> where String: borrow::Borrow, Q: ?Sized + hash::Hash + cmp::Eq + cmp::Ord, @@ -175,10 +168,10 @@ impl Object { { let value = match self.inner.get(k) { Some(value) => value.clone(), - None => return VmResult::Ok(None), + None => return Ok(None), }; - VmResult::Ok(Some(vm_try!(T::from_value(value)))) + Ok(Some(T::from_value(value)?)) } /// Returns a mutable reference to the value corresponding to the key. @@ -215,12 +208,12 @@ impl Object { /// Inserts a key-value pair into the dynamic object, converting it as /// necessary through the [`ToValue`] trait. #[inline] - pub fn insert_value(&mut self, k: String, v: T) -> VmResult<()> + pub fn insert_value(&mut self, k: String, v: T) -> Result<(), VmError> where T: ToValue, { - vm_try!(self.inner.try_insert(k, vm_try!(v.to_value()))); - VmResult::Ok(()) + self.inner.try_insert(k, v.to_value()?)?; + Ok(()) } /// Inserts a key-value pair into the map. @@ -239,15 +232,7 @@ impl Object { /// assert_eq!(map["b"], 3); /// ``` #[inline] - #[rune::function(path = Self::insert)] - pub(crate) fn rune_insert(&mut self, k: String, v: Value) -> VmResult> { - VmResult::Ok(vm_try!(self.inner.try_insert(k, v))) - } - - /// Inserts a key-value pair into the map. - /// - /// If the map did not have this key present, `None` is returned. - #[inline] + #[rune::function(keep, path = Self::insert)] pub fn insert(&mut self, k: String, v: Value) -> alloc::Result> { self.inner.try_insert(k, v) } @@ -362,45 +347,45 @@ impl Object { a: &Self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { if a.len() != b.len() { - return VmResult::Ok(false); + return Ok(false); } for (k1, v1) in a.iter() { let Some(v2) = b.get(k1) else { - return VmResult::Ok(false); + return Ok(false); }; - if !vm_try!(Value::partial_eq_with(v1, v2, caller)) { - return VmResult::Ok(false); + if !Value::partial_eq_with(v1, v2, caller)? { + return Ok(false); } } - VmResult::Ok(true) + Ok(true) } pub(crate) fn eq_with( a: &Self, b: &Self, - eq: fn(&Value, &Value, &mut dyn ProtocolCaller) -> VmResult, + eq: fn(&Value, &Value, &mut dyn ProtocolCaller) -> Result, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { if a.inner.len() != b.inner.len() { - return VmResult::Ok(false); + return Ok(false); } for (key, a) in a.inner.iter() { let Some(b) = b.inner.get(key) else { - return VmResult::Ok(false); + return Ok(false); }; - if !vm_try!(eq(a, b, caller)) { - return VmResult::Ok(false); + if !eq(a, b, caller)? { + return Ok(false); } } - VmResult::Ok(true) + Ok(true) } } @@ -459,15 +444,15 @@ pub struct RuneIter { impl RuneIter { #[rune::function(instance, keep, protocol = NEXT)] - pub fn next(&mut self) -> VmResult> { + pub fn next(&mut self) -> Result, VmError> { unsafe { let Some(bucket) = self.iter.next() else { - return VmResult::Ok(None); + return Ok(None); }; let (key, value) = bucket.as_ref(); - let key = vm_try!(key.try_clone()); - VmResult::Ok(Some((key, value.clone()))) + let key = key.try_clone()?; + Ok(Some((key, value.clone()))) } } @@ -488,9 +473,9 @@ impl iter::Iterator for RuneIter { #[inline] fn next(&mut self) -> Option { match RuneIter::next(self) { - VmResult::Ok(Some(value)) => Some(Ok(value)), - VmResult::Ok(None) => None, - VmResult::Err(err) => Some(Err(err)), + Ok(Some(value)) => Some(Ok(value)), + Ok(None) => None, + Err(err) => Some(Err(err)), } } } @@ -505,15 +490,15 @@ pub struct RuneIterKeys { impl RuneIterKeys { #[rune::function(instance, keep, protocol = NEXT)] - pub fn next(&mut self) -> VmResult> { + pub fn next(&mut self) -> Result, VmError> { unsafe { let Some(bucket) = self.iter.next() else { - return VmResult::Ok(None); + return Ok(None); }; let (key, _) = bucket.as_ref(); - let key = vm_try!(key.try_clone()); - VmResult::Ok(Some(key)) + let key = key.try_clone()?; + Ok(Some(key)) } } @@ -534,9 +519,9 @@ impl iter::Iterator for RuneIterKeys { #[inline] fn next(&mut self) -> Option { match RuneIterKeys::next(self) { - VmResult::Ok(Some(value)) => Some(Ok(value)), - VmResult::Ok(None) => None, - VmResult::Err(err) => Some(Err(err)), + Ok(Some(value)) => Some(Ok(value)), + Ok(None) => None, + Err(err) => Some(Err(err)), } } } @@ -551,14 +536,14 @@ pub struct RuneValues { impl RuneValues { #[rune::function(instance, keep, protocol = NEXT)] - pub fn next(&mut self) -> VmResult> { + pub fn next(&mut self) -> Result, VmError> { unsafe { let Some(bucket) = self.iter.next() else { - return VmResult::Ok(None); + return Ok(None); }; let (_, value) = bucket.as_ref(); - VmResult::Ok(Some(value.clone())) + Ok(Some(value.clone())) } } @@ -579,9 +564,9 @@ impl iter::Iterator for RuneValues { #[inline] fn next(&mut self) -> Option { match RuneValues::next(self) { - VmResult::Ok(Some(value)) => Some(Ok(value)), - VmResult::Ok(None) => None, - VmResult::Err(err) => Some(Err(err)), + Ok(Some(value)) => Some(Ok(value)), + Ok(None) => None, + Err(err) => Some(Err(err)), } } } diff --git a/crates/rune/src/runtime/panic.rs b/crates/rune/src/runtime/panic.rs index 2c6a37c91..08fe3f436 100644 --- a/crates/rune/src/runtime/panic.rs +++ b/crates/rune/src/runtime/panic.rs @@ -1,12 +1,15 @@ use core::fmt; -use ::rust_alloc::boxed::Box; +use rust_alloc::boxed::Box; use crate::runtime::PanicReason; +use crate::vm_error; pub trait BoxedPanic: fmt::Display + fmt::Debug + Send + Sync {} impl BoxedPanic for T where T: ?Sized + fmt::Display + fmt::Debug + Send + Sync {} +vm_error!(Panic); + /// A descriptive panic. /// /// This can be used as an error variant in native functions that you want to be diff --git a/crates/rune/src/runtime/protocol_caller.rs b/crates/rune/src/runtime/protocol_caller.rs index 617d4df8a..c1acb321e 100644 --- a/crates/rune/src/runtime/protocol_caller.rs +++ b/crates/rune/src/runtime/protocol_caller.rs @@ -1,6 +1,6 @@ use crate::runtime::vm::{CallResult, CallResultOnly, Isolated}; use crate::runtime::{ - DynArgs, Protocol, Stack, UnitFn, Value, Vm, VmError, VmErrorKind, VmExecution, VmResult, + DynArgs, Protocol, Stack, UnitFn, Value, Vm, VmError, VmErrorKind, VmExecution, }; use crate::Hash; @@ -12,14 +12,14 @@ pub(crate) trait ProtocolCaller: 'static { protocol: &'static Protocol, target: Value, args: &mut dyn DynArgs, - ) -> VmResult { - match vm_try!(self.try_call_protocol_fn(protocol, target, args)) { - CallResultOnly::Ok(value) => VmResult::Ok(value), + ) -> Result { + match self.try_call_protocol_fn(protocol, target, args)? { + CallResultOnly::Ok(value) => Ok(value), CallResultOnly::Unsupported(value) => { - VmResult::err(VmErrorKind::MissingProtocolFunction { + Err(VmError::new(VmErrorKind::MissingProtocolFunction { protocol, instance: value.type_info(), - }) + })) } } } @@ -30,7 +30,7 @@ pub(crate) trait ProtocolCaller: 'static { protocol: &'static Protocol, target: Value, args: &mut dyn DynArgs, - ) -> VmResult>; + ) -> Result, VmError>; } /// Use the global environment caller. @@ -44,7 +44,7 @@ impl ProtocolCaller for EnvProtocolCaller { protocol: &Protocol, target: Value, args: &mut dyn DynArgs, - ) -> VmResult> { + ) -> Result, VmError> { /// Check that arguments matches expected or raise the appropriate error. fn check_args(args: usize, expected: usize) -> Result<(), VmError> { if args != expected { @@ -68,27 +68,27 @@ impl ProtocolCaller for EnvProtocolCaller { .. }) = unit.function(&hash) { - vm_try!(check_args(count, *expected)); + check_args(count, *expected)?; - let mut stack = vm_try!(Stack::with_capacity(count)); - vm_try!(stack.push(target)); - vm_try!(args.push_to_stack(&mut stack)); + let mut stack = Stack::with_capacity(count)?; + stack.push(target)?; + args.push_to_stack(&mut stack)?; let mut vm = Vm::with_stack(context.clone(), unit.clone(), stack); vm.set_ip(*offset); - return VmResult::Ok(CallResultOnly::Ok(vm_try!(call.call_with_vm(vm)))); + return Ok(CallResultOnly::Ok(call.call_with_vm(vm)?)); } if let Some(handler) = context.function(&hash) { - let mut stack = vm_try!(Stack::with_capacity(count)); + let mut stack = Stack::with_capacity(count)?; let addr = stack.addr(); - vm_try!(stack.push(target)); - vm_try!(args.push_to_stack(&mut stack)); - vm_try!(handler(&mut stack, addr, count, addr.output())); + stack.push(target)?; + args.push_to_stack(&mut stack)?; + handler.call(&mut stack, addr, count, addr.output())?; let value = stack.at(addr).clone(); - return VmResult::Ok(CallResultOnly::Ok(value)); + return Ok(CallResultOnly::Ok(value)); } - VmResult::Ok(CallResultOnly::Unsupported(target)) + Ok(CallResultOnly::Unsupported(target)) }) } } @@ -99,28 +99,22 @@ impl ProtocolCaller for Vm { protocol: &'static Protocol, target: Value, args: &mut dyn DynArgs, - ) -> VmResult> { + ) -> Result, VmError> { let addr = self.stack().addr(); - vm_try!(self.stack_mut().push(())); + self.stack_mut().push(())?; - match vm_try!(self.call_instance_fn( - Isolated::Isolated, - target, - protocol, - args, - addr.output() - )) { - CallResult::Unsupported(value) => VmResult::Ok(CallResultOnly::Unsupported(value)), + match self.call_instance_fn(Isolated::Isolated, target, protocol, args, addr.output())? { + CallResult::Unsupported(value) => Ok(CallResultOnly::Unsupported(value)), CallResult::Ok(()) => { let value = self.stack().at(addr).clone(); self.stack_mut().truncate(addr); - VmResult::Ok(CallResultOnly::Ok(value)) + Ok(CallResultOnly::Ok(value)) } CallResult::Frame => { let mut execution = VmExecution::new(self); - let value = vm_try!(execution.complete()); + let value = execution.complete()?; execution.vm_mut().stack_mut().truncate(addr); - VmResult::Ok(CallResultOnly::Ok(value)) + Ok(CallResultOnly::Ok(value)) } } } diff --git a/crates/rune/src/runtime/range.rs b/crates/rune/src/runtime/range.rs index 1ae3a7f67..98e5e884e 100644 --- a/crates/rune/src/runtime/range.rs +++ b/crates/rune/src/runtime/range.rs @@ -4,13 +4,12 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{ - EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value, - VmErrorKind, VmResult, -}; use crate::Any; -use super::StepsBetween; +use super::{ + EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, StepsBetween, + ToValue, Value, VmError, VmErrorKind, +}; /// Type for a range expression `start..end`. /// @@ -93,28 +92,28 @@ impl Range { /// range.iter() /// ``` #[rune::function(keep)] - pub fn iter(&self) -> VmResult { + pub fn iter(&self) -> Result { let value = match (self.start.as_ref(), self.end.as_ref()) { (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => { - let end = vm_try!(end.as_integer::()); - vm_try!(rune::to_value(RangeIter::new(*start..end))) + let end = end.as_integer::()?; + rune::to_value(RangeIter::new(*start..end))? } (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => { - let end = vm_try!(end.as_integer::()); - vm_try!(rune::to_value(RangeIter::new(*start..end))) + let end = end.as_integer::()?; + rune::to_value(RangeIter::new(*start..end))? } (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => { - vm_try!(rune::to_value(RangeIter::new(*start..*end))) + rune::to_value(RangeIter::new(*start..*end))? } (start, end) => { - return VmResult::err(VmErrorKind::UnsupportedIterRange { + return Err(VmError::from(VmErrorKind::UnsupportedIterRange { start: start.type_info(), end: end.type_info(), - }) + })) } }; - VmResult::Ok(value) + Ok(value) } /// Iterate over the range. @@ -142,7 +141,7 @@ impl Range { /// } /// ``` #[rune::function(keep, protocol = INTO_ITER)] - pub fn into_iter(&self) -> VmResult { + pub fn into_iter(&self) -> Result { self.iter() } @@ -161,7 +160,7 @@ impl Range { /// assert!((f64::NAN..2.0) != (f64::NAN..2.0)); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub fn partial_eq(&self, other: &Self) -> VmResult { + pub fn partial_eq(&self, other: &Self) -> Result { self.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -169,9 +168,9 @@ impl Range { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - if !vm_try!(Value::partial_eq_with(&self.start, &b.start, caller)) { - return VmResult::Ok(false); + ) -> Result { + if !Value::partial_eq_with(&self.start, &b.start, caller)? { + return Ok(false); } Value::partial_eq_with(&self.end, &b.end, caller) @@ -189,13 +188,17 @@ impl Range { /// assert!(!eq(range, 'b'..'e')); /// ``` #[rune::function(keep, protocol = EQ)] - pub fn eq(&self, other: &Self) -> VmResult { + pub fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - pub(crate) fn eq_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { - if !vm_try!(Value::eq_with(&self.start, &b.start, caller)) { - return VmResult::Ok(false); + pub(crate) fn eq_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { + if !Value::eq_with(&self.start, &b.start, caller)? { + return Ok(false); } Value::eq_with(&self.end, &b.end, caller) @@ -212,7 +215,7 @@ impl Range { /// assert!(!((f64::NAN..2.0) < (f64::INFINITY..2.0))); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - pub fn partial_cmp(&self, other: &Self) -> VmResult> { + pub fn partial_cmp(&self, other: &Self) -> Result, VmError> { self.partial_cmp_with(other, &mut EnvProtocolCaller) } @@ -220,10 +223,10 @@ impl Range { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { - match vm_try!(Value::partial_cmp_with(&self.start, &b.start, caller)) { + ) -> Result, VmError> { + match Value::partial_cmp_with(&self.start, &b.start, caller)? { Some(Ordering::Equal) => (), - other => return VmResult::Ok(other), + other => return Ok(other), } Value::partial_cmp_with(&self.end, &b.end, caller) @@ -241,14 +244,18 @@ impl Range { /// assert_eq!(cmp('c'..'e', 'b'..'e'), Ordering::Greater); /// ``` #[rune::function(keep, protocol = CMP)] - pub fn cmp(&self, other: &Self) -> VmResult { + pub fn cmp(&self, other: &Self) -> Result { self.cmp_with(other, &mut EnvProtocolCaller) } - pub(crate) fn cmp_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { - match vm_try!(Value::cmp_with(&self.start, &b.start, caller)) { + pub(crate) fn cmp_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { + match Value::cmp_with(&self.start, &b.start, caller)? { Ordering::Equal => (), - other => return VmResult::Ok(other), + other => return Ok(other), } Value::cmp_with(&self.end, &b.end, caller) @@ -271,7 +278,7 @@ impl Range { /// assert!(range is std::ops::Range); /// ``` #[rune::function(keep)] - pub(crate) fn contains(&self, value: Value) -> VmResult { + pub(crate) fn contains(&self, value: Value) -> Result { self.contains_with(value, &mut EnvProtocolCaller) } @@ -279,14 +286,14 @@ impl Range { &self, value: Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - match vm_try!(Value::partial_cmp_with(&self.start, &value, caller)) { + ) -> Result { + match Value::partial_cmp_with(&self.start, &value, caller)? { Some(Ordering::Less | Ordering::Equal) => {} - _ => return VmResult::Ok(false), + _ => return Ok(false), } - VmResult::Ok(matches!( - vm_try!(Value::partial_cmp_with(&self.end, &value, caller)), + Ok(matches!( + Value::partial_cmp_with(&self.end, &value, caller)?, Some(Ordering::Greater) )) } @@ -332,17 +339,17 @@ double_ended_range_iter!(Range, RangeIter, { #[rune::function(instance, keep, protocol = LEN)] #[inline] - pub(crate) fn len(&self) -> VmResult + pub(crate) fn len(&self) -> Result where T: Copy + StepsBetween + fmt::Debug, { let Some(result) = T::steps_between(self.iter.start, self.iter.end) else { - return VmResult::panic(format!( + return Err(VmError::panic(format!( "could not calculate length of range {:?}..={:?}", self.iter.start, self.iter.end - )); + ))); }; - VmResult::Ok(result) + Ok(result) } }); diff --git a/crates/rune/src/runtime/range_from.rs b/crates/rune/src/runtime/range_from.rs index 8c9a0e013..2e4110bce 100644 --- a/crates/rune/src/runtime/range_from.rs +++ b/crates/rune/src/runtime/range_from.rs @@ -4,11 +4,12 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{ +use crate::Any; + +use super::{ EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value, - VmErrorKind, VmResult, + VmError, VmErrorKind, }; -use crate::Any; /// Type for a from range expression `start..`. /// @@ -87,25 +88,19 @@ impl RangeFrom { /// range.iter() /// ``` #[rune::function(keep)] - pub fn iter(&self) -> VmResult { + pub fn iter(&self) -> Result { let value = match self.start.as_ref() { - Repr::Inline(Inline::Unsigned(start)) => { - vm_try!(crate::to_value(RangeFromIter::new(*start..))) - } - Repr::Inline(Inline::Signed(start)) => { - vm_try!(crate::to_value(RangeFromIter::new(*start..))) - } - Repr::Inline(Inline::Char(start)) => { - vm_try!(crate::to_value(RangeFromIter::new(*start..))) - } + Repr::Inline(Inline::Unsigned(start)) => crate::to_value(RangeFromIter::new(*start..))?, + Repr::Inline(Inline::Signed(start)) => crate::to_value(RangeFromIter::new(*start..))?, + Repr::Inline(Inline::Char(start)) => crate::to_value(RangeFromIter::new(*start..))?, start => { - return VmResult::err(VmErrorKind::UnsupportedIterRangeFrom { + return Err(VmError::new(VmErrorKind::UnsupportedIterRangeFrom { start: start.type_info(), - }) + })); } }; - VmResult::Ok(value) + Ok(value) } /// Build an iterator over the range. @@ -139,7 +134,7 @@ impl RangeFrom { /// } /// ``` #[rune::function(keep, protocol = INTO_ITER)] - pub fn into_iter(&self) -> VmResult { + pub fn into_iter(&self) -> Result { self.iter() } @@ -158,7 +153,7 @@ impl RangeFrom { /// assert!((f64::NAN..) != (f64::NAN..)); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub fn partial_eq(&self, other: &Self) -> VmResult { + pub fn partial_eq(&self, other: &Self) -> Result { self.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -166,7 +161,7 @@ impl RangeFrom { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { Value::partial_eq_with(&self.start, &b.start, caller) } @@ -182,11 +177,15 @@ impl RangeFrom { /// assert!(!eq(range, 'b'..)); /// ``` #[rune::function(keep, protocol = EQ)] - pub fn eq(&self, other: &Self) -> VmResult { + pub fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - pub(crate) fn eq_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn eq_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { Value::eq_with(&self.start, &b.start, caller) } @@ -201,7 +200,7 @@ impl RangeFrom { /// assert!(!((f64::NAN..) < (f64::INFINITY..))); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - pub fn partial_cmp(&self, other: &Self) -> VmResult> { + pub fn partial_cmp(&self, other: &Self) -> Result, VmError> { self.partial_cmp_with(other, &mut EnvProtocolCaller) } @@ -209,7 +208,7 @@ impl RangeFrom { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { Value::partial_cmp_with(&self.start, &b.start, caller) } @@ -225,11 +224,15 @@ impl RangeFrom { /// assert_eq!(cmp('c'.., 'b'..), Ordering::Greater); /// ``` #[rune::function(keep, protocol = CMP)] - pub fn cmp(&self, other: &Self) -> VmResult { + pub fn cmp(&self, other: &Self) -> Result { self.cmp_with(other, &mut EnvProtocolCaller) } - pub(crate) fn cmp_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn cmp_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { Value::cmp_with(&self.start, &b.start, caller) } @@ -252,7 +255,7 @@ impl RangeFrom { /// assert!(range is RangeFrom); /// ``` #[rune::function(keep)] - pub(crate) fn contains(&self, value: Value) -> VmResult { + pub(crate) fn contains(&self, value: Value) -> Result { self.contains_with(value, &mut EnvProtocolCaller) } @@ -260,9 +263,9 @@ impl RangeFrom { &self, value: Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - VmResult::Ok(matches!( - vm_try!(Value::partial_cmp_with(&self.start, &value, caller)), + ) -> Result { + Ok(matches!( + Value::partial_cmp_with(&self.start, &value, caller)?, Some(Ordering::Less | Ordering::Equal) )) } diff --git a/crates/rune/src/runtime/range_full.rs b/crates/rune/src/runtime/range_full.rs index 0691fc4ab..90a5a5e0a 100644 --- a/crates/rune/src/runtime/range_full.rs +++ b/crates/rune/src/runtime/range_full.rs @@ -4,7 +4,7 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{FromValue, RuntimeError, ToValue, Value, VmResult}; +use crate::runtime::{FromValue, RuntimeError, ToValue, Value}; use crate::Any; /// Type for a full range expression `..`. @@ -58,8 +58,8 @@ impl RangeFull { /// assert!(range is std::ops::RangeFull); /// ``` #[rune::function(keep)] - pub(crate) fn contains(&self, _: Value) -> VmResult { - VmResult::Ok(true) + pub(crate) fn contains(&self, _: Value) -> bool { + true } /// Test the full range for partial equality. @@ -71,8 +71,8 @@ impl RangeFull { /// assert!(range == ..); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub fn partial_eq(&self, _: &Self) -> VmResult { - VmResult::Ok(true) + pub fn partial_eq(&self, _: &Self) -> bool { + true } /// Test the full range for total equality. @@ -86,8 +86,8 @@ impl RangeFull { /// assert!(eq(range, ..)); /// ``` #[rune::function(keep, protocol = EQ)] - pub fn eq(&self, _: &Self) -> VmResult { - VmResult::Ok(true) + pub fn eq(&self, _: &Self) -> bool { + true } /// Test the full range for partial ordering. @@ -99,8 +99,8 @@ impl RangeFull { /// assert!(!((..) > (..))); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - pub fn partial_cmp(&self, _: &Self) -> VmResult> { - VmResult::Ok(Some(Ordering::Equal)) + pub fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) } /// Test the full range for total ordering. @@ -114,8 +114,8 @@ impl RangeFull { /// assert_eq!(cmp(.., ..), Ordering::Equal); /// ``` #[rune::function(keep, protocol = CMP)] - pub fn cmp(&self, _: &Self) -> VmResult { - VmResult::Ok(Ordering::Equal) + pub fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal } } diff --git a/crates/rune/src/runtime/range_inclusive.rs b/crates/rune/src/runtime/range_inclusive.rs index 31d5f4bab..07178b136 100644 --- a/crates/rune/src/runtime/range_inclusive.rs +++ b/crates/rune/src/runtime/range_inclusive.rs @@ -4,13 +4,12 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{ - EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value, - VmErrorKind, VmResult, -}; use crate::Any; -use super::StepsBetween; +use super::{ + EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, StepsBetween, + ToValue, Value, VmError, VmErrorKind, +}; /// Type for an inclusive range expression `start..=end`. /// @@ -94,28 +93,28 @@ impl RangeInclusive { /// range.iter() /// ``` #[rune::function(keep)] - pub fn iter(&self) -> VmResult { + pub fn iter(&self) -> Result { let value = match (self.start.as_ref(), self.end.as_ref()) { (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => { - let end = vm_try!(end.as_integer::()); - vm_try!(rune::to_value(RangeInclusiveIter::new(*start..=end))) + let end = end.as_integer::()?; + rune::to_value(RangeInclusiveIter::new(*start..=end))? } (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => { - let end = vm_try!(end.as_integer::()); - vm_try!(rune::to_value(RangeInclusiveIter::new(*start..=end))) + let end = end.as_integer::()?; + rune::to_value(RangeInclusiveIter::new(*start..=end))? } (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => { - vm_try!(rune::to_value(RangeInclusiveIter::new(*start..=*end))) + rune::to_value(RangeInclusiveIter::new(*start..=*end))? } (start, end) => { - return VmResult::err(VmErrorKind::UnsupportedIterRangeInclusive { + return Err(VmError::new(VmErrorKind::UnsupportedIterRangeInclusive { start: start.type_info(), end: end.type_info(), - }) + })) } }; - VmResult::Ok(value) + Ok(value) } /// Iterate over the range. @@ -143,7 +142,7 @@ impl RangeInclusive { /// } /// ``` #[rune::function(keep, protocol = INTO_ITER)] - pub fn into_iter(&self) -> VmResult { + pub fn into_iter(&self) -> Result { self.iter() } @@ -162,7 +161,7 @@ impl RangeInclusive { /// assert!((f64::NAN..=2.0) != (f64::NAN..=2.0)); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub fn partial_eq(&self, other: &Self) -> VmResult { + pub fn partial_eq(&self, other: &Self) -> Result { self.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -170,9 +169,9 @@ impl RangeInclusive { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - if !vm_try!(Value::partial_eq_with(&self.start, &b.start, caller)) { - return VmResult::Ok(false); + ) -> Result { + if !Value::partial_eq_with(&self.start, &b.start, caller)? { + return Ok(false); } Value::partial_eq_with(&self.end, &b.end, caller) @@ -190,13 +189,17 @@ impl RangeInclusive { /// assert!(!eq(range, 'b'..='e')); /// ``` #[rune::function(keep, protocol = EQ)] - pub fn eq(&self, other: &Self) -> VmResult { + pub fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - pub(crate) fn eq_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { - if !vm_try!(Value::eq_with(&self.start, &b.start, caller)) { - return VmResult::Ok(false); + pub(crate) fn eq_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { + if !Value::eq_with(&self.start, &b.start, caller)? { + return Ok(false); } Value::eq_with(&self.end, &b.end, caller) @@ -213,7 +216,7 @@ impl RangeInclusive { /// assert!(!((f64::NAN..=2.0) < (f64::INFINITY..=2.0))); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - pub fn partial_cmp(&self, other: &Self) -> VmResult> { + pub fn partial_cmp(&self, other: &Self) -> Result, VmError> { self.partial_cmp_with(other, &mut EnvProtocolCaller) } @@ -221,10 +224,10 @@ impl RangeInclusive { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { - match vm_try!(Value::partial_cmp_with(&self.start, &b.start, caller)) { + ) -> Result, VmError> { + match Value::partial_cmp_with(&self.start, &b.start, caller)? { Some(Ordering::Equal) => (), - other => return VmResult::Ok(other), + other => return Ok(other), } Value::partial_cmp_with(&self.end, &b.end, caller) @@ -242,14 +245,18 @@ impl RangeInclusive { /// assert_eq!(cmp('c'..='e', 'b'..='e'), Ordering::Greater); /// ``` #[rune::function(keep, protocol = CMP)] - pub fn cmp(&self, other: &Self) -> VmResult { + pub fn cmp(&self, other: &Self) -> Result { self.cmp_with(other, &mut EnvProtocolCaller) } - pub(crate) fn cmp_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { - match vm_try!(Value::cmp_with(&self.start, &b.start, caller)) { + pub(crate) fn cmp_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { + match Value::cmp_with(&self.start, &b.start, caller)? { Ordering::Equal => (), - other => return VmResult::Ok(other), + other => return Ok(other), } Value::cmp_with(&self.end, &b.end, caller) @@ -272,7 +279,7 @@ impl RangeInclusive { /// assert!(range is std::ops::RangeInclusive); /// ``` #[rune::function(keep)] - pub(crate) fn contains(&self, value: Value) -> VmResult { + pub(crate) fn contains(&self, value: Value) -> Result { self.contains_with(value, &mut EnvProtocolCaller) } @@ -280,14 +287,14 @@ impl RangeInclusive { &self, value: Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - match vm_try!(Value::partial_cmp_with(&self.start, &value, caller)) { + ) -> Result { + match Value::partial_cmp_with(&self.start, &value, caller)? { Some(Ordering::Less | Ordering::Equal) => {} - _ => return VmResult::Ok(false), + _ => return Ok(false), } - VmResult::Ok(matches!( - vm_try!(Value::partial_cmp_with(&self.end, &value, caller)), + Ok(matches!( + Value::partial_cmp_with(&self.end, &value, caller)?, Some(Ordering::Greater | Ordering::Equal) )) } @@ -333,18 +340,18 @@ double_ended_range_iter!(RangeInclusive, RangeInclusiveIter, { #[rune::function(instance, keep, protocol = LEN)] #[inline] - pub(crate) fn len(&self) -> VmResult + pub(crate) fn len(&self) -> Result where T: Copy + StepsBetween + fmt::Debug, { let Some(result) = T::steps_between(*self.iter.start(), *self.iter.end()) else { - return VmResult::panic(format!( + return Err(VmError::panic(format!( "could not calculate length of range {:?}..={:?}", self.iter.start(), self.iter.end() - )); + ))); }; - VmResult::Ok(result) + Ok(result) } }); diff --git a/crates/rune/src/runtime/range_to.rs b/crates/rune/src/runtime/range_to.rs index 7746b68f7..be8f7fb3c 100644 --- a/crates/rune/src/runtime/range_to.rs +++ b/crates/rune/src/runtime/range_to.rs @@ -4,11 +4,10 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{ - EnvProtocolCaller, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmResult, -}; use crate::Any; +use super::{EnvProtocolCaller, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmError}; + /// Type for an inclusive range expression `..end`. /// /// # Examples @@ -72,7 +71,7 @@ impl RangeTo { /// assert!((..f64::NAN) != (..f64::NAN)); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub fn partial_eq(&self, other: &Self) -> VmResult { + pub fn partial_eq(&self, other: &Self) -> Result { self.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -80,7 +79,7 @@ impl RangeTo { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { Value::partial_eq_with(&self.end, &b.end, caller) } @@ -96,11 +95,15 @@ impl RangeTo { /// assert!(!eq(range, ..'f')); /// ``` #[rune::function(keep, protocol = EQ)] - pub fn eq(&self, other: &Self) -> VmResult { + pub fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - pub(crate) fn eq_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn eq_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { Value::eq_with(&self.end, &b.end, caller) } @@ -115,7 +118,7 @@ impl RangeTo { /// assert!(!((..f64::NAN) < (..f64::INFINITY))); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - pub fn partial_cmp(&self, other: &Self) -> VmResult> { + pub fn partial_cmp(&self, other: &Self) -> Result, VmError> { self.partial_cmp_with(other, &mut EnvProtocolCaller) } @@ -123,7 +126,7 @@ impl RangeTo { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { Value::partial_cmp_with(&self.end, &b.end, caller) } @@ -139,11 +142,15 @@ impl RangeTo { /// assert_eq!(cmp(..'c', ..'b'), Ordering::Greater); /// ``` #[rune::function(keep, protocol = CMP)] - pub fn cmp(&self, other: &Self) -> VmResult { + pub fn cmp(&self, other: &Self) -> Result { self.cmp_with(other, &mut EnvProtocolCaller) } - pub(crate) fn cmp_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn cmp_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { Value::cmp_with(&self.end, &b.end, caller) } @@ -164,7 +171,7 @@ impl RangeTo { /// assert!(range is std::ops::RangeTo); /// ``` #[rune::function(keep)] - pub(crate) fn contains(&self, value: Value) -> VmResult { + pub(crate) fn contains(&self, value: Value) -> Result { self.contains_with(value, &mut EnvProtocolCaller) } @@ -172,9 +179,9 @@ impl RangeTo { &self, value: Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - VmResult::Ok(matches!( - vm_try!(Value::partial_cmp_with(&self.end, &value, caller)), + ) -> Result { + Ok(matches!( + Value::partial_cmp_with(&self.end, &value, caller)?, Some(Ordering::Greater) )) } diff --git a/crates/rune/src/runtime/range_to_inclusive.rs b/crates/rune/src/runtime/range_to_inclusive.rs index 23feb5ede..7446cb0ef 100644 --- a/crates/rune/src/runtime/range_to_inclusive.rs +++ b/crates/rune/src/runtime/range_to_inclusive.rs @@ -4,11 +4,10 @@ use core::ops; use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{ - EnvProtocolCaller, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmResult, -}; use crate::Any; +use super::{EnvProtocolCaller, FromValue, ProtocolCaller, RuntimeError, ToValue, Value, VmError}; + /// Type for an inclusive range expression `..=end`. /// /// # Examples @@ -70,7 +69,7 @@ impl RangeToInclusive { /// assert!((..=f64::NAN) != (..=f64::NAN)); /// ``` #[rune::function(keep, protocol = PARTIAL_EQ)] - pub fn partial_eq(&self, other: &Self) -> VmResult { + pub fn partial_eq(&self, other: &Self) -> Result { self.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -78,7 +77,7 @@ impl RangeToInclusive { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { Value::partial_eq_with(&self.end, &b.end, caller) } @@ -94,11 +93,15 @@ impl RangeToInclusive { /// assert!(!eq(range, ..='f')); /// ``` #[rune::function(keep, protocol = EQ)] - pub fn eq(&self, other: &Self) -> VmResult { + pub fn eq(&self, other: &Self) -> Result { self.eq_with(other, &mut EnvProtocolCaller) } - pub(crate) fn eq_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn eq_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { Value::eq_with(&self.end, &b.end, caller) } @@ -113,7 +116,7 @@ impl RangeToInclusive { /// assert!(!((..=f64::NAN) < (..=f64::INFINITY))); /// ``` #[rune::function(keep, protocol = PARTIAL_CMP)] - pub fn partial_cmp(&self, other: &Self) -> VmResult> { + pub fn partial_cmp(&self, other: &Self) -> Result, VmError> { self.partial_cmp_with(other, &mut EnvProtocolCaller) } @@ -121,7 +124,7 @@ impl RangeToInclusive { &self, b: &Self, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { Value::partial_cmp_with(&self.end, &b.end, caller) } @@ -137,11 +140,15 @@ impl RangeToInclusive { /// assert_eq!(cmp(..='c', ..='b'), Ordering::Greater); /// ``` #[rune::function(keep, protocol = CMP)] - pub fn cmp(&self, other: &Self) -> VmResult { + pub fn cmp(&self, other: &Self) -> Result { self.cmp_with(other, &mut EnvProtocolCaller) } - pub(crate) fn cmp_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn cmp_with( + &self, + b: &Self, + caller: &mut dyn ProtocolCaller, + ) -> Result { Value::cmp_with(&self.end, &b.end, caller) } @@ -162,7 +169,7 @@ impl RangeToInclusive { /// assert!(range is std::ops::RangeToInclusive); /// ``` #[rune::function(keep)] - pub(crate) fn contains(&self, value: Value) -> VmResult { + pub(crate) fn contains(&self, value: Value) -> Result { self.contains_with(value, &mut EnvProtocolCaller) } @@ -170,9 +177,9 @@ impl RangeToInclusive { &self, value: Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - VmResult::Ok(matches!( - vm_try!(Value::partial_cmp_with(&self.end, &value, caller)), + ) -> Result { + Ok(matches!( + Value::partial_cmp_with(&self.end, &value, caller)?, Some(Ordering::Greater | Ordering::Equal) )) } diff --git a/crates/rune/src/runtime/ref.rs b/crates/rune/src/runtime/ref.rs index a0f4ce078..9483db886 100644 --- a/crates/rune/src/runtime/ref.rs +++ b/crates/rune/src/runtime/ref.rs @@ -5,10 +5,12 @@ use core::pin::Pin; use core::ptr::NonNull; use core::task::{Context, Poll}; -#[cfg(feature = "alloc")] -use ::rust_alloc::rc::Rc; -#[cfg(feature = "alloc")] -use ::rust_alloc::sync::Arc; +use rust_alloc::rc::Rc; +use rust_alloc::sync::Arc; + +use crate::any::AnyMarker; + +use super::{FromValue, RuntimeError, Value}; pub(super) struct RefVtable { pub(super) drop: DropFn, @@ -32,7 +34,6 @@ pub struct Ref { guard: RawAnyGuard, } -#[cfg(feature = "alloc")] impl From> for Ref { /// Construct from an atomically reference-counted value. /// @@ -45,6 +46,7 @@ impl From> for Ref { /// let value: Ref = Ref::from(Rc::new(String::from("hello world"))); /// assert_eq!(value.as_ref(), "hello world"); /// ``` + #[inline] fn from(value: Rc) -> Ref { unsafe fn drop_fn(data: NonNull<()>) { let _ = Rc::from_raw(data.cast::().as_ptr().cast_const()); @@ -59,7 +61,6 @@ impl From> for Ref { } } -#[cfg(feature = "alloc")] impl From> for Ref { /// Construct from an atomically reference-counted value. /// @@ -72,6 +73,7 @@ impl From> for Ref { /// let value: Ref = Ref::from(Arc::new(String::from("hello world"))); /// assert_eq!(value.as_ref(), "hello world"); /// ``` + #[inline] fn from(value: Arc) -> Ref { unsafe fn drop_fn(data: NonNull<()>) { let _ = Arc::from_raw(data.cast::().as_ptr().cast_const()); @@ -87,6 +89,7 @@ impl From> for Ref { } impl Ref { + #[inline] pub(super) const fn new(value: NonNull, guard: RawAnyGuard) -> Self { Self { value, guard } } @@ -101,6 +104,7 @@ impl Ref { /// let value: Ref = Ref::from_static("Hello World"); /// assert_eq!(value.as_ref(), "Hello World"); /// ``` + #[inline] pub const fn from_static(value: &'static T) -> Ref { let value = unsafe { NonNull::new_unchecked((value as *const T).cast_mut()) }; let guard = RawAnyGuard::new(NonNull::dangling(), &RefVtable { drop: |_| {} }); @@ -184,6 +188,7 @@ impl Ref { /// The returned pointer must not outlive the associated guard, since this /// prevents other uses of the underlying data which is incompatible with /// the current. + #[inline] pub fn into_raw(this: Self) -> (NonNull, RawAnyGuard) { (this.value, this.guard) } @@ -194,6 +199,7 @@ impl Ref { /// /// The caller is responsible for ensuring that the raw reference is /// associated with the specific pointer. + #[inline] pub unsafe fn from_raw(value: NonNull, guard: RawAnyGuard) -> Self { Self { value, guard } } @@ -227,6 +233,16 @@ where } } +impl FromValue for Ref +where + T: AnyMarker, +{ + #[inline] + fn from_value(value: Value) -> Result { + value.into_ref() + } +} + /// A strong owned mutable reference to the given type that can be safely /// dereferenced. /// @@ -246,6 +262,7 @@ pub struct Mut { } impl Mut { + #[inline] pub(super) const fn new(value: NonNull, guard: RawAnyGuard) -> Self { Self { value, guard } } @@ -260,6 +277,7 @@ impl Mut { /// let value: Mut<[u8]> = Mut::from_static(&mut [][..]); /// assert_eq!(&value[..], b""); /// ``` + #[inline] pub fn from_static(value: &'static mut T) -> Mut { let value = unsafe { NonNull::new_unchecked((value as *const T).cast_mut()) }; let guard = RawAnyGuard::new(NonNull::dangling(), &RefVtable { drop: |_| {} }); @@ -282,6 +300,7 @@ impl Mut { /// assert_eq!(&*value, &mut [1, 2][..]); /// # Ok::<_, rune::support::Error>(()) /// ``` + #[inline] pub fn map(this: Self, f: F) -> Mut where F: FnOnce(&mut T) -> &mut U, @@ -345,6 +364,7 @@ impl Mut { /// The returned pointer must not outlive the associated guard, since this /// prevents other uses of the underlying data which is incompatible with /// the current. + #[inline] pub fn into_raw(this: Self) -> (NonNull, RawAnyGuard) { (this.value, this.guard) } @@ -356,6 +376,7 @@ impl Mut { /// /// The caller is responsible for ensuring that the raw mutable reference is /// associated with the specific pointer. + #[inline] pub unsafe fn from_raw(value: NonNull, guard: RawAnyGuard) -> Self { Self { value, guard } } @@ -378,6 +399,7 @@ impl AsMut for Mut { impl Deref for Mut { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { // Safety: An owned mut holds onto a hard pointer to the data, // preventing it from being dropped for the duration of the owned mut. @@ -386,6 +408,7 @@ impl Deref for Mut { } impl DerefMut for Mut { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { // Safety: An owned mut holds onto a hard pointer to the data, // preventing it from being dropped for the duration of the owned mut. @@ -397,17 +420,29 @@ impl fmt::Debug for Mut where T: fmt::Debug, { + #[inline] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, fmt) } } +impl FromValue for Mut +where + T: AnyMarker, +{ + #[inline] + fn from_value(value: Value) -> Result { + value.into_mut() + } +} + impl Future for Mut where F: Unpin + Future, { type Output = F::Output; + #[inline] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // NB: inner Future is Unpin. let this = self.get_mut(); @@ -423,12 +458,14 @@ pub struct RawAnyGuard { } impl RawAnyGuard { + #[inline] pub(super) const fn new(data: NonNull<()>, vtable: &'static RefVtable) -> Self { Self { data, vtable } } } impl Drop for RawAnyGuard { + #[inline] fn drop(&mut self) { // Safety: type and referential safety is guaranteed at construction // time, since all constructors are unsafe. diff --git a/crates/rune/src/runtime/runtime_context.rs b/crates/rune/src/runtime/runtime_context.rs index f1a47cc60..d2def6a4a 100644 --- a/crates/rune/src/runtime/runtime_context.rs +++ b/crates/rune/src/runtime/runtime_context.rs @@ -1,16 +1,14 @@ use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc::prelude::*; use crate::hash; -use crate::runtime::{ConstConstruct, ConstValue, InstAddress, Memory, Output, VmResult}; +use crate::runtime::{ConstConstruct, ConstValue}; use crate::Hash; -/// A type-reduced function handler. -pub(crate) type FunctionHandler = - dyn Fn(&mut dyn Memory, InstAddress, usize, Output) -> VmResult<()> + Send + Sync; +use super::FunctionHandler; /// Static run context visible to the virtual machine. /// @@ -21,7 +19,7 @@ pub(crate) type FunctionHandler = #[derive(Default, TryClone)] pub struct RuntimeContext { /// Registered native function handlers. - functions: hash::Map>, + functions: hash::Map, /// Named constant values constants: hash::Map, /// Constant constructors. @@ -32,7 +30,7 @@ assert_impl!(RuntimeContext: Send + Sync); impl RuntimeContext { pub(crate) fn new( - functions: hash::Map>, + functions: hash::Map, constants: hash::Map, construct: hash::Map>, ) -> Self { @@ -45,7 +43,7 @@ impl RuntimeContext { /// Lookup the given native function handler in the context. #[inline] - pub fn function(&self, hash: &Hash) -> Option<&Arc> { + pub fn function(&self, hash: &Hash) -> Option<&FunctionHandler> { self.functions.get(hash) } diff --git a/crates/rune/src/runtime/select.rs b/crates/rune/src/runtime/select.rs index c08370e68..bc90e8fb3 100644 --- a/crates/rune/src/runtime/select.rs +++ b/crates/rune/src/runtime/select.rs @@ -1,12 +1,12 @@ use core::future; use core::pin::Pin; -use core::task::{Context, Poll}; +use core::task::{ready, Context, Poll}; use futures_core::Stream; use futures_util::stream::FuturesUnordered; use crate::runtime::future::SelectFuture; -use crate::runtime::{Future, Mut, Value, VmResult}; +use crate::runtime::{Future, Mut, Value, VmError}; /// A stored select. #[derive(Debug)] @@ -22,16 +22,14 @@ impl Select { } impl future::Future for Select { - type Output = VmResult<(usize, Value)>; + type Output = Result<(usize, Value), VmError>; + #[inline] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let poll = Pin::new(&mut self.futures).poll_next(cx); - - let poll = match poll { - Poll::Ready(poll) => poll.expect("inner stream should never end"), - Poll::Pending => return Poll::Pending, + let Some(result) = ready!(Pin::new(&mut self.futures).poll_next(cx)) else { + return Poll::Ready(Err(VmError::panic("select: no futures to select from"))); }; - Poll::Ready(poll) + Poll::Ready(result) } } diff --git a/crates/rune/src/runtime/shared.rs b/crates/rune/src/runtime/shared.rs new file mode 100644 index 000000000..f0095ead9 --- /dev/null +++ b/crates/rune/src/runtime/shared.rs @@ -0,0 +1,515 @@ +use core::fmt; +use core::marker::PhantomData; +use core::mem::{replace, ManuallyDrop}; +use core::ptr::{self, addr_of, NonNull}; + +use crate::alloc; +use crate::alloc::clone::TryClone; +use crate::any::AnyMarker; +use crate::compile::meta; +use crate::{Any, Hash}; + +use super::{ + AnyObj, AnyObjData, AnyObjError, AnyObjErrorKind, AnyObjVtable, AnyTypeInfo, BorrowMut, + BorrowRef, FromValue, MaybeTypeOf, Mut, RawAnyGuard, Ref, RefVtable, RuntimeError, ToValue, + TypeHash, TypeInfo, TypeOf, Value, +}; + +/// A typed wrapper for a reference. +/// +/// This is identical in layout to [`AnyObj`], but provides a statically +/// type-checked container. +/// +/// [`AnyObj`]: super::AnyObj +pub struct Shared { + /// The shared value. + shared: NonNull, + /// The statically known type of the value. + _marker: PhantomData, +} + +impl Shared +where + T: Any, +{ + /// Construct a new typed shared value. + /// + /// # Examples + /// + /// ``` + /// use rune::Value; + /// use rune::runtime::Shared; + /// use rune::alloc::String; + /// + /// let string = String::try_from("Hello World")?; + /// let string = Shared::new(string)?; + /// let string = Value::from(string); + /// + /// let string = string.into_any_obj()?; + /// assert_eq!(string.borrow_ref::()?.as_str(), "Hello World"); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + #[inline] + pub fn new(value: T) -> alloc::Result { + let any = AnyObj::new(value)?; + // SAFETY: We know that the value is valid. + unsafe { Ok(any.unsafe_into_shared()) } + } + + /// Construct a new typed object. + /// + /// # Safety + /// + /// Caller must ensure that the type is of the value `T`. + #[inline] + pub(super) unsafe fn from_raw(shared: NonNull>) -> Self { + Self { + shared: shared.cast(), + _marker: PhantomData, + } + } + + /// Coerce into a type-erased [`AnyObj`]. + #[inline] + pub(crate) fn into_any_obj(self) -> AnyObj { + let this = ManuallyDrop::new(self); + // SAFETY: We know that the shared value is valid. + unsafe { AnyObj::from_raw(this.shared.cast()) } + } + + /// Take the owned value of type `T`. + /// + /// This consumes any live references of the value and accessing them in the + /// future will result in an error. + /// + /// # Errors + /// + /// This errors if the underlying value is not owned. + pub fn take(self) -> Result { + let vtable = vtable(&self); + + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( + vtable.type_info(), + ))); + } + + // SAFETY: The appropriate type has been type checked for when the + // container was constructed. + unsafe { + self.shared.as_ref().access.try_take()?; + let data = vtable.as_ptr::(self.shared); + Ok(data.read()) + } + } + + /// Downcast into an owned value of type [`Ref`]. + /// + /// # Errors + /// + /// This errors in case the underlying value is not owned, non-owned + /// references cannot be coerced into [`Ref`]. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// let value = value.into_shared::()?; + /// + /// let reference = value.clone().into_ref()?; + /// assert!(value.borrow_ref().is_ok()); + /// assert_eq!(reference.0, 42); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub fn into_ref(self) -> Result, AnyObjError> { + let vtable = vtable(&self); + + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( + vtable.type_info(), + ))); + } + + // SAFETY: The appropriate type has been type checked for when the + // container was constructed. + unsafe { + self.shared.as_ref().access.try_shared()?; + let this = ManuallyDrop::new(self); + let data = vtable.as_ptr(this.shared); + + let vtable = &RefVtable { + drop: |shared: NonNull<()>| { + let shared = shared.cast::(); + shared.as_ref().access.release(); + AnyObjData::dec(shared) + }, + }; + + let guard = RawAnyGuard::new(this.shared.cast(), vtable); + Ok(Ref::new(data, guard)) + } + } + + /// Downcast into an owned value of type [`Mut`]. + /// + /// # Errors + /// + /// This errors in case the underlying value is not owned, non-owned + /// references cannot be coerced into [`Mut`]. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// let value = value.into_shared::()?; + /// + /// let mut mutable = value.clone().into_mut()?; + /// assert!(value.borrow_ref().is_err()); + /// mutable.0 += 1; + /// drop(mutable); + /// + /// assert_eq!(value.borrow_ref()?.0, 43); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub fn into_mut(self) -> Result, AnyObjError> { + let vtable = vtable(&self); + + if !vtable.is_owned() { + return Err(AnyObjError::new(AnyObjErrorKind::NotOwned( + vtable.type_info(), + ))); + } + + // SAFETY: The appropriate type has been type checked for when the + // container was constructed. + unsafe { + self.shared.as_ref().access.try_exclusive()?; + let this = ManuallyDrop::new(self); + let data = vtable.as_ptr(this.shared); + + let vtable = &RefVtable { + drop: |shared: NonNull<()>| { + let shared = shared.cast::(); + shared.as_ref().access.release(); + AnyObjData::dec(shared) + }, + }; + + let guard = RawAnyGuard::new(this.shared.cast(), vtable); + Ok(Mut::new(data, guard)) + } + } + + /// Borrow a shared reference to the value while checking for shared access. + /// + /// This prevents other exclusive accesses from being performed while the + /// guard returned from this function is live. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// let value = value.into_shared::()?; + /// + /// let borrowed = value.borrow_ref()?; + /// assert!(value.borrow_ref().is_ok()); + /// drop(borrowed); + /// assert!(value.borrow_ref().is_ok()); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub fn borrow_ref(&self) -> Result, AnyObjError> { + let vtable = vtable(self); + + // SAFETY: The appropriate type has been type checked for when the + // container was constructed. + unsafe { + let guard = self.shared.as_ref().access.shared()?; + let data = vtable.as_ptr(self.shared); + Ok(BorrowRef::new(data, guard.into_raw())) + } + } + + /// Borrow an exclusive reference to the value. + /// + /// This prevents other accesses from being performed while the guard + /// returned from this function is live. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// let value = value.into_shared::()?; + /// + /// let borrowed = value.borrow_mut()?; + /// assert!(value.borrow_ref().is_err()); + /// drop(borrowed); + /// assert!(value.borrow_ref().is_ok()); + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub fn borrow_mut(&self) -> Result, AnyObjError> { + let vtable = vtable(self); + + if !vtable.is_mutable() { + return Err(AnyObjError::new(AnyObjErrorKind::Cast( + T::ANY_TYPE_INFO, + vtable.type_info(), + ))); + } + + // SAFETY: The appropriate type has been type checked for when the + // container was constructed. + unsafe { + let guard = self.shared.as_ref().access.exclusive()?; + let data = vtable.as_ptr(self.shared); + Ok(BorrowMut::new(data, guard.into_raw())) + } + } + + /// Test if the value is sharable. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// let value = value.into_shared::()?; + /// + /// { + /// assert!(value.is_writable()); + /// + /// let borrowed = value.borrow_mut()?; + /// assert!(!value.is_writable()); + /// drop(borrowed); + /// assert!(value.is_writable()); + /// } + /// + /// let foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_ref(&foo)? }; + /// let value = value.into_shared::()?; + /// assert!(value.is_readable()); + /// assert!(!value.is_writable()); + /// } + /// + /// let mut foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_mut(&mut foo)? }; + /// let value = value.into_shared::()?; + /// assert!(value.is_readable()); + /// assert!(value.is_writable()); + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub fn is_readable(&self) -> bool { + // Safety: Since we have a reference to this shared, we know that the + // inner is available. + unsafe { self.shared.as_ref().access.is_shared() } + } + + /// Test if a value is writable. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// let value = value.into_shared::()?; + /// + /// { + /// assert!(value.is_writable()); + /// + /// let borrowed = value.borrow_mut()?; + /// assert!(!value.is_writable()); + /// drop(borrowed); + /// assert!(value.is_writable()); + /// } + /// + /// let foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_ref(&foo)? }; + /// let value = value.into_shared::()?; + /// assert!(value.is_readable()); + /// assert!(!value.is_writable()); + /// } + /// + /// let mut foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_mut(&mut foo)? }; + /// let value = value.into_shared::()?; + /// assert!(value.is_readable()); + /// assert!(value.is_writable()); + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` + pub fn is_writable(&self) -> bool { + unsafe { + let shared = self.shared.as_ref(); + shared.vtable.is_mutable() && shared.access.is_exclusive() + } + } + + /// Debug format the current any type. + pub(crate) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + vtable(self).debug(f) + } + + /// Access the underlying type id for the data. + pub fn type_hash(&self) -> Hash { + vtable(self).type_hash() + } + + /// Access full type info for the underlying type. + pub fn type_info(&self) -> TypeInfo { + vtable(self).type_info() + } +} + +impl fmt::Debug for Shared +where + T: Any, +{ + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.debug(f) + } +} + +impl Drop for Shared { + fn drop(&mut self) { + // Safety: We know that the inner value is live in this instance. + unsafe { + AnyObjData::dec(self.shared); + } + } +} + +#[inline] +pub(super) fn vtable(any: &Shared) -> &'static AnyObjVtable { + unsafe { addr_of!((*any.shared.as_ptr()).vtable).read() } +} + +impl FromValue for Shared +where + T: AnyMarker, +{ + #[inline] + fn from_value(value: Value) -> Result { + value.into_shared() + } +} + +impl ToValue for Shared +where + T: AnyMarker, +{ + #[inline] + fn to_value(self) -> Result { + Ok(Value::from(self.into_any_obj())) + } +} + +impl MaybeTypeOf for Shared +where + T: MaybeTypeOf, +{ + #[inline] + fn maybe_type_of() -> alloc::Result { + T::maybe_type_of() + } +} + +impl TypeHash for Shared +where + T: TypeHash, +{ + const HASH: Hash = T::HASH; +} + +impl TypeOf for Shared +where + T: TypeOf, +{ + const PARAMETERS: Hash = T::PARAMETERS; + const STATIC_TYPE_INFO: AnyTypeInfo = T::STATIC_TYPE_INFO; +} + +impl Clone for Shared +where + T: Any, +{ + #[inline] + fn clone(&self) -> Self { + // SAFETY: We know that the inner value is live in this instance. + unsafe { + AnyObjData::inc(self.shared); + } + + Self { + shared: self.shared, + _marker: PhantomData, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + if ptr::eq(self.shared.as_ptr(), source.shared.as_ptr()) { + return; + } + + let old = replace(&mut self.shared, source.shared); + + // SAFETY: We know that the inner value is live in both instances. + unsafe { + AnyObjData::dec(old); + AnyObjData::inc(self.shared); + } + } +} + +impl TryClone for Shared +where + T: Any, +{ + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(self.clone()) + } + + #[inline] + fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> { + self.clone_from(source); + Ok(()) + } +} diff --git a/crates/rune/src/runtime/stack.rs b/crates/rune/src/runtime/stack.rs index 5570ffa84..c1052c9e2 100644 --- a/crates/rune/src/runtime/stack.rs +++ b/crates/rune/src/runtime/stack.rs @@ -7,7 +7,7 @@ use core::slice; use crate::alloc::alloc::Global; use crate::alloc::prelude::*; use crate::alloc::{self, Vec}; -use crate::runtime::{InstAddress, Output, Value, VmErrorKind}; +use crate::runtime::{Address, Output, Value, VmErrorKind}; // This is a bit tricky. We know that `Value::empty()` is `Sync` but we can't // convince Rust that is the case. @@ -21,7 +21,7 @@ static EMPTY: AssertSync = AssertSync(Value::empty()); #[cfg_attr(test, derive(PartialEq))] #[non_exhaustive] pub struct StackError { - addr: InstAddress, + addr: Address, } impl From for StackError { @@ -45,7 +45,7 @@ impl core::error::Error for StackError {} #[cfg_attr(test, derive(PartialEq))] #[non_exhaustive] pub struct SliceError { - addr: InstAddress, + addr: Address, len: usize, stack: usize, } @@ -77,62 +77,58 @@ pub trait Memory { /// # Examples /// /// ``` - /// use rune::vm_try; - /// use rune::runtime::{Output, Memory, ToValue, VmResult, InstAddress}; + /// use rune::runtime::{Address, Memory, Output, VmError}; /// - /// fn sum(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + /// fn sum(stack: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { /// let mut number = 0; /// - /// for value in vm_try!(stack.slice_at(addr, args)) { - /// number += vm_try!(value.as_integer::()); + /// for value in stack.slice_at(addr, args)? { + /// number += value.as_integer::()?; /// } /// - /// out.store(stack, number); - /// VmResult::Ok(()) + /// out.store(stack, number)?; + /// Ok(()) /// } /// ``` - fn slice_at(&self, addr: InstAddress, len: usize) -> Result<&[Value], SliceError>; + fn slice_at(&self, addr: Address, len: usize) -> Result<&[Value], SliceError>; /// Access the given slice mutably. /// /// # Examples /// /// ``` - /// use rune::vm_try; - /// use rune::runtime::{Output, Memory, InstAddress, Value, VmResult}; + /// use rune::runtime::{Address, Memory, Output, Value, VmError}; /// - /// fn drop_values(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - /// for value in vm_try!(stack.slice_at_mut(addr, args)) { + /// fn drop_values(stack: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { + /// for value in stack.slice_at_mut(addr, args)? { /// *value = Value::empty(); /// } /// - /// out.store(stack, ()); - /// VmResult::Ok(()) + /// out.store(stack, ())?; + /// Ok(()) /// } /// ``` - fn slice_at_mut(&mut self, addr: InstAddress, len: usize) -> Result<&mut [Value], SliceError>; + fn slice_at_mut(&mut self, addr: Address, len: usize) -> Result<&mut [Value], SliceError>; /// Get a value mutable at the given index from the stack bottom. /// /// # Examples /// /// ``` - /// use rune::vm_try; - /// use rune::Module; - /// use rune::runtime::{Output, Memory, VmResult, InstAddress}; - /// - /// fn add_one(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - /// let mut value = vm_try!(stack.at_mut(addr)); - /// let number = vm_try!(value.as_integer::()); - /// *value = vm_try!(rune::to_value(number + 1)); - /// out.store(stack, ()); - /// VmResult::Ok(()) + /// use rune::runtime::{Address, Memory, Output, VmError}; + /// + /// fn add_one(stack: &mut dyn Memory, addr: Address, args: usize, out: Output) -> Result<(), VmError> { + /// let mut value = stack.at_mut(addr)?; + /// let number = value.as_integer::()?; + /// *value = rune::to_value(number + 1)?; + /// out.store(stack, ())?; + /// Ok(()) /// } /// ``` - fn at_mut(&mut self, addr: InstAddress) -> Result<&mut Value, StackError>; + fn at_mut(&mut self, addr: Address) -> Result<&mut Value, StackError>; /// Get the slice at the given address with the given static length. - fn array_at(&self, addr: InstAddress) -> Result<[&Value; N], SliceError> + fn array_at(&self, addr: Address) -> Result<[&Value; N], SliceError> where Self: Sized, { @@ -146,23 +142,23 @@ where M: Memory + ?Sized, { #[inline] - fn slice_at(&self, addr: InstAddress, len: usize) -> Result<&[Value], SliceError> { + fn slice_at(&self, addr: Address, len: usize) -> Result<&[Value], SliceError> { (**self).slice_at(addr, len) } #[inline] - fn slice_at_mut(&mut self, addr: InstAddress, len: usize) -> Result<&mut [Value], SliceError> { + fn slice_at_mut(&mut self, addr: Address, len: usize) -> Result<&mut [Value], SliceError> { (**self).slice_at_mut(addr, len) } #[inline] - fn at_mut(&mut self, addr: InstAddress) -> Result<&mut Value, StackError> { + fn at_mut(&mut self, addr: Address) -> Result<&mut Value, StackError> { (**self).at_mut(addr) } } impl Memory for [Value; N] { - fn slice_at(&self, addr: InstAddress, len: usize) -> Result<&[Value], SliceError> { + fn slice_at(&self, addr: Address, len: usize) -> Result<&[Value], SliceError> { if len == 0 { return Ok(&[]); } @@ -180,7 +176,7 @@ impl Memory for [Value; N] { Ok(values) } - fn slice_at_mut(&mut self, addr: InstAddress, len: usize) -> Result<&mut [Value], SliceError> { + fn slice_at_mut(&mut self, addr: Address, len: usize) -> Result<&mut [Value], SliceError> { if len == 0 { return Ok(&mut []); } @@ -202,7 +198,7 @@ impl Memory for [Value; N] { } #[inline] - fn at_mut(&mut self, addr: InstAddress) -> Result<&mut Value, StackError> { + fn at_mut(&mut self, addr: Address) -> Result<&mut Value, StackError> { let Some(value) = self.get_mut(addr.offset()) else { return Err(StackError { addr }); }; @@ -238,16 +234,16 @@ impl Stack { /// ``` /// use rune::vm_try; /// use rune::Module; - /// use rune::runtime::{Output, Stack, VmResult, InstAddress}; + /// use rune::runtime::{Output, Stack, VmError, Address}; /// - /// fn add_one(stack: &mut Stack, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - /// let value = vm_try!(stack.at(addr).as_integer::()); + /// fn add_one(stack: &mut Stack, addr: Address, args: usize, out: Output) -> Result<(), VmError> { + /// let value = stack.at(addr).as_integer::()?; /// out.store(stack, value + 1); - /// VmResult::Ok(()) + /// Ok(()) /// } /// ``` #[inline(always)] - pub fn at(&self, addr: InstAddress) -> &Value { + pub fn at(&self, addr: Address) -> &Value { self.top .checked_add(addr.offset()) .and_then(|n| self.stack.get(n)) @@ -261,17 +257,17 @@ impl Stack { /// ``` /// use rune::vm_try; /// use rune::Module; - /// use rune::runtime::{Output, Stack, VmResult, InstAddress}; + /// use rune::runtime::{Output, Stack, VmError, Address}; /// - /// fn add_one(stack: &mut Stack, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - /// let mut value = vm_try!(stack.at_mut(addr)); - /// let number = vm_try!(value.as_integer::()); - /// *value = vm_try!(rune::to_value(number + 1)); + /// fn add_one(stack: &mut Stack, addr: Address, args: usize, out: Output) -> Result<(), VmError> { + /// let mut value = stack.at_mut(addr)?; + /// let number = value.as_integer::()?; + /// *value = rune::to_value(number + 1)?; /// out.store(stack, ()); - /// VmResult::Ok(()) + /// Ok(()) /// } /// ``` - pub fn at_mut(&mut self, addr: InstAddress) -> Result<&mut Value, StackError> { + pub fn at_mut(&mut self, addr: Address) -> Result<&mut Value, StackError> { self.top .checked_add(addr.offset()) .and_then(|n| self.stack.get_mut(n)) @@ -285,20 +281,20 @@ impl Stack { /// ``` /// use rune::vm_try; /// use rune::Module; - /// use rune::runtime::{Output, Stack, ToValue, VmResult, InstAddress}; + /// use rune::runtime::{Output, Stack, ToValue, VmError, Address}; /// - /// fn sum(stack: &mut Stack, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + /// fn sum(stack: &mut Stack, addr: Address, args: usize, out: Output) -> Result<(), VmError> { /// let mut number = 0; /// - /// for value in vm_try!(stack.slice_at(addr, args)) { - /// number += vm_try!(value.as_integer::()); + /// for value in stack.slice_at(addr, args)? { + /// number += value.as_integer::()?; /// } /// - /// out.store(stack, number); - /// VmResult::Ok(()) + /// out.store(stack, number)?; + /// Ok(()) /// } /// ``` - pub fn slice_at(&self, addr: InstAddress, len: usize) -> Result<&[Value], SliceError> { + pub fn slice_at(&self, addr: Address, len: usize) -> Result<&[Value], SliceError> { let stack_len = self.stack.len(); if let Some(slice) = inner_slice_at(&self.stack, self.top, addr, len) { @@ -315,23 +311,19 @@ impl Stack { /// ``` /// use rune::vm_try; /// use rune::Module; - /// use rune::runtime::{Output, Stack, VmResult, InstAddress}; + /// use rune::runtime::{Output, Stack, VmError, Address}; /// - /// fn sum(stack: &mut Stack, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { - /// for value in vm_try!(stack.slice_at_mut(addr, args)) { - /// let number = vm_try!(value.as_integer::()); - /// *value = vm_try!(rune::to_value(number + 1)); + /// fn sum(stack: &mut Stack, addr: Address, args: usize, out: Output) -> Result<(), VmError> { + /// for value in stack.slice_at_mut(addr, args)? { + /// let number = value.as_integer::()?; + /// *value = rune::to_value(number + 1)?; /// } /// - /// out.store(stack, ()); - /// VmResult::Ok(()) + /// out.store(stack, ())?; + /// Ok(()) /// } /// ``` - pub fn slice_at_mut( - &mut self, - addr: InstAddress, - len: usize, - ) -> Result<&mut [Value], SliceError> { + pub fn slice_at_mut(&mut self, addr: Address, len: usize) -> Result<&mut [Value], SliceError> { let stack_len = self.stack.len(); if let Some(slice) = inner_slice_at_mut(&mut self.stack, self.top, addr, len) { @@ -343,8 +335,8 @@ impl Stack { /// The current top address of the stack. #[inline] - pub(crate) const fn addr(&self) -> InstAddress { - InstAddress::new(self.stack.len().saturating_sub(self.top)) + pub(crate) const fn addr(&self) -> Address { + Address::new(self.stack.len().saturating_sub(self.top)) } /// Try to resize the stack with space for the given size. @@ -389,7 +381,7 @@ impl Stack { } /// Truncate the stack at the given address. - pub(crate) fn truncate(&mut self, addr: InstAddress) { + pub(crate) fn truncate(&mut self, addr: Address) { if let Some(len) = self.top.checked_add(addr.offset()) { self.stack.truncate(len); } @@ -423,7 +415,7 @@ impl Stack { } /// Swap the value at position a with the value at position b. - pub(crate) fn swap(&mut self, a: InstAddress, b: InstAddress) -> Result<(), StackError> { + pub(crate) fn swap(&mut self, a: Address, b: Address) -> Result<(), StackError> { if a == b { return Ok(()); } @@ -451,7 +443,7 @@ impl Stack { /// /// Returns the old stack top. #[tracing::instrument(skip_all)] - pub(crate) fn swap_top(&mut self, addr: InstAddress, len: usize) -> Result { + pub(crate) fn swap_top(&mut self, addr: Address, len: usize) -> Result { let old_len = self.stack.len(); if len == 0 { @@ -503,7 +495,7 @@ impl Stack { } /// Copy the value at the given address to the output. - pub(crate) fn copy(&mut self, from: InstAddress, out: Output) -> Result<(), StackError> { + pub(crate) fn copy(&mut self, from: Address, out: Output) -> Result<(), StackError> { let Some(to) = out.as_addr() else { return Ok(()); }; @@ -517,7 +509,7 @@ impl Stack { if from.max(to) >= self.stack.len() { return Err(StackError { - addr: InstAddress::new(from.max(to).wrapping_sub(self.top)), + addr: Address::new(from.max(to).wrapping_sub(self.top)), }); } @@ -532,7 +524,7 @@ impl Stack { } /// Get a pair of addresses. - pub(crate) fn pair(&mut self, a: InstAddress, b: InstAddress) -> Result, StackError> { + pub(crate) fn pair(&mut self, a: Address, b: Address) -> Result, StackError> { if a == b { return Ok(Pair::Same(self.at_mut(a)?)); } @@ -560,23 +552,23 @@ impl Stack { impl Memory for Stack { #[inline] - fn slice_at(&self, addr: InstAddress, len: usize) -> Result<&[Value], SliceError> { + fn slice_at(&self, addr: Address, len: usize) -> Result<&[Value], SliceError> { Stack::slice_at(self, addr, len) } #[inline] - fn slice_at_mut(&mut self, addr: InstAddress, len: usize) -> Result<&mut [Value], SliceError> { + fn slice_at_mut(&mut self, addr: Address, len: usize) -> Result<&mut [Value], SliceError> { Stack::slice_at_mut(self, addr, len) } #[inline] - fn at_mut(&mut self, addr: InstAddress) -> Result<&mut Value, StackError> { + fn at_mut(&mut self, addr: Address) -> Result<&mut Value, StackError> { Stack::at_mut(self, addr) } } #[inline(always)] -fn inner_slice_at(values: &[Value], top: usize, addr: InstAddress, len: usize) -> Option<&[Value]> { +fn inner_slice_at(values: &[Value], top: usize, addr: Address, len: usize) -> Option<&[Value]> { if len == 0 { return Some(&[]); } @@ -590,7 +582,7 @@ fn inner_slice_at(values: &[Value], top: usize, addr: InstAddress, len: usize) - fn inner_slice_at_mut( values: &mut [Value], top: usize, - addr: InstAddress, + addr: Address, len: usize, ) -> Option<&mut [Value]> { if len == 0 { @@ -603,7 +595,7 @@ fn inner_slice_at_mut( } #[inline(always)] -fn slice_error(stack: usize, bottom: usize, addr: InstAddress, len: usize) -> SliceError { +fn slice_error(stack: usize, bottom: usize, addr: Address, len: usize) -> SliceError { SliceError { addr, len, diff --git a/crates/rune/src/runtime/static_string.rs b/crates/rune/src/runtime/static_string.rs index 286982ade..aac1d01f5 100644 --- a/crates/rune/src/runtime/static_string.rs +++ b/crates/rune/src/runtime/static_string.rs @@ -3,6 +3,9 @@ use core::fmt; use core::hash; use core::ops; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate::alloc::prelude::*; @@ -10,7 +13,8 @@ use crate::alloc::{self, String}; use crate::hash::{Hash, IntoHash}; /// Struct representing a static string. -#[derive(Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] pub struct StaticString { inner: String, hash: Hash, diff --git a/crates/rune/src/runtime/stream.rs b/crates/rune/src/runtime/stream.rs index 53edc7fc1..0ac63ff77 100644 --- a/crates/rune/src/runtime/stream.rs +++ b/crates/rune/src/runtime/stream.rs @@ -1,10 +1,12 @@ use core::fmt; use crate as rune; +use crate::alloc; use crate::alloc::clone::TryClone; use crate::alloc::fmt::TryWrite; use crate::runtime::{ - Formatter, GeneratorState, Mut, Value, Vm, VmErrorKind, VmExecution, VmResult, + Formatter, GeneratorState, Mut, Value, Vm, VmError, VmErrorKind, VmExecution, VmHaltInfo, + VmOutcome, }; use crate::Any; @@ -28,71 +30,56 @@ use crate::Any; /// assert!(g is Stream); /// ``` #[derive(Any)] -#[rune(impl_params = [Vm], item = ::std::stream)] -pub struct Stream -where - T: AsRef + AsMut, -{ - execution: Option>, +#[rune(item = ::std::stream)] +pub struct Stream { + execution: Option>, } -impl Stream -where - T: AsRef + AsMut, -{ +impl Stream { /// Construct a stream from a virtual machine. - pub(crate) fn new(vm: T) -> Self { + pub(crate) fn new(vm: Vm) -> Self { Self { execution: Some(VmExecution::new(vm)), } } - /// Construct a generator from a complete execution. - pub(crate) fn from_execution(execution: VmExecution) -> Self { - Self { - execution: Some(execution), - } - } - /// Get the next value produced by this stream. - pub async fn next(&mut self) -> VmResult> { + pub async fn next(&mut self) -> Result, VmError> { let Some(execution) = self.execution.as_mut() else { - return VmResult::Ok(None); + return Ok(None); }; - let state = if execution.is_resumed() { - vm_try!(execution.async_resume_with(Value::empty()).await) - } else { - vm_try!(execution.async_resume().await) - }; - - VmResult::Ok(match state { - GeneratorState::Yielded(value) => Some(value), - GeneratorState::Complete(_) => { + match execution.resume().await? { + VmOutcome::Complete(..) => { self.execution = None; - None + Ok(None) } - }) + VmOutcome::Yielded(value) => Ok(Some(value)), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } } - /// Resume the generator and return the next generator state. - pub async fn resume(&mut self, value: Value) -> VmResult { - let execution = vm_try!(self + /// Resume the stream with a value and return the next [`GeneratorState`]. + pub async fn resume(&mut self, value: Value) -> Result { + let execution = self .execution .as_mut() - .ok_or(VmErrorKind::GeneratorComplete)); + .ok_or(VmError::new(VmErrorKind::GeneratorComplete))?; - let state = if execution.is_resumed() { - vm_try!(execution.async_resume_with(value).await) - } else { - vm_try!(execution.async_resume().await) - }; + let outcome = execution.resume().with_value(value).await?; - if state.is_complete() { - self.execution = None; + match outcome { + VmOutcome::Complete(value) => { + self.execution = None; + Ok(GeneratorState::Complete(value)) + } + VmOutcome::Yielded(value) => Ok(GeneratorState::Yielded(value)), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), } - - VmResult::Ok(state) } } @@ -122,7 +109,7 @@ impl Stream { /// assert_eq!(g.next().await, None); /// `` #[rune::function(keep, instance, path = Self::next)] - pub(crate) async fn next_shared(mut this: Mut) -> VmResult> { + pub(crate) async fn next_shared(mut this: Mut) -> Result, VmError> { this.next().await } @@ -172,7 +159,7 @@ impl Stream { pub(crate) async fn resume_shared( mut this: Mut, value: Value, - ) -> VmResult { + ) -> Result { this.resume(value).await } @@ -193,8 +180,8 @@ impl Stream { /// println!("{a:?}"); /// `` #[rune::function(keep, instance, protocol = DEBUG_FMT)] - fn debug(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{self:?}") + fn debug(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{self:?}") } /// Clone a stream. @@ -223,24 +210,12 @@ impl Stream { /// assert_eq!(b.resume(()).await, GeneratorState::Complete(())); /// `` #[rune::function(keep, instance, protocol = CLONE)] - fn clone(&self) -> VmResult { - VmResult::Ok(vm_try!(self.try_clone())) - } -} - -impl Stream<&mut Vm> { - /// Convert the current stream into one which owns its virtual machine. - pub fn into_owned(self) -> Stream { - Stream { - execution: self.execution.map(|e| e.into_owned()), - } + fn clone(&self) -> alloc::Result { + self.try_clone() } } -impl fmt::Debug for Stream -where - T: AsRef + AsMut, -{ +impl fmt::Debug for Stream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Stream") .field("completed", &self.execution.is_none()) @@ -248,10 +223,7 @@ where } } -impl TryClone for Stream -where - T: TryClone + AsRef + AsMut, -{ +impl TryClone for Stream { 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 aa395a9fd..9000162f1 100644 --- a/crates/rune/src/runtime/tests.rs +++ b/crates/rune/src/runtime/tests.rs @@ -13,7 +13,7 @@ use crate::alloc::prelude::*; use crate::support::Result; use crate::Any; -use super::{Access, AnyObj, Bytes, Tuple, TypeHash, Value, VmResult}; +use super::{Access, Address, AnyObj, Bytes, FunctionHandler, Output, Tuple, TypeHash, Value}; #[derive(Debug, PartialEq, Eq, Any)] struct Thing(u32); @@ -35,7 +35,16 @@ impl Wake for NoopWaker { #[test] fn test_take() -> Result<()> { let thing = Value::from(AnyObj::new(Thing(0))?); - let _ = thing.into_any_obj()?; + let _ = thing.into_any_obj()?.take()?; + Ok(()) +} + +#[test] +fn test_take_shared() -> Result<()> { + let thing = Value::from(AnyObj::new(Thing(0))?); + let shared = thing.into_shared::()?; + let inner = shared.take()?; + assert_eq!(inner, Thing(0)); Ok(()) } @@ -51,6 +60,18 @@ fn test_clone_take() -> Result<()> { Ok(()) } +#[test] +fn test_clone_take_shared() -> Result<()> { + let v = Value::from(AnyObj::new(Thing(0))?); + let v2 = v.clone(); + let v3 = v.clone().into_shared::()?; + assert_eq!(Thing(0), v2.downcast::()?); + assert!(v3.take().is_err()); + let any = v.into_any_obj()?; + assert_eq!(any.type_hash(), Thing::HASH); + Ok(()) +} + #[test] fn test_from_ref() -> Result<()> { let value = Thing(10u32); @@ -93,7 +114,7 @@ fn test_from_mut() -> Result<()> { fn ensure_future_dropped_poll() -> crate::support::Result<()> { use crate::runtime::Future; - let mut future = pin!(Future::new(async { VmResult::Ok(10) })?); + let mut future = pin!(Future::new(async { Ok(10) })?); let waker = Arc::new(NoopWaker).into(); let mut cx = Context::from_waker(&waker); @@ -114,9 +135,9 @@ fn ensure_future_dropped_poll() -> crate::support::Result<()> { fn ensure_future_dropped_explicitly() -> crate::support::Result<()> { use crate::runtime::Future; - let mut future = pin!(Future::new(async { VmResult::Ok(10) })?); + let mut future = pin!(Future::new(async { Ok(10) })?); // NB: We cause the future to be dropped explicitly through it's Drop destructor here by replacing it. - future.set(Future::new(async { VmResult::Ok(0) })?); + future.set(Future::new(async { Ok(0) })?); let waker = Arc::new(NoopWaker).into(); let mut cx = Context::from_waker(&waker); @@ -361,3 +382,36 @@ fn test_drop_boxed_tuple() { let boxed = Tuple::from_boxed(boxed); drop(boxed); } + +#[test] +fn test_function_handler() { + use std::thread; + + let handler = FunctionHandler::new(|m, _addr, _count, _out| { + *m.at_mut(Address::ZERO).unwrap() = Value::from(42u32); + Ok(()) + }) + .unwrap(); + + let handler2 = handler.clone(); + + let t = thread::spawn(move || { + let mut memory = [Value::empty()]; + handler + .call(&mut memory, Address::ZERO, 0, Output::discard()) + .unwrap(); + let [value] = memory; + value.as_integer::().unwrap() + }); + + let mut memory = [Value::empty()]; + handler2 + .call(&mut memory, Address::ZERO, 0, Output::discard()) + .unwrap(); + let [value] = memory; + assert_eq!(value.as_integer::().unwrap(), 42); + + assert_eq!(t.join().unwrap(), 42); + + drop(handler2); +} diff --git a/crates/rune/src/runtime/to_value.rs b/crates/rune/src/runtime/to_value.rs index f48a4a311..3daa5da9d 100644 --- a/crates/rune/src/runtime/to_value.rs +++ b/crates/rune/src/runtime/to_value.rs @@ -2,7 +2,7 @@ use crate::alloc::prelude::*; use crate::alloc::{self, HashMap}; use crate::any::AnyMarker; -use super::{AnyObj, Object, RuntimeError, Value, VmResult}; +use super::{AnyObj, Object, RuntimeError, Value, VmError}; /// Derive macro for the [`ToValue`] trait for converting types into the dynamic /// `Value` container. @@ -112,31 +112,21 @@ pub trait ToValue: Sized { } /// Trait governing things that can be returned from native functions. -pub trait ToReturn: Sized { - /// Convert something into a return value. - fn to_return(self) -> VmResult; -} - -impl ToReturn for VmResult +pub trait IntoReturn where - T: ToValue, + Self: Sized, { - #[inline] - fn to_return(self) -> VmResult { - match self { - VmResult::Ok(value) => VmResult::Ok(vm_try!(value.to_value())), - VmResult::Err(error) => VmResult::Err(error), - } - } + /// Convert something into a return value. + fn into_return(self) -> Result; } -impl ToReturn for T +impl IntoReturn for T where T: ToValue, { #[inline] - fn to_return(self) -> VmResult { - VmResult::Ok(vm_try!(T::to_value(self))) + fn into_return(self) -> Result { + Ok(T::to_value(self)?) } } @@ -225,8 +215,7 @@ impl ToValue for &str { } } -#[cfg(feature = "alloc")] -impl ToValue for ::rust_alloc::boxed::Box { +impl ToValue for rust_alloc::boxed::Box { #[inline] fn to_value(self) -> Result { let this = self.try_to_string()?; @@ -234,8 +223,7 @@ impl ToValue for ::rust_alloc::boxed::Box { } } -#[cfg(feature = "alloc")] -impl ToValue for ::rust_alloc::string::String { +impl ToValue for rust_alloc::string::String { #[inline] fn to_value(self) -> Result { let string = alloc::String::try_from(self)?; @@ -281,10 +269,10 @@ macro_rules! impl_map { }; } -impl_map!(HashMap<::rust_alloc::string::String, T>); +impl_map!(HashMap); impl_map!(HashMap); cfg_std! { - impl_map!(::std::collections::HashMap<::rust_alloc::string::String, T>); + impl_map!(::std::collections::HashMap); impl_map!(::std::collections::HashMap); } diff --git a/crates/rune/src/runtime/tuple.rs b/crates/rune/src/runtime/tuple.rs index c08003dd9..362f0e6ad 100644 --- a/crates/rune/src/runtime/tuple.rs +++ b/crates/rune/src/runtime/tuple.rs @@ -13,11 +13,10 @@ use crate::alloc::{self, Box}; use crate::Any; use super::{ - ConstValue, EmptyConstContext, Formatter, FromConstValue, FromValue, Mut, RawAnyGuard, Ref, - RuntimeError, ToConstValue, ToValue, UnsafeToMut, UnsafeToRef, Value, VmErrorKind, VmResult, + ConstValue, EmptyConstContext, Formatter, FromConstValue, FromValue, Hasher, Mut, + ProtocolCaller, RawAnyGuard, Ref, RuntimeError, ToConstValue, ToValue, UnsafeToMut, + UnsafeToRef, Value, VmError, VmErrorKind, }; -#[cfg(feature = "alloc")] -use super::{Hasher, ProtocolCaller}; /// The type of a tuple slice. #[repr(transparent)] @@ -46,59 +45,62 @@ impl Tuple { } /// Get the given value at the given index. - pub fn get_value(&self, index: usize) -> VmResult> + pub fn get_value(&self, index: usize) -> Result, VmError> where T: FromValue, { let value = match self.values.get(index) { Some(value) => value.clone(), - None => return VmResult::Ok(None), + None => return Ok(None), }; - VmResult::Ok(Some(vm_try!(T::from_value(value)))) + Ok(Some(T::from_value(value)?)) } pub(crate) fn hash_with( &self, hasher: &mut Hasher, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { for value in self.values.iter() { - vm_try!(value.hash_with(hasher, caller)); + value.hash_with(hasher, caller)?; } - VmResult::Ok(()) + Ok(()) } pub(crate) fn debug_fmt_with( &self, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let mut it = self.iter().peekable(); - vm_try!(vm_write!(f, "(")); + write!(f, "(")?; while let Some(value) = it.next() { - vm_try!(value.debug_fmt_with(f, caller)); + value.debug_fmt_with(f, caller)?; if it.peek().is_some() { - vm_try!(vm_write!(f, ", ")); + write!(f, ", ")?; } } - vm_try!(vm_write!(f, ")")); - VmResult::Ok(()) + write!(f, ")")?; + Ok(()) } - pub(crate) fn clone_with(&self, caller: &mut dyn ProtocolCaller) -> VmResult { - let mut vec = vm_try!(alloc::Vec::try_with_capacity(self.len())); + pub(crate) fn clone_with( + &self, + caller: &mut dyn ProtocolCaller, + ) -> Result { + let mut vec = alloc::Vec::try_with_capacity(self.len())?; for value in self.values.iter() { - let value = vm_try!(value.clone_with(caller)); - vm_try!(vec.try_push(value)); + let value = value.clone_with(caller)?; + vec.try_push(value)?; } - VmResult::Ok(vm_try!(OwnedTuple::try_from(vec))) + Ok(OwnedTuple::try_from(vec)?) } } @@ -252,12 +254,11 @@ impl fmt::Debug for OwnedTuple { } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::vec::Vec> for OwnedTuple { +impl TryFrom> for OwnedTuple { type Error = alloc::Error; #[inline] - fn try_from(vec: ::rust_alloc::vec::Vec) -> Result { + fn try_from(vec: rust_alloc::vec::Vec) -> Result { Ok(Self { inner: alloc::Box::try_from(vec.into_boxed_slice())?, }) @@ -313,23 +314,22 @@ impl TryFrom> for OwnedTuple { } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::boxed::Box<[Value]>> for OwnedTuple { +impl TryFrom> for OwnedTuple { type Error = alloc::Error; #[inline] - fn try_from(inner: ::rust_alloc::boxed::Box<[Value]>) -> alloc::Result { + fn try_from(inner: rust_alloc::boxed::Box<[Value]>) -> alloc::Result { Ok(Self { inner: alloc::Box::try_from(inner)?, }) } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::boxed::Box<[ConstValue]>> for OwnedTuple { +impl TryFrom> for OwnedTuple { type Error = RuntimeError; - fn try_from(inner: ::rust_alloc::boxed::Box<[ConstValue]>) -> Result { + #[inline] + fn try_from(inner: rust_alloc::boxed::Box<[ConstValue]>) -> Result { if inner.is_empty() { return Ok(OwnedTuple::new()); } diff --git a/crates/rune/src/runtime/type_.rs b/crates/rune/src/runtime/type.rs similarity index 74% rename from crates/rune/src/runtime/type_.rs rename to crates/rune/src/runtime/type.rs index 106454fbb..e1729436f 100644 --- a/crates/rune/src/runtime/type_.rs +++ b/crates/rune/src/runtime/type.rs @@ -1,4 +1,6 @@ +#[cfg(feature = "musli")] use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; @@ -8,12 +10,10 @@ use crate::runtime::RuntimeError; use crate::{item, FromValue, Hash, Item, Value}; /// A value representing a type in the virtual machine. -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Decode, Encode, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] -#[serde(transparent)] -#[musli(transparent)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))] pub struct Type(Hash); impl Type { diff --git a/crates/rune/src/runtime/type_info.rs b/crates/rune/src/runtime/type_info.rs index 4e845f204..71d02fce3 100644 --- a/crates/rune/src/runtime/type_info.rs +++ b/crates/rune/src/runtime/type_info.rs @@ -7,7 +7,7 @@ use crate::compile::Named; use crate::hash::Hash; use crate::{Any, TypeHash}; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use super::Rtti; diff --git a/crates/rune/src/runtime/unit.rs b/crates/rune/src/runtime/unit.rs index f89cc6597..5fdec630e 100644 --- a/crates/rune/src/runtime/unit.rs +++ b/crates/rune/src/runtime/unit.rs @@ -9,16 +9,22 @@ mod storage; use core::fmt; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; +#[cfg(feature = "musli")] +use musli::mode::Binary; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::de::DeserializeOwned; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; use crate::alloc::prelude::*; use crate::alloc::{self, Box, String, Vec}; use crate::hash; -use crate::runtime::{Call, ConstValue, DebugInfo, Inst, InstAddress, Rtti, StaticString}; +use crate::runtime::{Address, Call, ConstValue, DebugInfo, Inst, Rtti, StaticString}; use crate::Hash; pub use self::storage::{ArrayUnit, EncodeError, UnitEncoder, UnitStorage}; @@ -37,12 +43,15 @@ pub type DefaultStorage = ByteCodeUnit; /// Instructions and debug info from a single compilation. /// /// See [`rune::prepare`] for more. -#[derive(Debug, TryClone, Default, Serialize, Deserialize)] -#[serde(bound = "S: Serialize + DeserializeOwned")] +#[derive(Debug, TryClone, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(bound = "S: Serialize + DeserializeOwned"))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] +#[cfg_attr(feature = "musli", musli(Binary, bound = {S: Encode}, decode_bound<'de, A> = {S: Decode<'de, Binary, A>}))] #[try_clone(bound = {S: TryClone})] pub struct Unit { /// The information needed to execute the program. - #[serde(flatten)] + #[cfg_attr(feature = "serde", serde(flatten))] logic: Logic, /// Debug info if available for unit. debug: Option>, @@ -51,8 +60,13 @@ pub struct Unit { assert_impl!(Unit: Send + Sync); /// Instructions from a single source file. -#[derive(Debug, TryClone, Default, Serialize, Deserialize)] -#[serde(rename = "Unit")] +#[derive(Debug, TryClone, Default)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename = "Unit") +)] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] #[try_clone(bound = {S: TryClone})] pub struct Logic { /// Storage for the unit. @@ -71,7 +85,7 @@ pub struct Logic { /// All keys are sorted with the default string sort. static_object_keys: Vec>, /// Drop sets. - drop_sets: Vec>, + drop_sets: Vec>, /// Runtime information for types. rtti: hash::Map>, /// Named constants @@ -97,7 +111,7 @@ impl Unit { static_strings: Vec>, static_bytes: Vec>, static_object_keys: Vec>, - drop_sets: Vec>, + drop_sets: Vec>, rtti: hash::Map>, debug: Option>, constants: hash::Map, @@ -152,7 +166,7 @@ impl Unit { /// Iterate over all available drop sets. #[cfg(feature = "cli")] #[inline] - pub(crate) fn iter_static_drop_sets(&self) -> impl Iterator + '_ { + pub(crate) fn iter_static_drop_sets(&self) -> impl Iterator + '_ { self.logic.drop_sets.iter().map(|v| &**v) } @@ -203,7 +217,7 @@ impl Unit { } #[inline] - pub(crate) fn lookup_drop_set(&self, set: usize) -> Option<&[InstAddress]> { + pub(crate) fn lookup_drop_set(&self, set: usize) -> Option<&[Address]> { Some(self.logic.drop_sets.get(set)?) } @@ -253,7 +267,9 @@ where } /// The kind and necessary information on registered functions. -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] #[non_exhaustive] pub(crate) enum UnitFn { /// Instruction offset of a function inside of the unit. diff --git a/crates/rune/src/runtime/unit/byte_code.rs b/crates/rune/src/runtime/unit/byte_code.rs index c2c2f3076..035b20bd5 100644 --- a/crates/rune/src/runtime/unit/byte_code.rs +++ b/crates/rune/src/runtime/unit/byte_code.rs @@ -1,5 +1,10 @@ use core::mem::size_of; +#[cfg(feature = "byte-code")] +use musli::storage; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; @@ -11,11 +16,13 @@ use crate::runtime::Inst; /// Unit stored as byte code, which is a more compact representation than /// `ArrayUnit`, but takes more time to execute since it needs to be decoded as /// it's being executed. -#[derive(Debug, TryClone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] pub struct ByteCodeUnit { /// The instructions contained in the source file. - #[try_clone(with = Clone::clone)] - bytes: rust_alloc::vec::Vec, + #[cfg_attr(feature = "musli", musli(bytes))] + bytes: Vec, /// Known jump offsets. offsets: Vec, } @@ -36,7 +43,7 @@ impl Iterator for ByteCodeUnitIter<'_> { } let ip = self.len.checked_sub(self.address.len())?; - let inst = musli::storage::decode(self.address).ok()?; + let inst = storage::decode(self.address).ok()?; Some((ip, inst)) } } @@ -49,7 +56,7 @@ impl UnitEncoder for ByteCodeUnit { #[inline] fn encode(&mut self, inst: Inst) -> Result<(), EncodeError> { - musli::storage::encode(&mut self.bytes, &inst)?; + storage::to_writer(&mut self.bytes, &inst)?; Ok(()) } @@ -102,7 +109,7 @@ impl UnitStorage for ByteCodeUnit { }; let start = bytes.as_ptr(); - let inst: Inst = musli::storage::decode(bytes).map_err(|_| BadInstruction { ip })?; + let inst: Inst = storage::decode(bytes).map_err(|_| BadInstruction { ip })?; let len = (bytes.as_ptr() as usize).wrapping_sub(start as usize); Ok(Some((inst, len))) } diff --git a/crates/rune/src/runtime/unit/storage.rs b/crates/rune/src/runtime/unit/storage.rs index 62b16d5d5..3fc533a14 100644 --- a/crates/rune/src/runtime/unit/storage.rs +++ b/crates/rune/src/runtime/unit/storage.rs @@ -9,6 +9,9 @@ use crate::alloc::{self, Vec}; #[cfg(feature = "byte-code")] use musli::storage; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate::runtime::Inst; @@ -76,7 +79,9 @@ pub trait UnitStorage: self::sealed::Sealed + fmt::Debug + Default { } /// Unit stored as array of instructions. -#[derive(Debug, TryClone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] pub struct ArrayUnit { instructions: Vec, } diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 9620a1344..cf238ef80 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -7,6 +7,7 @@ mod tests; mod inline; pub use self::inline::Inline; +#[cfg(feature = "serde")] mod serde; mod rtti; @@ -16,9 +17,9 @@ pub use self::rtti::{Accessor, Rtti}; mod data; pub use self::data::{EmptyStruct, Struct, TupleStruct}; -mod dynamic; -pub use self::dynamic::Dynamic; -pub(crate) use self::dynamic::DynamicTakeError; +mod any_sequence; +pub use self::any_sequence::AnySequence; +pub(crate) use self::any_sequence::AnySequenceTakeError; use core::any; use core::cmp::Ordering; @@ -26,7 +27,7 @@ use core::fmt; use core::mem::replace; use core::ptr::NonNull; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; @@ -36,16 +37,15 @@ use crate::{Any, Hash, TypeHash}; use super::{ AccessError, AnyObj, AnyObjDrop, BorrowMut, BorrowRef, CallResultOnly, ConstValue, - ConstValueKind, DynGuardedArgs, EnvProtocolCaller, Formatter, FromValue, Future, IntoOutput, - Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, Protocol, ProtocolCaller, RawAnyObjGuard, Ref, - RuntimeError, Snapshot, Type, TypeInfo, Vec, VmErrorKind, VmIntegerRepr, VmResult, + ConstValueKind, DynGuardedArgs, EnvProtocolCaller, Formatter, FromValue, Future, Hasher, + IntoOutput, Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, Protocol, ProtocolCaller, + RawAnyObjGuard, Ref, RuntimeError, Shared, Snapshot, Tuple, Type, TypeInfo, Vec, VmError, + VmErrorKind, VmIntegerRepr, }; -#[cfg(feature = "alloc")] -use super::{Hasher, Tuple}; /// Defined guard for a reference value. /// -/// See [Value::from_ref]. +/// See [`Value::from_ref`]. pub struct ValueRefGuard { #[allow(unused)] guard: AnyObjDrop, @@ -53,30 +53,22 @@ pub struct ValueRefGuard { /// Defined guard for a reference value. /// -/// See [Value::from_mut]. +/// See [`Value::from_mut`]. pub struct ValueMutGuard { #[allow(unused)] guard: AnyObjDrop, } -/// The guard returned by [Value::into_any_mut_ptr]. +/// The guard returned by [`Value::into_any_mut_ptr`]. pub struct RawValueGuard { #[allow(unused)] guard: RawAnyObjGuard, } -// Small helper function to build errors. -fn err(error: E) -> VmResult -where - VmErrorKind: From, -{ - VmResult::err(error) -} - #[derive(Clone)] pub(crate) enum Repr { Inline(Inline), - Dynamic(Dynamic, Value>), + Dynamic(AnySequence, Value>), Any(AnyObj), } @@ -204,7 +196,7 @@ impl Value { /// /// ``` /// use rune::Any; - /// use rune::runtime::{Value, VmResult}; + /// use rune::runtime::Value; /// /// #[derive(Any)] /// struct Foo(u32); @@ -253,6 +245,43 @@ impl Value { } /// Test if the value is writable. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// + /// { + /// assert!(value.is_writable()); + /// + /// let borrowed = value.borrow_mut::()?; + /// assert!(!value.is_writable()); + /// drop(borrowed); + /// assert!(value.is_writable()); + /// } + /// + /// let foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_ref(&foo)? }; + /// assert!(value.is_readable()); + /// assert!(!value.is_writable()); + /// } + /// + /// let mut foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_mut(&mut foo)? }; + /// assert!(value.is_readable()); + /// assert!(value.is_writable()); + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` pub fn is_writable(&self) -> bool { match self.repr { Repr::Inline(Inline::Empty) => false, @@ -262,7 +291,44 @@ impl Value { } } - /// Test if the value is readable. + /// Test if a value is readable. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Value}; + /// + /// #[derive(Any)] + /// struct Struct(u32); + /// + /// let value = Value::new(Struct(42))?; + /// + /// { + /// assert!(value.is_writable()); + /// + /// let borrowed = value.borrow_mut::()?; + /// assert!(!value.is_writable()); + /// drop(borrowed); + /// assert!(value.is_writable()); + /// } + /// + /// let foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_ref(&foo)? }; + /// assert!(value.is_readable()); + /// assert!(!value.is_writable()); + /// } + /// + /// let mut foo = Struct(42); + /// + /// { + /// let (value, guard) = unsafe { Value::from_mut(&mut foo)? }; + /// assert!(value.is_readable()); + /// assert!(value.is_writable()); + /// } + /// # Ok::<_, rune::support::Error>(()) + /// ``` pub fn is_readable(&self) -> bool { match &self.repr { Repr::Inline(Inline::Empty) => false, @@ -298,7 +364,7 @@ impl Value { /// This function errors if called outside of a virtual machine. /// /// [`DISPLAY_FMT`]: Protocol::DISPLAY_FMT - pub fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> { + pub fn display_fmt(&self, f: &mut Formatter) -> Result<(), VmError> { self.display_fmt_with(f, &mut EnvProtocolCaller) } @@ -308,27 +374,27 @@ impl Value { &self, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { 'fallback: { match self.as_ref() { Repr::Inline(value) => match value { Inline::Char(c) => { - vm_try!(f.try_write_char(*c)); + f.try_write_char(*c)?; } Inline::Unsigned(byte) => { let mut buffer = itoa::Buffer::new(); - vm_try!(f.try_write_str(buffer.format(*byte))); + f.try_write_str(buffer.format(*byte))?; } Inline::Signed(integer) => { let mut buffer = itoa::Buffer::new(); - vm_try!(f.try_write_str(buffer.format(*integer))); + f.try_write_str(buffer.format(*integer))?; } Inline::Float(float) => { let mut buffer = ryu::Buffer::new(); - vm_try!(f.try_write_str(buffer.format(*float))); + f.try_write_str(buffer.format(*float))?; } Inline::Bool(bool) => { - vm_try!(vm_write!(f, "{bool}")); + write!(f, "{bool}")?; } _ => { break 'fallback; @@ -339,16 +405,15 @@ impl Value { } } - return VmResult::Ok(()); + return Ok(()); }; let mut args = DynGuardedArgs::new((f,)); - let result = - vm_try!(caller.call_protocol_fn(&Protocol::DISPLAY_FMT, self.clone(), &mut args)); + let result = caller.call_protocol_fn(&Protocol::DISPLAY_FMT, self.clone(), &mut args)?; - vm_try!(<()>::from_value(result)); - VmResult::Ok(()) + <()>::from_value(result)?; + Ok(()) } /// Perform a shallow clone of the value using the [`CLONE`] protocol. @@ -363,31 +428,27 @@ impl Value { /// This function errors if called outside of a virtual machine. /// /// [`CLONE`]: Protocol::CLONE - pub fn clone_(&self) -> VmResult { + pub fn clone_(&self) -> Result { self.clone_with(&mut EnvProtocolCaller) } - pub(crate) fn clone_with(&self, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn clone_with(&self, caller: &mut dyn ProtocolCaller) -> Result { match self.as_ref() { Repr::Inline(value) => { - return VmResult::Ok(Self { + return Ok(Self { repr: Repr::Inline(*value), }); } Repr::Dynamic(value) => { // TODO: This type of cloning should be deep, not shallow. - return VmResult::Ok(Self { + return Ok(Self { repr: Repr::Dynamic(value.clone()), }); } Repr::Any(..) => {} } - VmResult::Ok(vm_try!(caller.call_protocol_fn( - &Protocol::CLONE, - self.clone(), - &mut () - ))) + caller.call_protocol_fn(&Protocol::CLONE, self.clone(), &mut ()) } /// Debug format the value using the [`DEBUG_FMT`] protocol. @@ -402,7 +463,7 @@ impl Value { /// This function errors if called outside of a virtual machine. /// /// [`DEBUG_FMT`]: Protocol::DEBUG_FMT - pub fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { + pub fn debug_fmt(&self, f: &mut Formatter) -> Result<(), VmError> { self.debug_fmt_with(f, &mut EnvProtocolCaller) } @@ -411,44 +472,40 @@ impl Value { &self, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { match &self.repr { Repr::Inline(value) => { - vm_try!(vm_write!(f, "{value:?}")); + write!(f, "{value:?}")?; } Repr::Dynamic(ref value) => { - vm_try!(value.debug_fmt_with(f, caller)); + value.debug_fmt_with(f, caller)?; } Repr::Any(..) => { // reborrow f to avoid moving it let mut args = DynGuardedArgs::new((&mut *f,)); - match vm_try!(caller.try_call_protocol_fn( - &Protocol::DEBUG_FMT, - self.clone(), - &mut args - )) { + match caller.try_call_protocol_fn(&Protocol::DEBUG_FMT, self.clone(), &mut args)? { CallResultOnly::Ok(value) => { - vm_try!(<()>::from_value(value)); + <()>::from_value(value)?; } CallResultOnly::Unsupported(value) => match &value.repr { Repr::Inline(value) => { - vm_try!(vm_write!(f, "{value:?}")); + write!(f, "{value:?}")?; } Repr::Dynamic(value) => { let ty = value.type_info(); - vm_try!(vm_write!(f, "<{ty} object at {value:p}>")); + write!(f, "<{ty} object at {value:p}>")?; } Repr::Any(value) => { let ty = value.type_info(); - vm_try!(vm_write!(f, "<{ty} object at {value:p}>")); + write!(f, "<{ty} object at {value:p}>")?; } }, } } } - VmResult::Ok(()) + Ok(()) } /// Convert value into an iterator using the [`Protocol::INTO_ITER`] @@ -462,13 +519,16 @@ impl Value { /// # Errors /// /// This function will error if called outside of a virtual machine context. - pub fn into_iter(self) -> VmResult { + pub fn into_iter(self) -> Result { self.into_iter_with(&mut EnvProtocolCaller) } - pub(crate) fn into_iter_with(self, caller: &mut dyn ProtocolCaller) -> VmResult { - let value = vm_try!(caller.call_protocol_fn(&Protocol::INTO_ITER, self, &mut ())); - VmResult::Ok(Iterator::new(value)) + pub(crate) fn into_iter_with( + self, + caller: &mut dyn ProtocolCaller, + ) -> Result { + let value = caller.call_protocol_fn(&Protocol::INTO_ITER, self, &mut ())?; + Ok(Iterator::new(value)) } /// Retrieves a human readable type name for the current value. @@ -485,29 +545,33 @@ impl Value { /// environment. /// /// [`Vm`]: crate::Vm - pub fn into_type_name(self) -> VmResult { + pub fn into_type_name(self) -> Result { let hash = Hash::associated_function(self.type_hash(), &Protocol::INTO_TYPE_NAME); crate::runtime::env::shared(|context, unit| { if let Some(name) = context.constant(&hash) { match name.as_kind() { - ConstValueKind::String(s) => { - return VmResult::Ok(vm_try!(String::try_from(s.as_str()))) + ConstValueKind::String(s) => return Ok(String::try_from(s.as_str())?), + _ => { + return Err(VmError::new(VmErrorKind::expected::( + name.type_info(), + ))) } - _ => return err(VmErrorKind::expected::(name.type_info())), } } if let Some(name) = unit.constant(&hash) { match name.as_kind() { - ConstValueKind::String(s) => { - return VmResult::Ok(vm_try!(String::try_from(s.as_str()))) + ConstValueKind::String(s) => return Ok(String::try_from(s.as_str())?), + _ => { + return Err(VmError::new(VmErrorKind::expected::( + name.type_info(), + ))) } - _ => return err(VmErrorKind::expected::(name.type_info())), } } - VmResult::Ok(vm_try!(self.type_info().try_to_string())) + Ok(self.type_info().try_to_string()?) }) } @@ -524,7 +588,7 @@ impl Value { /// Construct an empty. pub fn empty_struct(rtti: Arc) -> alloc::Result { - Ok(Value::from(Dynamic::new(rtti, [])?)) + Ok(Value::from(AnySequence::new(rtti, [])?)) } /// Construct a typed tuple. @@ -532,34 +596,37 @@ impl Value { rtti: Arc, data: impl IntoIterator, ) -> alloc::Result { - Ok(Value::from(Dynamic::new(rtti, data)?)) + Ok(Value::from(AnySequence::new(rtti, data)?)) } /// Drop the interior value. - pub(crate) fn drop(self) -> VmResult<()> { + /// + /// This consumes any live references of the value and accessing them in the + /// future will result in an error. + pub(crate) fn drop(self) -> Result<(), VmError> { match self.repr { Repr::Dynamic(value) => { - vm_try!(value.drop()); + value.drop()?; } Repr::Any(value) => { - vm_try!(value.drop()); + value.drop()?; } _ => {} } - VmResult::Ok(()) + Ok(()) } /// Move the interior value. - pub(crate) fn move_(self) -> VmResult { + pub(crate) fn move_(self) -> Result { match self.repr { - Repr::Dynamic(value) => VmResult::Ok(Value { - repr: Repr::Dynamic(vm_try!(value.take())), + Repr::Dynamic(value) => Ok(Value { + repr: Repr::Dynamic(value.take()?), }), - Repr::Any(value) => VmResult::Ok(Value { - repr: Repr::Any(vm_try!(value.take())), + Repr::Any(value) => Ok(Value { + repr: Repr::Any(value.take()?), }), - repr => VmResult::Ok(Value { repr }), + repr => Ok(Value { repr }), } } @@ -773,8 +840,6 @@ impl Value { } /// Coerce into an [`AnyObj`]. - /// - /// This consumes the underlying value. #[inline] pub fn into_any_obj(self) -> Result { match self.repr { @@ -784,6 +849,22 @@ impl Value { } } + /// Coerce into a [`Shared`]. + /// + /// This type checks and coerces the value into a type which statically + /// guarantees that the underlying type is of the given type. + #[inline] + pub fn into_shared(self) -> Result, RuntimeError> + where + T: Any, + { + match self.repr { + Repr::Inline(value) => Err(RuntimeError::expected_any_obj(value.type_info())), + Repr::Dynamic(value) => Err(RuntimeError::expected_any_obj(value.type_info())), + Repr::Any(value) => Ok(value.into_shared()?), + } + } + /// Coerce into a future, or convert into a future using the /// [Protocol::INTO_FUTURE] protocol. /// @@ -811,9 +892,7 @@ impl Value { repr => Value::from(repr), }; - let value = EnvProtocolCaller - .call_protocol_fn(&Protocol::INTO_FUTURE, target, &mut ()) - .into_result()?; + let value = EnvProtocolCaller.call_protocol_fn(&Protocol::INTO_FUTURE, target, &mut ())?; Future::from_value(value) } @@ -875,7 +954,7 @@ impl Value { /// /// # Examples /// - /// ```rust + /// ``` /// use rune::Value; /// use rune::alloc::String; /// @@ -908,7 +987,7 @@ impl Value { /// /// # Examples /// - /// ```rust + /// ``` /// use rune::Value; /// use rune::alloc::String; /// @@ -946,7 +1025,7 @@ impl Value { /// /// # Examples /// - /// ```rust + /// ``` /// use rune::Value; /// use rune::alloc::String; /// @@ -992,7 +1071,7 @@ impl Value { /// /// # Examples /// - /// ```rust + /// ``` /// use rune::{Mut, Value}; /// use rune::alloc::String; /// @@ -1055,7 +1134,7 @@ impl Value { /// # Errors /// /// This function will error if called outside of a virtual machine context. - pub fn partial_eq(a: &Value, b: &Value) -> VmResult { + pub fn partial_eq(a: &Value, b: &Value) -> Result { Self::partial_eq_with(a, b, &mut EnvProtocolCaller) } @@ -1067,7 +1146,7 @@ impl Value { &self, b: &Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { self.bin_op_with( b, caller, @@ -1075,7 +1154,7 @@ impl Value { Inline::partial_eq, |lhs, rhs, caller| { if lhs.0.variant_hash != rhs.0.variant_hash { - return VmResult::Ok(false); + return Ok(false); } Vec::eq_with(lhs.1, rhs.1, Value::partial_eq_with, caller) @@ -1093,7 +1172,7 @@ impl Value { /// # Errors /// /// This function will error if called outside of a virtual machine context. - pub fn eq(&self, b: &Value) -> VmResult { + pub fn eq(&self, b: &Value) -> Result { self.eq_with(b, &mut EnvProtocolCaller) } @@ -1101,10 +1180,14 @@ impl Value { /// /// This is the basis for the eq operation (`==`). #[cfg_attr(feature = "bench", inline(never))] - pub(crate) fn eq_with(&self, b: &Value, caller: &mut dyn ProtocolCaller) -> VmResult { + pub(crate) fn eq_with( + &self, + b: &Value, + caller: &mut dyn ProtocolCaller, + ) -> Result { self.bin_op_with(b, caller, &Protocol::EQ, Inline::eq, |lhs, rhs, caller| { if lhs.0.variant_hash != rhs.0.variant_hash { - return VmResult::Ok(false); + return Ok(false); } Vec::eq_with(lhs.1, rhs.1, Value::eq_with, caller) @@ -1121,7 +1204,7 @@ impl Value { /// # Errors /// /// This function will error if called outside of a virtual machine context. - pub fn partial_cmp(a: &Value, b: &Value) -> VmResult> { + pub fn partial_cmp(a: &Value, b: &Value) -> Result, VmError> { Value::partial_cmp_with(a, b, &mut EnvProtocolCaller) } @@ -1133,7 +1216,7 @@ impl Value { &self, b: &Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { self.bin_op_with( b, caller, @@ -1143,7 +1226,7 @@ impl Value { let ord = lhs.0.variant_hash.cmp(&rhs.0.variant_hash); if ord != Ordering::Equal { - return VmResult::Ok(Some(ord)); + return Ok(Some(ord)); } Vec::partial_cmp_with(lhs.1, rhs.1, caller) @@ -1161,7 +1244,7 @@ impl Value { /// # Errors /// /// This function will error if called outside of a virtual machine context. - pub fn cmp(a: &Value, b: &Value) -> VmResult { + pub fn cmp(a: &Value, b: &Value) -> Result { Value::cmp_with(a, b, &mut EnvProtocolCaller) } @@ -1173,7 +1256,7 @@ impl Value { &self, b: &Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { self.bin_op_with( b, caller, @@ -1183,7 +1266,7 @@ impl Value { let ord = lhs.0.variant_hash.cmp(&rhs.0.variant_hash); if ord != Ordering::Equal { - return VmResult::Ok(ord); + return Ok(ord); } Vec::cmp_with(lhs.1, rhs.1, caller) @@ -1192,8 +1275,7 @@ impl Value { } /// Hash the current value. - #[cfg(feature = "alloc")] - pub fn hash(&self, hasher: &mut Hasher) -> VmResult<()> { + pub fn hash(&self, hasher: &mut Hasher) -> Result<(), VmError> { self.hash_with(hasher, &mut EnvProtocolCaller) } @@ -1203,19 +1285,19 @@ impl Value { &self, hasher: &mut Hasher, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { match self.as_ref() { Repr::Inline(value) => { - vm_try!(value.hash(hasher)); - return VmResult::Ok(()); + value.hash(hasher)?; + return Ok(()); } Repr::Any(value) => match value.type_hash() { Vec::HASH => { - let vec = vm_try!(value.borrow_ref::()); + let vec = value.borrow_ref::()?; return Vec::hash_with(&vec, hasher, caller); } OwnedTuple::HASH => { - let tuple = vm_try!(value.borrow_ref::()); + let tuple = value.borrow_ref::()?; return Tuple::hash_with(&tuple, hasher, caller); } _ => {} @@ -1226,16 +1308,16 @@ impl Value { let mut args = DynGuardedArgs::new((hasher,)); if let CallResultOnly::Ok(value) = - vm_try!(caller.try_call_protocol_fn(&Protocol::HASH, self.clone(), &mut args)) + caller.try_call_protocol_fn(&Protocol::HASH, self.clone(), &mut args)? { - vm_try!(<()>::from_value(value)); - return VmResult::Ok(()); + <()>::from_value(value)?; + return Ok(()); } - err(VmErrorKind::UnsupportedUnaryOperation { + Err(VmError::new(VmErrorKind::UnsupportedUnaryOperation { op: Protocol::HASH.name, operand: self.type_info(), - }) + })) } fn bin_op_with( @@ -1248,53 +1330,51 @@ impl Value { (&Arc, &[Value]), (&Arc, &[Value]), &mut dyn ProtocolCaller, - ) -> VmResult, - ) -> VmResult + ) -> Result, + ) -> Result where T: FromValue, { match (self.as_ref(), b.as_ref()) { - (Repr::Inline(lhs), Repr::Inline(rhs)) => { - return VmResult::Ok(vm_try!(inline(lhs, rhs))) - } + (Repr::Inline(lhs), Repr::Inline(rhs)) => return Ok(inline(lhs, rhs)?), (Repr::Inline(lhs), rhs) => { - return VmResult::err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } (Repr::Dynamic(lhs), Repr::Dynamic(rhs)) => { let lhs_rtti = lhs.rtti(); let rhs_rtti = rhs.rtti(); - let lhs = vm_try!(lhs.borrow_ref()); - let rhs = vm_try!(rhs.borrow_ref()); + let lhs = lhs.borrow_ref()?; + let rhs = rhs.borrow_ref()?; if lhs_rtti.hash == rhs_rtti.hash { return dynamic((lhs_rtti, &lhs), (rhs_rtti, &rhs), caller); } - return VmResult::err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs_rtti.clone().type_info(), rhs: rhs_rtti.clone().type_info(), - }); + })); } _ => {} } if let CallResultOnly::Ok(value) = - vm_try!(caller.try_call_protocol_fn(protocol, self.clone(), &mut Some((b.clone(),)))) + caller.try_call_protocol_fn(protocol, self.clone(), &mut Some((b.clone(),)))? { - return VmResult::Ok(vm_try!(T::from_value(value))); + return Ok(T::from_value(value)?); } - err(VmErrorKind::UnsupportedBinaryOperation { + Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: self.type_info(), rhs: b.type_info(), - }) + })) } /// Try to coerce the current value as the specified integer `T`. @@ -1361,7 +1441,7 @@ impl Value { /// /// Any empty value will cause an access error. #[inline] - pub(crate) fn as_any(&self) -> Option<&AnyObj> { + pub fn as_any(&self) -> Option<&AnyObj> { match &self.repr { Repr::Inline(..) => None, Repr::Dynamic(..) => None, @@ -1408,52 +1488,44 @@ impl Value { } } - pub(crate) fn protocol_into_iter(&self) -> VmResult { + pub(crate) fn protocol_into_iter(&self) -> Result { EnvProtocolCaller.call_protocol_fn(&Protocol::INTO_ITER, self.clone(), &mut ()) } - pub(crate) fn protocol_next(&self) -> VmResult> { - let value = - vm_try!(EnvProtocolCaller.call_protocol_fn(&Protocol::NEXT, self.clone(), &mut ())); + pub(crate) fn protocol_next(&self) -> Result, VmError> { + let value = EnvProtocolCaller.call_protocol_fn(&Protocol::NEXT, self.clone(), &mut ())?; - VmResult::Ok(vm_try!(FromValue::from_value(value))) + Ok(FromValue::from_value(value)?) } - pub(crate) fn protocol_next_back(&self) -> VmResult> { - let value = vm_try!(EnvProtocolCaller.call_protocol_fn( - &Protocol::NEXT_BACK, - self.clone(), - &mut () - )); + pub(crate) fn protocol_next_back(&self) -> Result, VmError> { + let value = + EnvProtocolCaller.call_protocol_fn(&Protocol::NEXT_BACK, self.clone(), &mut ())?; - VmResult::Ok(vm_try!(FromValue::from_value(value))) + Ok(FromValue::from_value(value)?) } - pub(crate) fn protocol_nth_back(&self, n: usize) -> VmResult> { - let value = vm_try!(EnvProtocolCaller.call_protocol_fn( + pub(crate) fn protocol_nth_back(&self, n: usize) -> Result, VmError> { + let value = EnvProtocolCaller.call_protocol_fn( &Protocol::NTH_BACK, self.clone(), - &mut Some((n,)) - )); + &mut Some((n,)), + )?; - VmResult::Ok(vm_try!(FromValue::from_value(value))) + Ok(FromValue::from_value(value)?) } - pub(crate) fn protocol_len(&self) -> VmResult { - let value = - vm_try!(EnvProtocolCaller.call_protocol_fn(&Protocol::LEN, self.clone(), &mut ())); + pub(crate) fn protocol_len(&self) -> Result { + let value = EnvProtocolCaller.call_protocol_fn(&Protocol::LEN, self.clone(), &mut ())?; - VmResult::Ok(vm_try!(FromValue::from_value(value))) + Ok(FromValue::from_value(value)?) } - pub(crate) fn protocol_size_hint(&self) -> VmResult<(usize, Option)> { - let value = vm_try!(EnvProtocolCaller.call_protocol_fn( - &Protocol::SIZE_HINT, - self.clone(), - &mut () - )); + pub(crate) fn protocol_size_hint(&self) -> Result<(usize, Option), VmError> { + let value = + EnvProtocolCaller.call_protocol_fn(&Protocol::SIZE_HINT, self.clone(), &mut ())?; - VmResult::Ok(vm_try!(FromValue::from_value(value))) + Ok(FromValue::from_value(value)?) } } @@ -1467,7 +1539,7 @@ impl fmt::Debug for Value { let mut s = String::new(); let result = Formatter::format_with(&mut s, |f| self.debug_fmt(f)); - if let Err(e) = result.into_result() { + if let Err(e) = result { match &self.repr { Repr::Inline(value) => { write!(f, "<{value:?}: {e}>")?; @@ -1523,6 +1595,23 @@ impl From for Value { } } +/// Conversion from a [`AnyObj`] into a [`Value`]. +/// +/// # Examples +/// +/// ``` +/// use rune::Value; +/// use rune::runtime::AnyObj; +/// use rune::alloc::String; +/// +/// let string = String::try_from("Hello World")?; +/// let string = AnyObj::new(string)?; +/// let string = Value::from(string); +/// +/// let string = string.into_shared::()?; +/// assert_eq!(string.borrow_ref()?.as_str(), "Hello World"); +/// # Ok::<_, rune::support::Error>(()) +/// ``` impl From for Value { #[inline] fn from(value: AnyObj) -> Self { @@ -1532,6 +1621,35 @@ impl From for Value { } } +/// Conversion from a [`Shared`] into a [`Value`]. +/// +/// # Examples +/// +/// ``` +/// use rune::Value; +/// use rune::runtime::Shared; +/// use rune::alloc::String; +/// +/// let string = String::try_from("Hello World")?; +/// let string = Shared::new(string)?; +/// let string = Value::from(string); +/// +/// let string = string.into_any_obj()?; +/// assert_eq!(string.borrow_ref::()?.as_str(), "Hello World"); +/// # Ok::<_, rune::support::Error>(()) +/// ``` +impl From> for Value +where + T: Any, +{ + #[inline] + fn from(value: Shared) -> Self { + Self { + repr: Repr::Any(value.into_any_obj()), + } + } +} + impl IntoOutput for Inline { #[inline] fn into_output(self) -> Result { @@ -1539,9 +1657,9 @@ impl IntoOutput for Inline { } } -impl From, Value>> for Value { +impl From, Value>> for Value { #[inline] - fn from(value: Dynamic, Value>) -> Self { + fn from(value: AnySequence, Value>) -> Self { Self { repr: Repr::Dynamic(value), } diff --git a/crates/rune/src/runtime/value/dynamic.rs b/crates/rune/src/runtime/value/any_sequence.rs similarity index 81% rename from crates/rune/src/runtime/value/dynamic.rs rename to crates/rune/src/runtime/value/any_sequence.rs index 40c7aff3f..bab99d8b5 100644 --- a/crates/rune/src/runtime/value/dynamic.rs +++ b/crates/rune/src/runtime/value/any_sequence.rs @@ -12,49 +12,51 @@ use crate::alloc::fmt::TryWrite; use crate::hash::Hash; use crate::runtime::{ Access, AccessError, BorrowMut, BorrowRef, Formatter, IntoOutput, ProtocolCaller, Rtti, - RttiKind, RuntimeError, Snapshot, TypeInfo, Value, VmResult, + RttiKind, RuntimeError, Snapshot, TypeInfo, Value, VmError, }; #[derive(Debug)] -pub(crate) enum DynamicTakeError { - Access(AccessError), +pub(crate) enum AnySequenceTakeError { Alloc(alloc::Error), + Access(AccessError), } -impl fmt::Display for DynamicTakeError { +impl fmt::Display for AnySequenceTakeError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DynamicTakeError::Access(error) => error.fmt(f), - DynamicTakeError::Alloc(error) => error.fmt(f), + AnySequenceTakeError::Access(error) => error.fmt(f), + AnySequenceTakeError::Alloc(error) => error.fmt(f), } } } -impl core::error::Error for DynamicTakeError {} +impl core::error::Error for AnySequenceTakeError {} -impl From for DynamicTakeError { +impl From for AnySequenceTakeError { + #[inline] fn from(error: AccessError) -> Self { Self::Access(error) } } -impl From for DynamicTakeError { +impl From for AnySequenceTakeError { + #[inline] fn from(error: alloc::Error) -> Self { Self::Alloc(error) } } -/// A dynamic value defined at runtime. +/// A sequence of dynamic value defined at runtime. /// /// This is an allocation-optimized container which allows an interior slice of /// data `T` to be checked for access and `H` to be immutably accessed inside of /// a single reference-counted container. -pub struct Dynamic { - shared: NonNull>, +pub struct AnySequence { + shared: NonNull>, } -impl Dynamic { +impl AnySequence { /// A dynamic value inside of the virtual machine. pub(crate) fn new( rtti: H, @@ -65,7 +67,7 @@ impl Dynamic { // Fill out the newly allocated container. unsafe { - let data = Shared::as_data_ptr(this.shared); + let data = AnySequenceData::as_data_ptr(this.shared); for (i, value) in it.enumerate() { data.add(i).write(value); @@ -77,14 +79,14 @@ impl Dynamic { /// A dynamic value inside of the virtual machine. fn alloc(rtti: H, len: usize) -> alloc::Result { - let layout = Shared::::layout(len)?; + let layout = AnySequenceData::::layout(len)?; - let shared = Global.allocate(layout)?.cast::>(); + let shared = Global.allocate(layout)?.cast::>(); // SAFETY: We've allocated space for both the shared header and the // trailing data. unsafe { - shared.write(Shared { + shared.write(AnySequenceData { rtti, count: Cell::new(1), access: Access::new(), @@ -137,7 +139,7 @@ impl Dynamic { // SAFETY: We know the layout is valid since it is reference counted. unsafe { let guard = self.shared.as_ref().access.shared()?; - let data = Shared::as_data_ptr(self.shared); + let data = AnySequenceData::as_data_ptr(self.shared); let data = NonNull::slice_from_raw_parts(data, self.shared.as_ref().len); Ok(BorrowRef::new(data, guard.into_raw())) } @@ -149,7 +151,7 @@ impl Dynamic { // SAFETY: We know the layout is valid since it is reference counted. unsafe { let guard = self.shared.as_ref().access.exclusive()?; - let data = Shared::as_data_ptr(self.shared); + let data = AnySequenceData::as_data_ptr(self.shared); let data = NonNull::slice_from_raw_parts(data, self.shared.as_ref().len); Ok(BorrowMut::new(data, guard.into_raw())) } @@ -162,47 +164,47 @@ impl Dynamic { unsafe { self.shared.as_ref().access.try_take()?; let len = self.shared.as_ref().len; - Shared::drop_values(self.shared, len); + AnySequenceData::drop_values(self.shared, len); Ok(()) } } } -impl Dynamic +impl AnySequence where H: Clone, { /// Take the interior value and return a handle to the taken value. - pub(crate) fn take(self) -> Result { + pub(crate) fn take(self) -> Result { // SAFETY: We are checking the interior value for access before taking // it. unsafe { self.shared.as_ref().access.try_take()?; let len = self.shared.as_ref().len; let new = Self::alloc(self.rtti().clone(), len)?; - let from = Shared::as_data_ptr(self.shared); - let to = Shared::as_data_ptr(new.shared); + let from = AnySequenceData::as_data_ptr(self.shared); + let to = AnySequenceData::as_data_ptr(new.shared); to.copy_from_nonoverlapping(from, len); Ok(new) } } } -impl Drop for Dynamic { +impl Drop for AnySequence { fn drop(&mut self) { // Decrement a shared value. unsafe { - Shared::dec(self.shared); + AnySequenceData::dec(self.shared); } } } -impl Clone for Dynamic { +impl Clone for AnySequence { #[inline] fn clone(&self) -> Self { // SAFETY: We know that the inner value is live in this instance. unsafe { - Shared::inc(self.shared); + AnySequenceData::inc(self.shared); } Self { @@ -220,14 +222,14 @@ impl Clone for Dynamic { // SAFETY: We know that the inner value is live in both instances. unsafe { - Shared::dec(old); - Shared::inc(self.shared); + AnySequenceData::dec(old); + AnySequenceData::inc(self.shared); } } } #[repr(C)] -struct Shared { +struct AnySequenceData { /// Run time type information of the shared value. rtti: H, /// Reference count. @@ -240,13 +242,13 @@ struct Shared { data: [T; 0], } -impl Shared { +impl AnySequenceData { #[inline] fn layout(len: usize) -> Result { let array = Layout::array::(len)?; Layout::from_size_align( - size_of::>() + array.size(), - align_of::>(), + size_of::>() + array.size(), + align_of::>(), ) } @@ -330,7 +332,7 @@ impl Shared { } } -impl Dynamic, T> { +impl AnySequence, T> { /// Access type hash on the dynamic value. #[inline] pub(crate) fn type_hash(&self) -> Hash { @@ -375,7 +377,7 @@ impl Dynamic, T> { } let guard = shared.access.shared()?; - let data = Shared::as_data_ptr(self.shared).add(index); + let data = AnySequenceData::as_data_ptr(self.shared).add(index); Ok(Some(BorrowRef::new(data, guard.into_raw()))) } } @@ -392,21 +394,21 @@ impl Dynamic, T> { } let guard = shared.access.exclusive()?; - let data = Shared::as_data_ptr(self.shared).add(index); + let data = AnySequenceData::as_data_ptr(self.shared).add(index); Ok(Some(BorrowMut::new(data, guard.into_raw()))) } } } -impl Dynamic, Value> { +impl AnySequence, Value> { /// Debug print the dynamic value. pub(crate) fn debug_fmt_with( &self, f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let rtti = self.rtti(); - let values = vm_try!(self.borrow_ref()); + let values = self.borrow_ref()?; match rtti.kind { RttiKind::Empty => debug_empty(rtti, f), @@ -416,9 +418,9 @@ impl Dynamic, Value> { } } -fn debug_empty(rtti: &Rtti, f: &mut Formatter) -> VmResult<()> { - vm_try!(write!(f, "{}", rtti.item)); - VmResult::Ok(()) +fn debug_empty(rtti: &Rtti, f: &mut Formatter) -> Result<(), VmError> { + write!(f, "{}", rtti.item)?; + Ok(()) } fn debug_tuple( @@ -426,21 +428,21 @@ fn debug_tuple( values: &[Value], f: &mut Formatter, caller: &mut dyn ProtocolCaller, -) -> VmResult<()> { - vm_try!(write!(f, "{} (", rtti.item)); +) -> Result<(), VmError> { + write!(f, "{} (", rtti.item)?; let mut first = true; for value in values.iter() { if !take(&mut first) { - vm_try!(write!(f, ", ")); + write!(f, ", ")?; } - vm_try!(value.debug_fmt_with(f, caller)); + value.debug_fmt_with(f, caller)?; } - vm_try!(write!(f, ")")); - VmResult::Ok(()) + write!(f, ")")?; + Ok(()) } fn debug_struct( @@ -448,8 +450,8 @@ fn debug_struct( values: &[Value], f: &mut Formatter, caller: &mut dyn ProtocolCaller, -) -> VmResult<()> { - vm_try!(write!(f, "{} {{", rtti.item)); +) -> Result<(), VmError> { + write!(f, "{} {{", rtti.item)?; let mut first = true; @@ -459,18 +461,18 @@ fn debug_struct( }; if !take(&mut first) { - vm_try!(write!(f, ", ")); + write!(f, ", ")?; } - vm_try!(write!(f, "{name}: ")); - vm_try!(field.debug_fmt_with(f, caller)); + write!(f, "{name}: ")?; + field.debug_fmt_with(f, caller)?; } - vm_try!(write!(f, "}}")); - VmResult::Ok(()) + write!(f, "}}")?; + Ok(()) } -impl IntoOutput for Dynamic, Value> { +impl IntoOutput for AnySequence, Value> { #[inline] fn into_output(self) -> Result { Ok(Value::from(self)) diff --git a/crates/rune/src/runtime/value/inline.rs b/crates/rune/src/runtime/value/inline.rs index 820d075d7..2f504147b 100644 --- a/crates/rune/src/runtime/value/inline.rs +++ b/crates/rune/src/runtime/value/inline.rs @@ -3,7 +3,9 @@ use core::cmp::Ordering; use core::fmt; use core::hash::Hash as _; +#[cfg(feature = "musli")] use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate as rune; @@ -13,7 +15,9 @@ use crate::runtime::{ use crate::{Hash, TypeHash}; /// An inline value. -#[derive(Clone, Copy, Encode, Decode, Deserialize, Serialize)] +#[derive(Clone, Copy)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Decode, Encode))] pub enum Inline { /// An empty value. /// @@ -39,8 +43,8 @@ pub enum Inline { Type(Type), /// Ordering. Ordering( - #[musli(with = crate::musli::ordering)] - #[serde(with = "crate::serde::ordering")] + #[cfg_attr(feature = "musli", musli(with = crate::musli::ordering))] + #[cfg_attr(feature = "serde", serde(with = "crate::serde::ordering"))] Ordering, ), /// A type hash. diff --git a/crates/rune/src/runtime/value/rtti.rs b/crates/rune/src/runtime/value/rtti.rs index 42446d5c8..f9c3a59f9 100644 --- a/crates/rune/src/runtime/value/rtti.rs +++ b/crates/rune/src/runtime/value/rtti.rs @@ -4,6 +4,9 @@ use core::hash; use rust_alloc::sync::Arc; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate::alloc::prelude::*; @@ -32,8 +35,13 @@ impl Accessor<'_> { } /// The kind of value stored. -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] +#[derive(Debug, Clone, Copy)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename_all = "kebab-case") +)] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] pub(crate) enum RttiKind { /// The value stored is empty. Empty, @@ -44,7 +52,9 @@ pub(crate) enum RttiKind { } /// Runtime information on variant. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "musli", derive(Encode, Decode))] #[non_exhaustive] pub struct Rtti { /// The kind of value. diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index ffae90a37..72f4168fe 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -124,7 +124,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { } #[inline] - fn visit_string(self, v: ::rust_alloc::string::String) -> Result + fn visit_string(self, v: rust_alloc::string::String) -> Result where E: de::Error, { @@ -143,7 +143,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { } #[inline] - fn visit_byte_buf(self, v: ::rust_alloc::vec::Vec) -> Result + fn visit_byte_buf(self, v: rust_alloc::vec::Vec) -> Result where E: de::Error, { diff --git a/crates/rune/src/runtime/value/tests.rs b/crates/rune/src/runtime/value/tests.rs index 4857fb2c0..839564bea 100644 --- a/crates/rune/src/runtime/value/tests.rs +++ b/crates/rune/src/runtime/value/tests.rs @@ -1,6 +1,6 @@ use rust_alloc::boxed::Box; -use super::Dynamic; +use super::AnySequence; #[derive(Debug, PartialEq, Eq)] struct Count(isize); @@ -9,14 +9,14 @@ struct Count(isize); fn dynamic_drop() { let header = Box::new(42u32); let v1 = crate::to_value([1u32, 2, 3, 4]).unwrap(); - let _dynamic = Dynamic::new(header, [v1]).unwrap(); + let _dynamic = AnySequence::new(header, [v1]).unwrap(); } #[test] fn dynamic_borrow_ref() { let header = Box::new(42u32); let v1 = crate::to_value([1u32, 2, 3, 4]).unwrap(); - let dynamic = Dynamic::new(header, [v1]).unwrap(); + let dynamic = AnySequence::new(header, [v1]).unwrap(); let values = dynamic.borrow_ref().unwrap(); let values2 = dynamic.borrow_ref().unwrap(); @@ -30,7 +30,7 @@ fn dynamic_borrow_ref() { #[test] fn dynamic_borrow_ref_err() -> crate::support::Result<()> { - let a = Dynamic::new((), [Count(0)])?; + let a = AnySequence::new((), [Count(0)])?; a.borrow_mut()?[0].0 += 1; @@ -51,7 +51,7 @@ fn dynamic_borrow_ref_err() -> crate::support::Result<()> { fn dynamic_borrow_mut() { let header = Box::new(42u32); let v1 = crate::to_value([1u32, 2, 3, 4]).unwrap(); - let dynamic = Dynamic::new(header, [v1]).unwrap(); + let dynamic = AnySequence::new(header, [v1]).unwrap(); let values = dynamic.borrow_mut().unwrap(); @@ -62,7 +62,7 @@ fn dynamic_borrow_mut() { #[test] fn dynamic_borrow_mut_err() -> crate::support::Result<()> { - let a = Dynamic::new((), [Count(0)])?; + let a = AnySequence::new((), [Count(0)])?; { let mut a_mut = a.borrow_mut()?; @@ -78,7 +78,7 @@ fn dynamic_borrow_mut_err() -> crate::support::Result<()> { #[test] fn dynamic_take() -> crate::support::Result<()> { - let a = Dynamic::new((), [Count(0)])?; + let a = AnySequence::new((), [Count(0)])?; let b = a.clone(); { @@ -95,7 +95,7 @@ fn dynamic_take() -> crate::support::Result<()> { #[test] fn dynamic_is_readable() -> crate::support::Result<()> { - let dynamic = Dynamic::new((), [1u32])?; + let dynamic = AnySequence::new((), [1u32])?; assert!(dynamic.is_readable()); { @@ -114,7 +114,7 @@ fn dynamic_is_readable() -> crate::support::Result<()> { #[test] fn dynamic_is_writable_take() -> crate::support::Result<()> { - let shared = Dynamic::new((), [1u32])?; + let shared = AnySequence::new((), [1u32])?; let shared2 = shared.clone(); assert!(shared.is_readable()); shared.take()?; @@ -125,7 +125,7 @@ fn dynamic_is_writable_take() -> crate::support::Result<()> { #[test] fn dynamic_is_writable() -> crate::support::Result<()> { - let shared = Dynamic::new((), [1u32])?; + let shared = AnySequence::new((), [1u32])?; assert!(shared.is_writable()); { diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs index 5b5a57831..69fdff018 100644 --- a/crates/rune/src/runtime/vec.rs +++ b/crates/rune/src/runtime/vec.rs @@ -10,15 +10,13 @@ use crate::alloc; use crate::alloc::fmt::TryWrite; use crate::alloc::prelude::*; use crate::runtime::slice::Iter; -#[cfg(feature = "alloc")] -use crate::runtime::Hasher; +use crate::shared::FixedVec; use crate::{Any, TypeHash}; -use super::EnvProtocolCaller; use super::{ - Formatter, FromValue, ProtocolCaller, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, - RangeToInclusive, RawAnyGuard, Ref, RuntimeError, ToValue, UnsafeToRef, Value, VmErrorKind, - VmResult, + EnvProtocolCaller, Formatter, FromValue, Hasher, ProtocolCaller, Range, RangeFrom, RangeFull, + RangeInclusive, RangeTo, RangeToInclusive, RawAnyGuard, Ref, RuntimeError, ToValue, + UnsafeToRef, Value, VmError, VmErrorKind, }; /// Struct representing a dynamic vector. @@ -29,13 +27,13 @@ use super::{ /// let mut vec = rune::runtime::Vec::new(); /// assert!(vec.is_empty()); /// -/// vec.push_value(42).into_result()?; -/// vec.push_value(true).into_result()?; +/// vec.push_value(42)?; +/// vec.push_value(true)?; /// assert_eq!(2, vec.len()); /// -/// assert_eq!(Some(42), vec.get_value(0).into_result()?); -/// assert_eq!(Some(true), vec.get_value(1).into_result()?); -/// assert_eq!(None::, vec.get_value(2).into_result()?); +/// assert_eq!(Some(42), vec.get_value(0)?); +/// assert_eq!(Some(true), vec.get_value(1)?); +/// assert_eq!(None::, vec.get_value(2)?); /// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Default, Any)] @@ -115,16 +113,16 @@ impl Vec { } /// Set by index - pub fn set(&mut self, index: usize, value: Value) -> VmResult<()> { + pub fn set(&mut self, index: usize, value: Value) -> Result<(), VmError> { let Some(v) = self.inner.get_mut(index) else { - return VmResult::err(VmErrorKind::OutOfRange { + return Err(VmError::new(VmErrorKind::OutOfRange { index: index.into(), length: self.len().into(), - }); + })); }; *v = value; - VmResult::Ok(()) + Ok(()) } /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. @@ -132,23 +130,23 @@ impl Vec { /// If `new_len` is greater than `len`, the `Vec` is extended by the /// difference, with each additional slot filled with `value`. If `new_len` /// is less than `len`, the `Vec` is simply truncated. - pub fn resize(&mut self, new_len: usize, value: Value) -> VmResult<()> { + pub fn resize(&mut self, new_len: usize, value: Value) -> Result<(), VmError> { if value.is_inline() { - vm_try!(self.inner.try_resize(new_len, value)); + self.inner.try_resize(new_len, value)?; } else { let len = self.inner.len(); if new_len > len { for _ in 0..new_len - len { - let value = vm_try!(value.clone_with(&mut EnvProtocolCaller)); - vm_try!(self.inner.try_push(value)); + let value = value.clone_with(&mut EnvProtocolCaller)?; + self.inner.try_push(value)?; } } else { self.inner.truncate(new_len); } } - VmResult::Ok(()) + Ok(()) } /// Appends an element to the back of a dynamic vector. @@ -158,12 +156,12 @@ impl Vec { /// Appends an element to the back of a dynamic vector, converting it as /// necessary through the [`ToValue`] trait. - pub fn push_value(&mut self, value: T) -> VmResult<()> + pub fn push_value(&mut self, value: T) -> Result<(), VmError> where T: ToValue, { - vm_try!(self.inner.try_push(vm_try!(value.to_value()))); - VmResult::Ok(()) + self.inner.try_push(value.to_value()?)?; + Ok(()) } /// Get the value at the given index. @@ -175,16 +173,15 @@ impl Vec { } /// Get the given value at the given index. - pub fn get_value(&self, index: usize) -> VmResult> + pub fn get_value(&self, index: usize) -> Result, VmError> where T: FromValue, { - let value = match self.inner.get(index) { - Some(value) => value.clone(), - None => return VmResult::Ok(None), + let Some(value) = self.inner.get(index) else { + return Ok(None); }; - VmResult::Ok(Some(vm_try!(T::from_value(value)))) + Ok(Some(T::from_value(value.clone())?)) } /// Get the mutable value at the given index. @@ -213,21 +210,20 @@ impl Vec { /// Inserts an element at position index within the vector, shifting all /// elements after it to the right. - pub fn insert(&mut self, index: usize, value: Value) -> VmResult<()> { - vm_try!(self.inner.try_insert(index, value)); - VmResult::Ok(()) + pub fn insert(&mut self, index: usize, value: Value) -> alloc::Result<()> { + self.inner.try_insert(index, value) } /// Extend this vector with something that implements the into_iter /// protocol. - pub fn extend(&mut self, value: Value) -> VmResult<()> { - let mut it = vm_try!(value.into_iter()); + pub fn extend(&mut self, value: Value) -> Result<(), VmError> { + let mut it = value.into_iter()?; - while let Some(value) = vm_try!(it.next()) { - vm_try!(self.push(value)); + while let Some(value) = it.next()? { + self.push(value)?; } - VmResult::Ok(()) + Ok(()) } /// Iterate over the vector. @@ -255,184 +251,183 @@ impl Vec { this: &[Value], f: &mut Formatter, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let mut it = this.iter().peekable(); - vm_try!(vm_write!(f, "[")); + write!(f, "[")?; while let Some(value) = it.next() { - vm_try!(value.debug_fmt_with(f, caller)); + value.debug_fmt_with(f, caller)?; if it.peek().is_some() { - vm_try!(vm_write!(f, ", ")); + write!(f, ", ")?; } } - vm_try!(vm_write!(f, "]")); - VmResult::Ok(()) + write!(f, "]")?; + Ok(()) } pub(crate) fn partial_eq_with( a: &[Value], b: Value, caller: &mut dyn ProtocolCaller, - ) -> VmResult { - let mut b = vm_try!(b.into_iter_with(caller)); + ) -> Result { + let mut b = b.into_iter_with(caller)?; for a in a { - let Some(b) = vm_try!(b.next()) else { - return VmResult::Ok(false); + let Some(b) = b.next()? else { + return Ok(false); }; - if !vm_try!(Value::partial_eq_with(a, &b, caller)) { - return VmResult::Ok(false); + if !Value::partial_eq_with(a, &b, caller)? { + return Ok(false); } } - if vm_try!(b.next()).is_some() { - return VmResult::Ok(false); + if b.next()?.is_some() { + return Ok(false); } - VmResult::Ok(true) + Ok(true) } pub(crate) fn eq_with( a: &[Value], b: &[Value], - eq: fn(&Value, &Value, &mut dyn ProtocolCaller) -> VmResult, + eq: fn(&Value, &Value, &mut dyn ProtocolCaller) -> Result, caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { if a.len() != b.len() { - return VmResult::Ok(false); + return Ok(false); } for (a, b) in a.iter().zip(b.iter()) { - if !vm_try!(eq(a, b, caller)) { - return VmResult::Ok(false); + if !eq(a, b, caller)? { + return Ok(false); } } - VmResult::Ok(true) + Ok(true) } pub(crate) fn partial_cmp_with( a: &[Value], b: &[Value], caller: &mut dyn ProtocolCaller, - ) -> VmResult> { + ) -> Result, VmError> { let mut b = b.iter(); for a in a.iter() { let Some(b) = b.next() else { - return VmResult::Ok(Some(Ordering::Greater)); + return Ok(Some(Ordering::Greater)); }; - match vm_try!(Value::partial_cmp_with(a, b, caller)) { + match Value::partial_cmp_with(a, b, caller)? { Some(Ordering::Equal) => continue, - other => return VmResult::Ok(other), + other => return Ok(other), } } if b.next().is_some() { - return VmResult::Ok(Some(Ordering::Less)); + return Ok(Some(Ordering::Less)); } - VmResult::Ok(Some(Ordering::Equal)) + Ok(Some(Ordering::Equal)) } pub(crate) fn cmp_with( a: &[Value], b: &[Value], caller: &mut dyn ProtocolCaller, - ) -> VmResult { + ) -> Result { let mut b = b.iter(); for a in a.iter() { let Some(b) = b.next() else { - return VmResult::Ok(Ordering::Greater); + return Ok(Ordering::Greater); }; - match vm_try!(Value::cmp_with(a, b, caller)) { + match Value::cmp_with(a, b, caller)? { Ordering::Equal => continue, - other => return VmResult::Ok(other), + other => return Ok(other), } } if b.next().is_some() { - return VmResult::Ok(Ordering::Less); + return Ok(Ordering::Less); } - VmResult::Ok(Ordering::Equal) + Ok(Ordering::Equal) } /// 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> { + pub(crate) fn index_get(this: &[Value], index: Value) -> Result, VmError> { let slice: Option<&[Value]> = 'out: { if let Some(value) = index.as_any() { match value.type_hash() { RangeFrom::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; break 'out this.get(start..); } RangeFull::HASH => { - _ = vm_try!(value.borrow_ref::()); + _ = value.borrow_ref::()?; break 'out this.get(..); } RangeInclusive::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; + let end = range.end.as_usize()?; break 'out this.get(start..=end); } RangeToInclusive::HASH => { - let range = vm_try!(value.borrow_ref::()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let end = range.end.as_usize()?; break 'out this.get(..=end); } RangeTo::HASH => { - let range = vm_try!(value.borrow_ref::()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let end = range.end.as_usize()?; break 'out this.get(..end); } Range::HASH => { - let range = vm_try!(value.borrow_ref::()); - let start = vm_try!(range.start.as_usize()); - let end = vm_try!(range.end.as_usize()); + let range = value.borrow_ref::()?; + let start = range.start.as_usize()?; + let end = range.end.as_usize()?; break 'out this.get(start..end); } _ => {} } }; - let index = vm_try!(usize::from_value(index)); + let index = usize::from_value(index)?; let Some(value) = this.get(index) else { - return VmResult::Ok(None); + return Ok(None); }; - return VmResult::Ok(Some(value.clone())); + return Ok(Some(value.clone())); }; let Some(values) = slice else { - return VmResult::Ok(None); + return Ok(None); }; - let vec = vm_try!(alloc::Vec::try_from(values)); - VmResult::Ok(Some(vm_try!(Value::vec(vec)))) + let vec = alloc::Vec::try_from(values)?; + Ok(Some(Value::vec(vec)?)) } - #[cfg(feature = "alloc")] pub(crate) fn hash_with( &self, hasher: &mut Hasher, caller: &mut dyn ProtocolCaller, - ) -> VmResult<()> { + ) -> Result<(), VmError> { for value in self.inner.iter() { - vm_try!(value.hash_with(hasher, caller)); + value.hash_with(hasher, caller)?; } - VmResult::Ok(()) + Ok(()) } } @@ -496,12 +491,11 @@ impl<'a> IntoIterator for &'a mut Vec { } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::vec::Vec> for Vec { +impl TryFrom> for Vec { type Error = alloc::Error; #[inline] - fn try_from(values: ::rust_alloc::vec::Vec) -> Result { + fn try_from(values: rust_alloc::vec::Vec) -> Result { let mut inner = alloc::Vec::try_with_capacity(values.len())?; for value in values { @@ -512,12 +506,11 @@ impl TryFrom<::rust_alloc::vec::Vec> for Vec { } } -#[cfg(feature = "alloc")] -impl TryFrom<::rust_alloc::boxed::Box<[Value]>> for Vec { +impl TryFrom> for Vec { type Error = alloc::Error; #[inline] - fn try_from(inner: ::rust_alloc::boxed::Box<[Value]>) -> Result { + fn try_from(inner: rust_alloc::boxed::Box<[Value]>) -> Result { Vec::try_from(inner.into_vec()) } } @@ -529,8 +522,7 @@ impl From> for Vec { } } -#[cfg(feature = "alloc")] -impl FromValue for ::rust_alloc::vec::Vec +impl FromValue for rust_alloc::vec::Vec where T: FromValue, { @@ -538,7 +530,7 @@ where fn from_value(value: Value) -> Result { let vec = value.downcast::()?; - let mut output = ::rust_alloc::vec::Vec::with_capacity(vec.len()); + let mut output = rust_alloc::vec::Vec::with_capacity(vec.len()); for value in vec { output.push(T::from_value(value)?); @@ -577,7 +569,7 @@ impl UnsafeToRef for [Value] { } } -impl ToValue for [T; N] +impl ToValue for alloc::Vec where T: ToValue, { @@ -594,7 +586,7 @@ where } } -impl ToValue for alloc::Vec +impl ToValue for rust_alloc::vec::Vec where T: ToValue, { @@ -611,8 +603,33 @@ where } } -#[cfg(feature = "alloc")] -impl ToValue for ::rust_alloc::vec::Vec +impl FromValue for [T; N] +where + T: FromValue, +{ + fn from_value(value: Value) -> Result { + let vec = value.into_ref::()?; + + let values = vec.as_slice(); + + if values.len() != N { + return Err(RuntimeError::new(VmErrorKind::ExpectedVecLength { + actual: vec.len(), + expected: N, + })); + }; + + let mut output = FixedVec::::new(); + + for v in values { + output.try_push(T::from_value(v.clone())?)?; + } + + Ok(output.into_inner()) + } +} + +impl ToValue for [T; N] where T: ToValue, { diff --git a/crates/rune/src/runtime/vec_tuple.rs b/crates/rune/src/runtime/vec_tuple.rs index 51bc13768..d2d5a4b7a 100644 --- a/crates/rune/src/runtime/vec_tuple.rs +++ b/crates/rune/src/runtime/vec_tuple.rs @@ -30,7 +30,7 @@ macro_rules! impl_from_value_tuple_vec { let vec = value.into_ref::<$crate::runtime::Vec>()?; let [$($var,)*] = vec.as_slice() else { - return Err(RuntimeError::new(VmErrorKind::ExpectedTupleLength { + return Err(RuntimeError::new(VmErrorKind::ExpectedVecLength { actual: vec.len(), expected: $count, })); diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index c5879833b..9a35d90ad 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -3,7 +3,7 @@ use core::fmt; use core::mem::replace; use core::ptr::NonNull; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate as rune; use crate::alloc::prelude::*; @@ -16,15 +16,16 @@ use crate::runtime; mod ops; use self::ops::*; +use super::inst; use super::{ - budget, Args, Awaited, BorrowMut, Bytes, Call, ControlFlow, DynArgs, DynGuardedArgs, Dynamic, - Format, FormatSpec, Formatter, FromValue, Function, Future, Generator, GeneratorState, - GuardedArgs, Inline, Inst, InstAddress, InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, + budget, Address, AnySequence, Args, Awaited, BorrowMut, Bytes, Call, ControlFlow, DynArgs, + DynGuardedArgs, Format, FormatSpec, Formatter, FromValue, Function, Future, Generator, + GeneratorState, GuardedArgs, Inline, InstArithmeticOp, InstBitwiseOp, InstOp, InstRange, InstShiftOp, InstTarget, InstValue, InstVariant, Object, Output, OwnedTuple, Pair, Panic, Protocol, ProtocolCaller, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, Repr, RttiKind, RuntimeContext, Select, SelectFuture, Stack, Stream, Type, TypeCheck, TypeHash, TypeInfo, TypeOf, Unit, UnitFn, UnitStorage, Value, Vec, VmDiagnostics, - VmDiagnosticsObj, VmError, VmErrorKind, VmExecution, VmHalt, VmIntegerRepr, VmResult, + VmDiagnosticsObj, VmError, VmErrorKind, VmExecution, VmHalt, VmIntegerRepr, VmOutcome, VmSendExecution, }; @@ -77,14 +78,6 @@ impl fmt::Display for Isolated { } } -/// Small helper function to build errors. -fn err(error: E) -> VmResult -where - VmErrorKind: From, -{ - VmResult::err(error) -} - /// The result from a dynamic call. Indicates if the attempted operation is /// supported. #[derive(Debug)] @@ -297,14 +290,14 @@ impl Vm { /// // Looking up an item from the source. /// let dynamic_max = vm.lookup_function(["max"])?; /// - /// let value = dynamic_max.call::((10, 20)).into_result()?; + /// let value = dynamic_max.call::((10, 20))?; /// assert_eq!(value, 20); /// /// // Building an item buffer to lookup an `::std` item. /// let item = rune::item!(::std::i64::max); /// let max = vm.lookup_function(item)?; /// - /// let value = max.call::((10, 20)).into_result()?; + /// let value = max.call::((10, 20))?; /// assert_eq!(value, 20); /// # Ok::<_, rune::support::Error>(()) /// ``` @@ -322,14 +315,17 @@ impl Vm { /// Run the given vm to completion. /// - /// If any async instructions are encountered, this will error. + /// # Errors + /// + /// If any non-completing outcomes like yielding or awaiting are + /// encountered, this will error. pub fn complete(self) -> Result { - self.into_execution().complete().into_result() + self.into_execution().complete() } /// Run the given vm to completion with support for async functions. pub async fn async_complete(self) -> Result { - self.into_execution().async_complete().await.into_result() + self.into_execution().resume().await?.into_complete() } /// Call the function identified by the given name. @@ -352,7 +348,7 @@ impl Vm { /// let unit = Arc::new(Unit::default()); /// let mut vm = rune::Vm::without_runtime(unit); /// - /// let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; + /// let output = vm.execute(["main"], (33i64,))?.complete()?; /// let output: i64 = rune::from_value(output)?; /// /// println!("output: {}", output); @@ -375,7 +371,7 @@ impl Vm { /// args.push(rune::to_value(1u32)?); /// args.push(rune::to_value(String::from("Hello World"))?); /// - /// let output = vm.execute(["main"], args)?.complete().into_result()?; + /// let output = vm.execute(["main"], args)?.complete()?; /// let output: i64 = rune::from_value(output)?; /// /// println!("output: {}", output); @@ -387,7 +383,7 @@ impl Vm { args: impl Args, ) -> Result, VmError> { self.set_entrypoint(name, args.count())?; - args.into_stack(&mut self.stack).into_result()?; + args.into_stack(&mut self.stack)?; Ok(VmExecution::new(self)) } @@ -407,7 +403,7 @@ impl Vm { self.stack.clear(); self.set_entrypoint(name, args.count())?; - args.into_stack(&mut self.stack).into_result()?; + args.into_stack(&mut self.stack)?; Ok(VmSendExecution(VmExecution::new(self))) } @@ -415,16 +411,6 @@ impl Vm { /// /// This function permits for using references since it doesn't defer its /// execution. - /// - /// # Panics - /// - /// If any of the arguments passed in are references, and that references is - /// captured somewhere in the call as [`Mut`] or [`Ref`] this call - /// will panic as we are trying to free the metadata relatedc to the - /// reference. - /// - /// [`Mut`]: crate::Mut - /// [`Ref`]: crate::Ref pub fn call( &mut self, name: impl ToTypeHash, @@ -435,13 +421,13 @@ impl Vm { // Safety: We hold onto the guard until the vm has completed and // `VmExecution` will clear the stack before this function returns. // Erronously or not. - let guard = unsafe { args.guarded_into_stack(&mut self.stack).into_result()? }; + let guard = unsafe { args.guarded_into_stack(&mut self.stack)? }; let value = { // Clearing the stack here on panics has safety implications - see // above. let vm = ClearStack(self); - VmExecution::new(&mut *vm.0).complete().into_result()? + VmExecution::new(&mut *vm.0).complete()? }; // Note: this might panic if something in the vm is holding on to a @@ -455,43 +441,35 @@ impl Vm { /// /// This function permits for using references since it doesn't defer its /// execution. - /// - /// # Panics - /// - /// If any of the arguments passed in are references, and that references is - /// captured somewhere in the call as [`Mut`] or [`Ref`] this call - /// will panic as we are trying to free the metadata relatedc to the - /// reference. - /// - /// [`Mut`]: crate::Mut - /// [`Ref`]: crate::Ref pub fn call_with_diagnostics( &mut self, name: impl ToTypeHash, args: impl GuardedArgs, - diagnostics: Option<&mut dyn VmDiagnostics>, + diagnostics: &mut dyn VmDiagnostics, ) -> Result { self.set_entrypoint(name, args.count())?; // Safety: We hold onto the guard until the vm has completed and // `VmExecution` will clear the stack before this function returns. // Erronously or not. - let guard = unsafe { args.guarded_into_stack(&mut self.stack).into_result()? }; + let guard = unsafe { args.guarded_into_stack(&mut self.stack)? }; let value = { // Clearing the stack here on panics has safety implications - see // above. let vm = ClearStack(self); VmExecution::new(&mut *vm.0) - .complete_with_diagnostics(diagnostics) - .into_result()? + .resume() + .with_diagnostics(diagnostics) + .complete() + .and_then(VmOutcome::into_complete) }; // Note: this might panic if something in the vm is holding on to a // reference of the value. We should prevent it from being possible to // take any owned references to values held by this. drop(guard); - Ok(value) + value } /// Call the given function immediately asynchronously, returning the @@ -499,16 +477,6 @@ impl Vm { /// /// This function permits for using references since it doesn't defer its /// execution. - /// - /// # Panics - /// - /// If any of the arguments passed in are references, and that references is - /// captured somewhere in the call as [`Mut`] or [`Ref`] - /// this call will panic as we are trying to free the metadata relatedc to - /// the reference. - /// - /// [`Mut`]: runtime::Mut - /// [`Ref`]: runtime::Ref pub async fn async_call(&mut self, name: N, args: A) -> Result where N: ToTypeHash, @@ -519,23 +487,23 @@ impl Vm { // Safety: We hold onto the guard until the vm has completed and // `VmExecution` will clear the stack before this function returns. // Erronously or not. - let guard = unsafe { args.guarded_into_stack(&mut self.stack).into_result()? }; + let guard = unsafe { args.guarded_into_stack(&mut self.stack)? }; let value = { // Clearing the stack here on panics has safety implications - see // above. let vm = ClearStack(self); VmExecution::new(&mut *vm.0) - .async_complete() + .resume() .await - .into_result()? + .and_then(VmOutcome::into_complete) }; // Note: this might panic if something in the vm is holding on to a // reference of the value. We should prevent it from being possible to // take any owned references to values held by this. drop(guard); - Ok(value) + value } /// Update the instruction pointer to match the function matching the given @@ -585,7 +553,7 @@ impl Vm { hash: impl ToTypeHash, args: &mut dyn DynArgs, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { let count = args.count().wrapping_add(1); let type_hash = target.type_hash(); let hash = Hash::associated_function(type_hash, hash.to_type_hash()); @@ -601,7 +569,7 @@ impl Vm { name: impl IntoHash, args: &mut dyn DynArgs, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { let count = args.count().wrapping_add(1); let hash = Hash::field_function(protocol, target.type_hash(), name); self.call_hash_with(Isolated::None, hash, target, args, count, out) @@ -616,19 +584,19 @@ impl Vm { index: usize, args: &mut dyn DynArgs, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { let count = args.count().wrapping_add(1); let hash = Hash::index_function(protocol, target.type_hash(), Hash::index(index)); self.call_hash_with(Isolated::None, hash, target, args, count, out) } - fn called_function_hook(&self, hash: Hash) -> VmResult<()> { + fn called_function_hook(&self, hash: Hash) -> Result<(), VmError> { runtime::env::exclusive(|_, _, diagnostics| { if let Some(diagnostics) = diagnostics { - vm_try!(diagnostics.function_used(hash, self.ip())); + diagnostics.function_used(hash, self.ip())?; } - VmResult::Ok(()) + Ok(()) }) } @@ -641,18 +609,18 @@ impl Vm { args: &mut dyn DynArgs, count: usize, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { if let Some(handler) = self.context.function(&hash) { let addr = self.stack.addr(); - vm_try!(self.called_function_hook(hash)); - vm_try!(self.stack.push(target)); - vm_try!(args.push_to_stack(&mut self.stack)); + self.called_function_hook(hash)?; + self.stack.push(target)?; + args.push_to_stack(&mut self.stack)?; - let result = handler(&mut self.stack, addr, count, out); + let result = handler.call(&mut self.stack, addr, count, out); self.stack.truncate(addr); - vm_try!(result); - return VmResult::Ok(CallResult::Ok(())); + result?; + return Ok(CallResult::Ok(())); } if let Some(UnitFn::Offset { @@ -662,53 +630,53 @@ impl Vm { .. }) = self.unit.function(&hash) { - vm_try!(check_args(count, *expected)); + check_args(count, *expected)?; let addr = self.stack.addr(); - vm_try!(self.called_function_hook(hash)); - vm_try!(self.stack.push(target)); - vm_try!(args.push_to_stack(&mut self.stack)); + self.called_function_hook(hash)?; + self.stack.push(target)?; + args.push_to_stack(&mut self.stack)?; let result = self.call_offset_fn(*offset, *call, addr, count, isolated, out); - if vm_try!(result) { + if result? { self.stack.truncate(addr); - return VmResult::Ok(CallResult::Frame); + return Ok(CallResult::Frame); } else { - return VmResult::Ok(CallResult::Ok(())); + return Ok(CallResult::Ok(())); } } - VmResult::Ok(CallResult::Unsupported(target)) + Ok(CallResult::Unsupported(target)) } #[cfg_attr(feature = "bench", inline(never))] fn internal_cmp( &mut self, match_ordering: fn(Ordering) -> bool, - lhs: InstAddress, - rhs: InstAddress, + lhs: Address, + rhs: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let rhs = self.stack.at(rhs); let lhs = self.stack.at(lhs); let ordering = match (lhs.as_inline_unchecked(), rhs.as_inline_unchecked()) { - (Some(lhs), Some(rhs)) => vm_try!(lhs.partial_cmp(rhs)), + (Some(lhs), Some(rhs)) => lhs.partial_cmp(rhs)?, _ => { let lhs = lhs.clone(); let rhs = rhs.clone(); - vm_try!(Value::partial_cmp_with(&lhs, &rhs, self)) + Value::partial_cmp_with(&lhs, &rhs, self)? } }; - vm_try!(out.store(&mut self.stack, || match ordering { + out.store(&mut self.stack, || match ordering { Some(ordering) => match_ordering(ordering), None => false, - })); + })?; - VmResult::Ok(()) + Ok(()) } /// Push a new call frame. @@ -719,7 +687,7 @@ impl Vm { pub(crate) fn push_call_frame( &mut self, ip: usize, - addr: InstAddress, + addr: Address, args: usize, isolated: Isolated, out: Output, @@ -769,46 +737,46 @@ impl Vm { } /// Implementation of getting a string index on an object-like type. - fn try_object_like_index_get(target: &Value, field: &str) -> VmResult> { + fn try_object_like_index_get(target: &Value, field: &str) -> Result, VmError> { match target.as_ref() { Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { - let Some(value) = vm_try!(data.get_field_ref(field)) else { - return err(VmErrorKind::MissingField { + let Some(value) = data.get_field_ref(field)? else { + return Err(VmError::new(VmErrorKind::MissingField { target: data.type_info(), - field: vm_try!(field.try_to_owned()), - }); + field: field.try_to_owned()?, + })); }; - VmResult::Ok(Some(value.clone())) + Ok(Some(value.clone())) } Repr::Any(value) => match value.type_hash() { Object::HASH => { - let target = vm_try!(value.borrow_ref::()); + let target = value.borrow_ref::()?; let Some(value) = target.get(field) else { - return err(VmErrorKind::MissingField { + return Err(VmError::new(VmErrorKind::MissingField { target: TypeInfo::any::(), - field: vm_try!(field.try_to_owned()), - }); + field: field.try_to_owned()?, + })); }; - VmResult::Ok(Some(value.clone())) + Ok(Some(value.clone())) } - _ => VmResult::Ok(None), + _ => Ok(None), }, - _ => VmResult::Ok(None), + _ => Ok(None), } } /// Implementation of getting a string index on an object-like type. - fn try_tuple_like_index_get(target: &Value, index: usize) -> VmResult> { + fn try_tuple_like_index_get(target: &Value, index: usize) -> Result, VmError> { let result = match target.as_ref() { Repr::Inline(target) => match target { Inline::Unit => Err(target.type_info()), - _ => return VmResult::Ok(None), + _ => return Ok(None), }, Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { - match vm_try!(data.get_ref(index)) { + match data.get_ref(index)? { Some(value) => Ok(value.clone()), None => Err(data.type_info()), } @@ -816,28 +784,23 @@ impl Vm { Repr::Dynamic(data) => Err(data.type_info()), Repr::Any(target) => match target.type_hash() { Result::::HASH => { - match ( - index, - &*vm_try!(target.borrow_ref::>()), - ) { + match (index, &*target.borrow_ref::>()?) { (0, Ok(value)) => Ok(value.clone()), (0, Err(value)) => Ok(value.clone()), _ => Err(target.type_info()), } } - Option::::HASH => { - match (index, &*vm_try!(target.borrow_ref::>())) { - (0, Some(value)) => Ok(value.clone()), - _ => Err(target.type_info()), - } - } - GeneratorState::HASH => match (index, &*vm_try!(target.borrow_ref())) { + Option::::HASH => match (index, &*target.borrow_ref::>()?) { + (0, Some(value)) => Ok(value.clone()), + _ => Err(target.type_info()), + }, + GeneratorState::HASH => match (index, &*target.borrow_ref()?) { (0, GeneratorState::Yielded(value)) => Ok(value.clone()), (0, GeneratorState::Complete(value)) => Ok(value.clone()), _ => Err(target.type_info()), }, runtime::Vec::HASH => { - let vec = vm_try!(target.borrow_ref::()); + let vec = target.borrow_ref::()?; match vec.get(index) { Some(value) => Ok(value.clone()), @@ -845,7 +808,7 @@ impl Vm { } } runtime::OwnedTuple::HASH => { - let tuple = vm_try!(target.borrow_ref::()); + let tuple = target.borrow_ref::()?; match tuple.get(index) { Some(value) => Ok(value.clone()), @@ -853,81 +816,85 @@ impl Vm { } } _ => { - return VmResult::Ok(None); + return Ok(None); } }, }; match result { - Ok(value) => VmResult::Ok(Some(value)), - Err(target) => err(VmErrorKind::MissingIndexInteger { + Ok(value) => Ok(Some(value)), + Err(target) => Err(VmError::new(VmErrorKind::MissingIndexInteger { target, index: VmIntegerRepr::from(index), - }), + })), } } /// Implementation of getting a string index on an object-like type. - fn try_tuple_like_index_set(target: &Value, index: usize, from: &Value) -> VmResult { + fn try_tuple_like_index_set( + target: &Value, + index: usize, + from: &Value, + ) -> Result { match target.as_ref() { Repr::Inline(target) => match target { - Inline::Unit => VmResult::Ok(false), - _ => VmResult::Ok(false), + Inline::Unit => Ok(false), + _ => Ok(false), }, Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Tuple) => { - if let Some(target) = vm_try!(data.borrow_mut()).get_mut(index) { + if let Some(target) = data.borrow_mut()?.get_mut(index) { target.clone_from(from); - return VmResult::Ok(true); + return Ok(true); } - VmResult::Ok(false) + Ok(false) } - Repr::Dynamic(..) => VmResult::Ok(false), + Repr::Dynamic(..) => Ok(false), Repr::Any(value) => match value.type_hash() { Result::::HASH => { - let mut result = vm_try!(value.borrow_mut::>()); + let mut result = value.borrow_mut::>()?; let target = match &mut *result { Ok(ok) if index == 0 => ok, Err(err) if index == 1 => err, - _ => return VmResult::Ok(false), + _ => return Ok(false), }; target.clone_from(from); - VmResult::Ok(true) + Ok(true) } Option::::HASH => { - let mut option = vm_try!(value.borrow_mut::>()); + let mut option = value.borrow_mut::>()?; let target = match &mut *option { Some(some) if index == 0 => some, - _ => return VmResult::Ok(false), + _ => return Ok(false), }; target.clone_from(from); - VmResult::Ok(true) + Ok(true) } runtime::Vec::HASH => { - let mut vec = vm_try!(value.borrow_mut::()); + let mut vec = value.borrow_mut::()?; if let Some(target) = vec.get_mut(index) { target.clone_from(from); - return VmResult::Ok(true); + return Ok(true); } - VmResult::Ok(false) + Ok(false) } runtime::OwnedTuple::HASH => { - let mut tuple = vm_try!(value.borrow_mut::()); + let mut tuple = value.borrow_mut::()?; if let Some(target) = tuple.get_mut(index) { target.clone_from(from); - return VmResult::Ok(true); + return Ok(true); } - VmResult::Ok(false) + Ok(false) } - _ => VmResult::Ok(false), + _ => Ok(false), }, } } @@ -971,7 +938,7 @@ impl Vm { } } - fn on_tuple(&self, ty: TypeCheck, value: &Value, f: F) -> VmResult> + fn on_tuple(&self, ty: TypeCheck, value: &Value, f: F) -> Result, VmError> where F: FnOnce(&[Value]) -> O, { @@ -982,11 +949,11 @@ impl Vm { }, Repr::Any(value) => match (ty, value.type_hash()) { (TypeCheck::Vec, runtime::Vec::HASH) => { - let vec = vm_try!(value.borrow_ref::()); + let vec = value.borrow_ref::()?; Some(f(&vec)) } (TypeCheck::Tuple, runtime::OwnedTuple::HASH) => { - let tuple = vm_try!(value.borrow_ref::()); + let tuple = value.borrow_ref::()?; Some(f(&tuple)) } _ => None, @@ -994,19 +961,19 @@ impl Vm { _ => None, }; - VmResult::Ok(value) + Ok(value) } /// Internal implementation of the instance check. - fn as_op(&mut self, lhs: InstAddress, rhs: InstAddress) -> VmResult { + fn as_op(&mut self, lhs: Address, rhs: Address) -> Result { let b = self.stack.at(rhs); let a = self.stack.at(lhs); let Repr::Inline(Inline::Type(ty)) = b.as_ref() else { - return err(VmErrorKind::UnsupportedIs { + return Err(VmError::new(VmErrorKind::UnsupportedIs { value: a.type_info(), test_type: b.type_info(), - }); + })); }; macro_rules! convert { @@ -1016,10 +983,10 @@ impl Vm { u64::HASH => Value::from($value as u64), i64::HASH => Value::from($value as i64), ty => { - return err(VmErrorKind::UnsupportedAs { + return Err(VmError::new(VmErrorKind::UnsupportedAs { value: TypeInfo::from(<$from as TypeOf>::STATIC_TYPE_INFO), type_hash: ty, - }); + })); } } }; @@ -1030,39 +997,39 @@ impl Vm { Repr::Inline(Inline::Signed(a)) => convert!(i64, *a), Repr::Inline(Inline::Float(a)) => convert!(f64, *a), value => { - return err(VmErrorKind::UnsupportedAs { + return Err(VmError::new(VmErrorKind::UnsupportedAs { value: value.type_info(), type_hash: ty.into_hash(), - }); + })); } }; - VmResult::Ok(value) + Ok(value) } /// Internal implementation of the instance check. - fn test_is_instance(&mut self, lhs: InstAddress, rhs: InstAddress) -> VmResult { + fn test_is_instance(&mut self, lhs: Address, rhs: Address) -> Result { let b = self.stack.at(rhs); let a = self.stack.at(lhs); let Some(Inline::Type(ty)) = b.as_inline() else { - return err(VmErrorKind::UnsupportedIs { + return Err(VmError::new(VmErrorKind::UnsupportedIs { value: a.type_info(), test_type: b.type_info(), - }); + })); }; - VmResult::Ok(a.type_hash() == ty.into_hash()) + Ok(a.type_hash() == ty.into_hash()) } fn internal_bool( &mut self, bool_op: impl FnOnce(bool, bool) -> bool, op: &'static str, - lhs: InstAddress, - rhs: InstAddress, + lhs: Address, + rhs: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let rhs = self.stack.at(rhs); let lhs = self.stack.at(lhs); @@ -1072,23 +1039,23 @@ impl Vm { Inline::Bool(value) } (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }; - vm_try!(out.store(&mut self.stack, inline)); - VmResult::Ok(()) + out.store(&mut self.stack, inline)?; + Ok(()) } /// Construct a future from calling an async function. fn call_generator_fn( &mut self, offset: usize, - addr: InstAddress, + addr: Address, args: usize, out: Output, ) -> Result<(), VmErrorKind> { @@ -1110,7 +1077,7 @@ impl Vm { fn call_stream_fn( &mut self, offset: usize, - addr: InstAddress, + addr: Address, args: usize, out: Output, ) -> Result<(), VmErrorKind> { @@ -1132,7 +1099,7 @@ impl Vm { fn call_async_fn( &mut self, offset: usize, - addr: InstAddress, + addr: Address, args: usize, out: Output, ) -> Result<(), VmErrorKind> { @@ -1143,7 +1110,7 @@ impl Vm { let mut vm = Self::with_stack(self.context.clone(), self.unit.clone(), stack); vm.ip = offset; let mut execution = vm.into_execution(); - let future = Future::new(async move { execution.async_complete().await })?; + let future = Future::new(async move { execution.resume().await?.into_complete() })?; *self.stack.at_mut(at)? = Value::try_from(future)?; } else { values.iter_mut().for_each(consume); @@ -1158,7 +1125,7 @@ impl Vm { &mut self, offset: usize, call: Call, - addr: InstAddress, + addr: Address, args: usize, isolated: Isolated, out: Output, @@ -1191,86 +1158,78 @@ impl Vm { &mut self, fallback: TargetFallback, protocol: &Protocol, - ) -> VmResult<()> { + ) -> Result<(), VmError> { match fallback { TargetFallback::Value(lhs, rhs) => { let mut args = DynGuardedArgs::new((rhs.clone(),)); - if let CallResult::Unsupported(lhs) = vm_try!(self.call_instance_fn( + if let CallResult::Unsupported(lhs) = self.call_instance_fn( Isolated::None, lhs, protocol.hash, &mut args, - Output::discard() - )) { - return err(VmErrorKind::UnsupportedBinaryOperation { + Output::discard(), + )? { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); }; - - VmResult::Ok(()) } TargetFallback::Field(lhs, hash, slot, rhs) => { let mut args = DynGuardedArgs::new((rhs,)); - if let CallResult::Unsupported(lhs) = vm_try!(self.call_field_fn( - protocol, - lhs.clone(), - hash, - &mut args, - Output::discard() - )) { + if let CallResult::Unsupported(lhs) = + self.call_field_fn(protocol, lhs.clone(), hash, &mut args, Output::discard())? + { let Some(field) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; - return err(VmErrorKind::UnsupportedObjectSlotIndexGet { + return Err(VmError::new(VmErrorKind::UnsupportedObjectSlotIndexGet { target: lhs.type_info(), field: field.clone(), - }); + })); } - - VmResult::Ok(()) } TargetFallback::Index(lhs, index, rhs) => { let mut args = DynGuardedArgs::new((rhs,)); - if let CallResult::Unsupported(lhs) = vm_try!(self.call_index_fn( + if let CallResult::Unsupported(lhs) = self.call_index_fn( protocol.hash, lhs.clone(), index, &mut args, - Output::discard() - )) { - return err(VmErrorKind::UnsupportedTupleIndexGet { + Output::discard(), + )? { + return Err(VmError::new(VmErrorKind::UnsupportedTupleIndexGet { target: lhs.type_info(), index, - }); + })); } - - VmResult::Ok(()) } } + + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_await(&mut self, addr: InstAddress) -> VmResult { - VmResult::Ok(vm_try!(self.stack.at(addr).clone().into_future())) + fn op_await(&mut self, addr: Address) -> Result { + Ok(self.stack.at(addr).clone().into_future()?) } #[cfg_attr(feature = "bench", inline(never))] fn op_select( &mut self, - addr: InstAddress, + addr: Address, len: usize, value: Output, - ) -> VmResult> { + ) -> Result, VmError> { let futures = futures_util::stream::FuturesUnordered::new(); - for (branch, value) in vm_try!(self.stack.slice_at(addr, len)).iter().enumerate() { - let future = vm_try!(value.clone().into_mut::()); + for (branch, value) in self.stack.slice_at(addr, len)?.iter().enumerate() { + let future = value.clone().into_mut::()?; if !future.is_completed() { futures.push(SelectFuture::new(self.ip + branch, future)); @@ -1278,69 +1237,69 @@ impl Vm { } if futures.is_empty() { - vm_try!(value.store(&mut self.stack, ())); + value.store(&mut self.stack, ())?; self.ip = self.ip.wrapping_add(len); - return VmResult::Ok(None); + return Ok(None); } - VmResult::Ok(Some(Select::new(futures))) + Ok(Some(Select::new(futures))) } #[cfg_attr(feature = "bench", inline(never))] - fn op_store(&mut self, value: InstValue, out: Output) -> VmResult<()> { - vm_try!(out.store(&mut self.stack, value.into_value())); - VmResult::Ok(()) + fn op_store(&mut self, value: InstValue, out: Output) -> Result<(), VmError> { + out.store(&mut self.stack, value.into_value())?; + Ok(()) } /// Copy a value from a position relative to the top of the stack, to the /// top of the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_copy(&mut self, addr: InstAddress, out: Output) -> VmResult<()> { - vm_try!(self.stack.copy(addr, out)); - VmResult::Ok(()) + fn op_copy(&mut self, addr: Address, out: Output) -> Result<(), VmError> { + self.stack.copy(addr, out)?; + Ok(()) } /// Move a value from a position relative to the top of the stack, to the /// top of the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_move(&mut self, addr: InstAddress, out: Output) -> VmResult<()> { + fn op_move(&mut self, addr: Address, out: Output) -> Result<(), VmError> { let value = self.stack.at(addr).clone(); - let value = vm_try!(value.move_()); - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + let value = value.move_()?; + out.store(&mut self.stack, value)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_drop(&mut self, set: usize) -> VmResult<()> { + fn op_drop(&mut self, set: usize) -> Result<(), VmError> { let Some(addresses) = self.unit.lookup_drop_set(set) else { - return err(VmErrorKind::MissingDropSet { set }); + return Err(VmError::new(VmErrorKind::MissingDropSet { set })); }; for &addr in addresses { - *vm_try!(self.stack.at_mut(addr)) = Value::empty(); + *self.stack.at_mut(addr)? = Value::empty(); } - VmResult::Ok(()) + Ok(()) } /// Swap two values on the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_swap(&mut self, a: InstAddress, b: InstAddress) -> VmResult<()> { - vm_try!(self.stack.swap(a, b)); - VmResult::Ok(()) + fn op_swap(&mut self, a: Address, b: Address) -> Result<(), VmError> { + self.stack.swap(a, b)?; + Ok(()) } /// Perform a jump operation. #[cfg_attr(feature = "bench", inline(never))] - fn op_jump(&mut self, jump: usize) -> VmResult<()> { - self.ip = vm_try!(self.unit.translate(jump)); - VmResult::Ok(()) + fn op_jump(&mut self, jump: usize) -> Result<(), VmError> { + self.ip = self.unit.translate(jump)?; + Ok(()) } /// Perform a conditional jump operation. #[cfg_attr(feature = "bench", inline(never))] #[cfg_attr(not(feature = "bench"), inline)] - fn op_jump_if(&mut self, cond: InstAddress, jump: usize) -> Result<(), VmErrorKind> { + fn op_jump_if(&mut self, cond: Address, jump: usize) -> Result<(), VmErrorKind> { if matches!( self.stack.at(cond).as_ref(), Repr::Inline(Inline::Bool(true)) @@ -1353,7 +1312,7 @@ impl Vm { /// pop-and-jump-if-not instruction. #[cfg_attr(feature = "bench", inline(never))] - fn op_jump_if_not(&mut self, cond: InstAddress, jump: usize) -> Result<(), VmErrorKind> { + fn op_jump_if_not(&mut self, cond: Address, jump: usize) -> Result<(), VmErrorKind> { if matches!( self.stack.at(cond).as_ref(), Repr::Inline(Inline::Bool(false)) @@ -1366,196 +1325,224 @@ impl Vm { /// Construct a new vec. #[cfg_attr(feature = "bench", inline(never))] - fn op_vec(&mut self, addr: InstAddress, count: usize, out: Output) -> VmResult<()> { - let vec = vm_try!(self.stack.slice_at_mut(addr, count)); - let vec = vm_try!(vec.iter_mut().map(take).try_collect::>()); - vm_try!(out.store(&mut self.stack, Vec::from(vec))); - VmResult::Ok(()) + fn op_vec(&mut self, addr: Address, count: usize, out: Output) -> Result<(), VmError> { + let vec = self.stack.slice_at_mut(addr, count)?; + let vec = vec + .iter_mut() + .map(take) + .try_collect::>()?; + out.store(&mut self.stack, Vec::from(vec))?; + Ok(()) } /// Construct a new tuple. #[cfg_attr(feature = "bench", inline(never))] - fn op_tuple(&mut self, addr: InstAddress, count: usize, out: Output) -> VmResult<()> { - let tuple = vm_try!(self.stack.slice_at_mut(addr, count)); + fn op_tuple(&mut self, addr: Address, count: usize, out: Output) -> Result<(), VmError> { + let tuple = self.stack.slice_at_mut(addr, count)?; - let tuple = vm_try!(tuple + let tuple = tuple .iter_mut() .map(take) - .try_collect::>()); + .try_collect::>()?; - vm_try!(out.store(&mut self.stack, || OwnedTuple::try_from(tuple))); - VmResult::Ok(()) + out.store(&mut self.stack, || OwnedTuple::try_from(tuple))?; + Ok(()) } /// Construct a new tuple with a fixed number of arguments. #[cfg_attr(feature = "bench", inline(never))] - fn op_tuple_n(&mut self, addr: &[InstAddress], out: Output) -> VmResult<()> { - let mut tuple = vm_try!(alloc::Vec::::try_with_capacity(addr.len())); + fn op_tuple_n(&mut self, addr: &[Address], out: Output) -> Result<(), VmError> { + let mut tuple = alloc::Vec::::try_with_capacity(addr.len())?; for &arg in addr { let value = self.stack.at(arg).clone(); - vm_try!(tuple.try_push(value)); + tuple.try_push(value)?; } - vm_try!(out.store(&mut self.stack, || OwnedTuple::try_from(tuple))); - VmResult::Ok(()) + out.store(&mut self.stack, || OwnedTuple::try_from(tuple))?; + Ok(()) } /// Push the tuple that is on top of the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_environment(&mut self, addr: InstAddress, count: usize, out: Output) -> VmResult<()> { + fn op_environment(&mut self, addr: Address, count: usize, out: Output) -> Result<(), VmError> { let tuple = self.stack.at(addr).clone(); - let tuple = vm_try!(tuple.borrow_tuple_ref()); + let tuple = tuple.borrow_tuple_ref()?; if tuple.len() != count { - return err(VmErrorKind::BadEnvironmentCount { + return Err(VmError::new(VmErrorKind::BadEnvironmentCount { expected: count, actual: tuple.len(), - }); + })); } if let Some(addr) = out.as_addr() { - let out = vm_try!(self.stack.slice_at_mut(addr, count)); + let out = self.stack.slice_at_mut(addr, count)?; for (value, out) in tuple.iter().zip(out.iter_mut()) { out.clone_from(value); } } - VmResult::Ok(()) + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_allocate(&mut self, size: usize) -> VmResult<()> { - vm_try!(self.stack.resize(size)); - VmResult::Ok(()) + fn op_allocate(&mut self, size: usize) -> Result<(), VmError> { + self.stack.resize(size)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_not(&mut self, operand: InstAddress, out: Output) -> VmResult<()> { - let value = self.stack.at(operand); - - let value = match value.as_ref() { - Repr::Inline(Inline::Bool(value)) => Value::from(!value), - Repr::Inline(Inline::Unsigned(value)) => Value::from(!value), - Repr::Inline(Inline::Signed(value)) => Value::from(!value), - value => { - let operand = value.type_info(); - return err(VmErrorKind::UnsupportedUnaryOperation { op: "!", operand }); - } - }; - - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + fn op_not(&mut self, addr: Address, out: Output) -> Result<(), VmError> { + self.unary(addr, out, &Protocol::NOT, |inline| match *inline { + Inline::Bool(value) => Some(Inline::Bool(!value)), + Inline::Unsigned(value) => Some(Inline::Unsigned(!value)), + Inline::Signed(value) => Some(Inline::Signed(!value)), + _ => None, + }) } #[cfg_attr(feature = "bench", inline(never))] - fn op_neg(&mut self, addr: InstAddress, out: Output) -> VmResult<()> { - let value = self.stack.at(addr); + fn op_neg(&mut self, addr: Address, out: Output) -> Result<(), VmError> { + self.unary(addr, out, &Protocol::NEG, |inline| match *inline { + Inline::Signed(value) => Some(Inline::Signed(-value)), + Inline::Float(value) => Some(Inline::Float(-value)), + _ => None, + }) + } - let value = match value.as_ref() { - Repr::Inline(Inline::Float(value)) => Value::from(-value), - Repr::Inline(Inline::Signed(value)) => Value::from(-value), - actual => { - let operand = actual.type_info(); - return err(VmErrorKind::UnsupportedUnaryOperation { op: "-", operand }); - } + fn unary( + &mut self, + operand: Address, + out: Output, + protocol: &'static Protocol, + op: impl FnOnce(&Inline) -> Option, + ) -> Result<(), VmError> { + let operand = self.stack.at(operand); + + 'fallback: { + let store = match operand.as_ref() { + Repr::Inline(inline) => op(inline), + Repr::Any(..) => break 'fallback, + _ => None, + }; + + let Some(store) = store else { + return Err(VmError::new(VmErrorKind::UnsupportedUnaryOperation { + op: protocol.name, + operand: operand.type_info(), + })); + }; + + out.store(&mut self.stack, store)?; + return Ok(()); }; - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + let operand = operand.clone(); + + if let CallResult::Unsupported(operand) = + self.call_instance_fn(Isolated::None, operand, protocol, &mut (), out)? + { + return Err(VmError::new(VmErrorKind::UnsupportedUnaryOperation { + op: protocol.name, + operand: operand.type_info(), + })); + } + + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_op( &mut self, op: InstOp, - lhs: InstAddress, - rhs: InstAddress, + lhs: Address, + rhs: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { match op { InstOp::Lt => { - vm_try!(self.internal_cmp(|o| matches!(o, Ordering::Less), lhs, rhs, out)); + self.internal_cmp(|o| matches!(o, Ordering::Less), lhs, rhs, out)?; } InstOp::Le => { - vm_try!(self.internal_cmp( + self.internal_cmp( |o| matches!(o, Ordering::Less | Ordering::Equal), lhs, rhs, - out - )); + out, + )?; } InstOp::Gt => { - vm_try!(self.internal_cmp(|o| matches!(o, Ordering::Greater), lhs, rhs, out)); + self.internal_cmp(|o| matches!(o, Ordering::Greater), lhs, rhs, out)?; } InstOp::Ge => { - vm_try!(self.internal_cmp( + self.internal_cmp( |o| matches!(o, Ordering::Greater | Ordering::Equal), lhs, rhs, - out - )); + out, + )?; } InstOp::Eq => { let rhs = self.stack.at(rhs); let lhs = self.stack.at(lhs); let test = if let (Some(lhs), Some(rhs)) = (lhs.as_inline(), rhs.as_inline()) { - vm_try!(lhs.partial_eq(rhs)) + lhs.partial_eq(rhs)? } else { let lhs = lhs.clone(); let rhs = rhs.clone(); - vm_try!(Value::partial_eq_with(&lhs, &rhs, self)) + Value::partial_eq_with(&lhs, &rhs, self)? }; - vm_try!(out.store(&mut self.stack, test)); + out.store(&mut self.stack, test)?; } InstOp::Neq => { let rhs = self.stack.at(rhs); let lhs = self.stack.at(lhs); let test = if let (Some(lhs), Some(rhs)) = (lhs.as_inline(), rhs.as_inline()) { - vm_try!(lhs.partial_eq(rhs)) + lhs.partial_eq(rhs)? } else { let lhs = lhs.clone(); let rhs = rhs.clone(); - vm_try!(Value::partial_eq_with(&lhs, &rhs, self)) + Value::partial_eq_with(&lhs, &rhs, self)? }; - vm_try!(out.store(&mut self.stack, !test)); + out.store(&mut self.stack, !test)?; } InstOp::And => { - vm_try!(self.internal_bool(|a, b| a && b, "&&", lhs, rhs, out)); + self.internal_bool(|a, b| a && b, "&&", lhs, rhs, out)?; } InstOp::Or => { - vm_try!(self.internal_bool(|a, b| a || b, "||", lhs, rhs, out)); + self.internal_bool(|a, b| a || b, "||", lhs, rhs, out)?; } InstOp::As => { - let value = vm_try!(self.as_op(lhs, rhs)); - vm_try!(out.store(&mut self.stack, value)); + let value = self.as_op(lhs, rhs)?; + out.store(&mut self.stack, value)?; } InstOp::Is => { - let is_instance = vm_try!(self.test_is_instance(lhs, rhs)); - vm_try!(out.store(&mut self.stack, is_instance)); + let is_instance = self.test_is_instance(lhs, rhs)?; + out.store(&mut self.stack, is_instance)?; } InstOp::IsNot => { - let is_instance = vm_try!(self.test_is_instance(lhs, rhs)); - vm_try!(out.store(&mut self.stack, !is_instance)); + let is_instance = self.test_is_instance(lhs, rhs)?; + out.store(&mut self.stack, !is_instance)?; } } - VmResult::Ok(()) + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_arithmetic( &mut self, op: InstArithmeticOp, - lhs: InstAddress, - rhs: InstAddress, + lhs: Address, + rhs: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let ops = ArithmeticOps::from_op(op); let lhs = self.stack.at(lhs); @@ -1565,13 +1552,13 @@ impl Vm { let inline = match (lhs.as_ref(), rhs.as_ref()) { (Repr::Inline(lhs), Repr::Inline(rhs)) => match (lhs, rhs) { (Inline::Unsigned(lhs), rhs) => { - let rhs = vm_try!(rhs.as_integer()); - let value = vm_try!((ops.u64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let value = (ops.u64)(*lhs, rhs).ok_or_else(ops.error)?; Inline::Unsigned(value) } (Inline::Signed(lhs), rhs) => { - let rhs = vm_try!(rhs.as_integer()); - let value = vm_try!((ops.i64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let value = (ops.i64)(*lhs, rhs).ok_or_else(ops.error)?; Inline::Signed(value) } (Inline::Float(lhs), Inline::Float(rhs)) => { @@ -1579,27 +1566,27 @@ impl Vm { Inline::Float(value) } (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }, (Repr::Any(..), ..) => { break 'fallback; } (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }; - vm_try!(out.store(&mut self.stack, inline)); - return VmResult::Ok(()); + out.store(&mut self.stack, inline)?; + return Ok(()); } let lhs = lhs.clone(); @@ -1608,26 +1595,26 @@ impl Vm { let mut args = DynGuardedArgs::new((rhs.clone(),)); if let CallResult::Unsupported(lhs) = - vm_try!(self.call_instance_fn(Isolated::None, lhs, &ops.protocol, &mut args, out)) + self.call_instance_fn(Isolated::None, lhs, &ops.protocol, &mut args, out)? { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } - VmResult::Ok(()) + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_bitwise( &mut self, op: InstBitwiseOp, - lhs: InstAddress, - rhs: InstAddress, + lhs: Address, + rhs: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let ops = BitwiseOps::from_op(op); let lhs = self.stack.at(lhs); @@ -1636,12 +1623,12 @@ impl Vm { 'fallback: { let inline = match (lhs.as_ref(), rhs.as_ref()) { (Repr::Inline(Inline::Unsigned(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); + let rhs = rhs.as_integer()?; let value = (ops.u64)(*lhs, rhs); Inline::Unsigned(value) } (Repr::Inline(Inline::Signed(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); + let rhs = rhs.as_integer()?; let value = (ops.i64)(*lhs, rhs); Inline::Signed(value) } @@ -1653,16 +1640,16 @@ impl Vm { break 'fallback; } (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }; - vm_try!(out.store(&mut self.stack, inline)); - return VmResult::Ok(()); + out.store(&mut self.stack, inline)?; + return Ok(()); }; let lhs = lhs.clone(); @@ -1671,93 +1658,93 @@ impl Vm { let mut args = DynGuardedArgs::new((&rhs,)); if let CallResult::Unsupported(lhs) = - vm_try!(self.call_instance_fn(Isolated::None, lhs, &ops.protocol, &mut args, out)) + self.call_instance_fn(Isolated::None, lhs, &ops.protocol, &mut args, out)? { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } - VmResult::Ok(()) + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_shift( &mut self, op: InstShiftOp, - lhs: InstAddress, - rhs: InstAddress, + lhs: Address, + rhs: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let ops = ShiftOps::from_op(op); let (lhs, rhs) = 'fallback: { let inline = { - match vm_try!(self.stack.pair(lhs, rhs)) { + match self.stack.pair(lhs, rhs)? { Pair::Same(value) => match value.as_mut() { Repr::Inline(Inline::Unsigned(value)) => { - let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(ops.error)); - let value = vm_try!((ops.u64)(*value, shift).ok_or_else(ops.error)); + let shift = u32::try_from(*value).ok().ok_or_else(ops.error)?; + let value = (ops.u64)(*value, shift).ok_or_else(ops.error)?; Inline::Unsigned(value) } Repr::Inline(Inline::Signed(value)) => { - let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(ops.error)); - let value = vm_try!((ops.i64)(*value, shift).ok_or_else(ops.error)); + let shift = u32::try_from(*value).ok().ok_or_else(ops.error)?; + let value = (ops.i64)(*value, shift).ok_or_else(ops.error)?; Inline::Signed(value) } Repr::Any(..) => break 'fallback (value.clone(), value.clone()), value => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), - }); + })); } }, Pair::Pair(lhs, rhs) => match (lhs.as_mut(), rhs.as_ref()) { (Repr::Inline(Inline::Unsigned(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); - let value = vm_try!((ops.u64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let value = (ops.u64)(*lhs, rhs).ok_or_else(ops.error)?; Inline::Unsigned(value) } (Repr::Inline(Inline::Signed(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); - let value = vm_try!((ops.i64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let value = (ops.i64)(*lhs, rhs).ok_or_else(ops.error)?; Inline::Signed(value) } (Repr::Any(..), _) => { break 'fallback (lhs.clone(), rhs.clone()); } (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }, } }; - vm_try!(out.store(&mut self.stack, inline)); - return VmResult::Ok(()); + out.store(&mut self.stack, inline)?; + return Ok(()); }; let mut args = DynGuardedArgs::new((rhs.clone(),)); if let CallResult::Unsupported(lhs) = - vm_try!(self.call_instance_fn(Isolated::None, lhs, &ops.protocol, &mut args, out)) + self.call_instance_fn(Isolated::None, lhs, &ops.protocol, &mut args, out)? { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } - VmResult::Ok(()) + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] @@ -1765,61 +1752,61 @@ impl Vm { &mut self, op: InstArithmeticOp, target: InstTarget, - rhs: InstAddress, - ) -> VmResult<()> { + rhs: Address, + ) -> Result<(), VmError> { let ops = AssignArithmeticOps::from_op(op); - let fallback = match vm_try!(target_value(&mut self.stack, &self.unit, target, rhs)) { + let fallback = match target_value(&mut self.stack, &self.unit, target, rhs)? { TargetValue::Same(value) => match value.as_mut() { Repr::Inline(Inline::Signed(value)) => { - let out = vm_try!((ops.i64)(*value, *value).ok_or_else(ops.error)); + let out = (ops.i64)(*value, *value).ok_or_else(ops.error)?; *value = out; - return VmResult::Ok(()); + return Ok(()); } Repr::Inline(Inline::Unsigned(value)) => { - let out = vm_try!((ops.u64)(*value, *value).ok_or_else(ops.error)); + let out = (ops.u64)(*value, *value).ok_or_else(ops.error)?; *value = out; - return VmResult::Ok(()); + return Ok(()); } Repr::Inline(Inline::Float(value)) => { let out = (ops.f64)(*value, *value); *value = out; - return VmResult::Ok(()); + return Ok(()); } Repr::Any(..) => TargetFallback::Value(value.clone(), value.clone()), value => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), - }); + })); } }, TargetValue::Pair(mut lhs, rhs) => match (lhs.as_mut(), rhs.as_ref()) { (Repr::Inline(Inline::Signed(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!((ops.i64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let out = (ops.i64)(*lhs, rhs).ok_or_else(ops.error)?; *lhs = out; - return VmResult::Ok(()); + return Ok(()); } (Repr::Inline(Inline::Unsigned(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!((ops.u64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let out = (ops.u64)(*lhs, rhs).ok_or_else(ops.error)?; *lhs = out; - return VmResult::Ok(()); + return Ok(()); } (Repr::Inline(Inline::Float(lhs)), Repr::Inline(Inline::Float(rhs))) => { let out = (ops.f64)(*lhs, *rhs); *lhs = out; - return VmResult::Ok(()); + return Ok(()); } (Repr::Any(..), _) => TargetFallback::Value(lhs.clone(), rhs.clone()), (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }, TargetValue::Fallback(fallback) => fallback, @@ -1833,58 +1820,58 @@ impl Vm { &mut self, op: InstBitwiseOp, target: InstTarget, - rhs: InstAddress, - ) -> VmResult<()> { + rhs: Address, + ) -> Result<(), VmError> { let ops = AssignBitwiseOps::from_ops(op); - let fallback = match vm_try!(target_value(&mut self.stack, &self.unit, target, rhs)) { + let fallback = match target_value(&mut self.stack, &self.unit, target, rhs)? { TargetValue::Same(value) => match value.as_mut() { Repr::Inline(Inline::Unsigned(value)) => { let rhs = *value; (ops.u64)(value, rhs); - return VmResult::Ok(()); + return Ok(()); } Repr::Inline(Inline::Signed(value)) => { let rhs = *value; (ops.i64)(value, rhs); - return VmResult::Ok(()); + return Ok(()); } Repr::Inline(Inline::Bool(value)) => { let rhs = *value; (ops.bool)(value, rhs); - return VmResult::Ok(()); + return Ok(()); } Repr::Any(..) => TargetFallback::Value(value.clone(), value.clone()), value => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), - }); + })); } }, TargetValue::Pair(mut lhs, rhs) => match (lhs.as_mut(), rhs.as_ref()) { (Repr::Inline(Inline::Unsigned(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); + let rhs = rhs.as_integer()?; (ops.u64)(lhs, rhs); - return VmResult::Ok(()); + return Ok(()); } (Repr::Inline(Inline::Signed(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); + let rhs = rhs.as_integer()?; (ops.i64)(lhs, rhs); - return VmResult::Ok(()); + return Ok(()); } (Repr::Inline(Inline::Bool(lhs)), Repr::Inline(Inline::Bool(rhs))) => { (ops.bool)(lhs, *rhs); - return VmResult::Ok(()); + return Ok(()); } (Repr::Any(..), ..) => TargetFallback::Value(lhs.clone(), rhs.clone()), (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }, TargetValue::Fallback(fallback) => fallback, @@ -1898,53 +1885,53 @@ impl Vm { &mut self, op: InstShiftOp, target: InstTarget, - rhs: InstAddress, - ) -> VmResult<()> { + rhs: Address, + ) -> Result<(), VmError> { let ops = AssignShiftOps::from_op(op); - let fallback = match vm_try!(target_value(&mut self.stack, &self.unit, target, rhs)) { + let fallback = match target_value(&mut self.stack, &self.unit, target, rhs)? { TargetValue::Same(value) => match value.as_mut() { Repr::Inline(Inline::Unsigned(value)) => { - let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(ops.error)); - let out = vm_try!((ops.u64)(*value, shift).ok_or_else(ops.error)); + let shift = u32::try_from(*value).ok().ok_or_else(ops.error)?; + let out = (ops.u64)(*value, shift).ok_or_else(ops.error)?; *value = out; - return VmResult::Ok(()); + return Ok(()); } Repr::Inline(Inline::Signed(value)) => { - let shift = vm_try!(u32::try_from(*value).ok().ok_or_else(ops.error)); - let out = vm_try!((ops.i64)(*value, shift).ok_or_else(ops.error)); + let shift = u32::try_from(*value).ok().ok_or_else(ops.error)?; + let out = (ops.i64)(*value, shift).ok_or_else(ops.error)?; *value = out; - return VmResult::Ok(()); + return Ok(()); } Repr::Any(..) => TargetFallback::Value(value.clone(), value.clone()), value => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: value.type_info(), rhs: value.type_info(), - }); + })); } }, TargetValue::Pair(mut lhs, rhs) => match (lhs.as_mut(), rhs.as_ref()) { (Repr::Inline(Inline::Unsigned(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!((ops.u64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let out = (ops.u64)(*lhs, rhs).ok_or_else(ops.error)?; *lhs = out; - return VmResult::Ok(()); + return Ok(()); } (Repr::Inline(Inline::Signed(lhs)), Repr::Inline(rhs)) => { - let rhs = vm_try!(rhs.as_integer()); - let out = vm_try!((ops.i64)(*lhs, rhs).ok_or_else(ops.error)); + let rhs = rhs.as_integer()?; + let out = (ops.i64)(*lhs, rhs).ok_or_else(ops.error)?; *lhs = out; - return VmResult::Ok(()); + return Ok(()); } (Repr::Any(..), _) => TargetFallback::Value(lhs.clone(), rhs.clone()), (lhs, rhs) => { - return err(VmErrorKind::UnsupportedBinaryOperation { + return Err(VmError::new(VmErrorKind::UnsupportedBinaryOperation { op: ops.protocol.name, lhs: lhs.type_info(), rhs: rhs.type_info(), - }); + })); } }, TargetValue::Fallback(fallback) => fallback, @@ -1957,17 +1944,17 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_index_set( &mut self, - target: InstAddress, - index: InstAddress, - value: InstAddress, - ) -> VmResult<()> { + target: Address, + index: Address, + value: Address, + ) -> Result<(), VmError> { let target = self.stack.at(target); let index = self.stack.at(index); let value = self.stack.at(value); - if let Some(field) = vm_try!(index.try_borrow_ref::()) { - if vm_try!(Self::try_object_slot_index_set(target, &field, value)) { - return VmResult::Ok(()); + if let Some(field) = index.try_borrow_ref::()? { + if Self::try_object_slot_index_set(target, &field, value)? { + return Ok(()); } } @@ -1977,38 +1964,38 @@ impl Vm { let mut args = DynGuardedArgs::new((&index, &value)); - if let CallResult::Unsupported(target) = vm_try!(self.call_instance_fn( + if let CallResult::Unsupported(target) = self.call_instance_fn( Isolated::None, target, &Protocol::INDEX_SET, &mut args, - Output::discard() - )) { - return err(VmErrorKind::UnsupportedIndexSet { + Output::discard(), + )? { + return Err(VmError::new(VmErrorKind::UnsupportedIndexSet { target: target.type_info(), index: index.type_info(), value: value.type_info(), - }); + })); } - VmResult::Ok(()) + Ok(()) } #[inline] #[tracing::instrument(skip(self, return_value))] - fn op_return_internal(&mut self, return_value: Value) -> VmResult> { + fn op_return_internal(&mut self, return_value: Value) -> Result, VmError> { let (exit, out) = self.pop_call_frame(); let out = if let Some(out) = out { - vm_try!(out.store(&mut self.stack, return_value)); + out.store(&mut self.stack, return_value)?; out } else { let addr = self.stack.addr(); - vm_try!(self.stack.push(return_value)); + self.stack.push(return_value)?; addr.output() }; - VmResult::Ok(exit.then_some(out)) + Ok(exit.then_some(out)) } fn lookup_function_by_hash(&self, hash: Hash) -> Result { @@ -2051,61 +2038,66 @@ impl Vm { } #[cfg_attr(feature = "bench", inline(never))] - fn op_return(&mut self, addr: InstAddress) -> VmResult> { + fn op_return(&mut self, addr: Address) -> Result, VmError> { let return_value = self.stack.at(addr).clone(); self.op_return_internal(return_value) } #[cfg_attr(feature = "bench", inline(never))] #[tracing::instrument(skip(self))] - fn op_return_unit(&mut self) -> VmResult> { + fn op_return_unit(&mut self) -> Result, VmError> { let (exit, out) = self.pop_call_frame(); let out = if let Some(out) = out { - vm_try!(out.store(&mut self.stack, ())); + out.store(&mut self.stack, ())?; out } else { let addr = self.stack.addr(); - vm_try!(self.stack.push(())); + self.stack.push(())?; addr.output() }; - VmResult::Ok(exit.then_some(out)) + Ok(exit.then_some(out)) } #[cfg_attr(feature = "bench", inline(never))] - fn op_load_instance_fn(&mut self, addr: InstAddress, hash: Hash, out: Output) -> VmResult<()> { + fn op_load_instance_fn( + &mut self, + addr: Address, + hash: Hash, + out: Output, + ) -> Result<(), VmError> { let instance = self.stack.at(addr); let ty = instance.type_hash(); let hash = Hash::associated_function(ty, hash); - vm_try!(out.store(&mut self.stack, || Type::new(hash))); - VmResult::Ok(()) + out.store(&mut self.stack, || Type::new(hash))?; + Ok(()) } /// Perform an index get operation. #[cfg_attr(feature = "bench", inline(never))] fn op_index_get( &mut self, - target: InstAddress, - index: InstAddress, + target: Address, + index: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let value = 'store: { let index = self.stack.at(index); let target = self.stack.at(target); match index.as_ref() { Repr::Inline(inline) => { - let index = vm_try!(inline.as_integer::()); + let index = inline.as_integer::()?; - if let Some(value) = vm_try!(Self::try_tuple_like_index_get(target, index)) { + if let Some(value) = Self::try_tuple_like_index_get(target, index)? { break 'store value; } } Repr::Any(value) => { - if let Some(index) = vm_try!(value.try_borrow_ref::()) { + if let Some(index) = value.try_borrow_ref::()? { if let Some(value) = - vm_try!(Self::try_object_like_index_get(target, index.as_str())) + Self::try_object_like_index_get(target, index.as_str())? { break 'store value; } @@ -2119,92 +2111,88 @@ impl Vm { let mut args = DynGuardedArgs::new((&index,)); - if let CallResult::Unsupported(target) = vm_try!(self.call_instance_fn( - Isolated::None, - target, - &Protocol::INDEX_GET, - &mut args, - out - )) { - return err(VmErrorKind::UnsupportedIndexGet { + if let CallResult::Unsupported(target) = + self.call_instance_fn(Isolated::None, target, &Protocol::INDEX_GET, &mut args, out)? + { + return Err(VmError::new(VmErrorKind::UnsupportedIndexGet { target: target.type_info(), index: index.type_info(), - }); + })); } - return VmResult::Ok(()); + return Ok(()); }; - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + out.store(&mut self.stack, value)?; + Ok(()) } /// Perform an index get operation specialized for tuples. #[cfg_attr(feature = "bench", inline(never))] fn op_tuple_index_set( &mut self, - target: InstAddress, + target: Address, index: usize, - value: InstAddress, - ) -> VmResult<()> { + value: Address, + ) -> Result<(), VmError> { let value = self.stack.at(value); let target = self.stack.at(target); - if vm_try!(Self::try_tuple_like_index_set(target, index, value)) { - return VmResult::Ok(()); + if Self::try_tuple_like_index_set(target, index, value)? { + return Ok(()); } - err(VmErrorKind::UnsupportedTupleIndexSet { + Err(VmError::new(VmErrorKind::UnsupportedTupleIndexSet { target: target.type_info(), - }) + })) } /// Perform an index get operation specialized for tuples. #[cfg_attr(feature = "bench", inline(never))] fn op_tuple_index_get_at( &mut self, - addr: InstAddress, + addr: Address, index: usize, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let value = self.stack.at(addr); - if let Some(value) = vm_try!(Self::try_tuple_like_index_get(value, index)) { - vm_try!(out.store(&mut self.stack, value)); - return VmResult::Ok(()); + if let Some(value) = Self::try_tuple_like_index_get(value, index)? { + out.store(&mut self.stack, value)?; + return Ok(()); } let value = value.clone(); if let CallResult::Unsupported(value) = - vm_try!(self.call_index_fn(&Protocol::GET, value, index, &mut (), out)) + self.call_index_fn(&Protocol::GET, value, index, &mut (), out)? { - return err(VmErrorKind::UnsupportedTupleIndexGet { + return Err(VmError::new(VmErrorKind::UnsupportedTupleIndexGet { target: value.type_info(), index, - }); + })); } - VmResult::Ok(()) + Ok(()) } /// Perform a specialized index set operation on an object. #[cfg_attr(feature = "bench", inline(never))] fn op_object_index_set( &mut self, - target: InstAddress, + target: Address, slot: usize, - value: InstAddress, - ) -> VmResult<()> { + value: Address, + ) -> Result<(), VmError> { let target = self.stack.at(target); let value = self.stack.at(value); let Some(field) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; - if vm_try!(Self::try_object_slot_index_set(target, field, value)) { - return VmResult::Ok(()); + if Self::try_object_slot_index_set(target, field, value)? { + return Ok(()); } let target = target.clone(); @@ -2215,237 +2203,236 @@ impl Vm { let mut args = DynGuardedArgs::new((value,)); let result = - vm_try!(self.call_field_fn(&Protocol::SET, target, hash, &mut args, Output::discard())); + self.call_field_fn(&Protocol::SET, target, hash, &mut args, Output::discard())?; if let CallResult::Unsupported(target) = result { let Some(field) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; - return err(VmErrorKind::UnsupportedObjectSlotIndexSet { + return Err(VmError::new(VmErrorKind::UnsupportedObjectSlotIndexSet { target: target.type_info(), field: field.clone(), - }); + })); }; - VmResult::Ok(()) + Ok(()) } /// Perform a specialized index get operation on an object. #[cfg_attr(feature = "bench", inline(never))] fn op_object_index_get_at( &mut self, - addr: InstAddress, + addr: Address, slot: usize, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let target = self.stack.at(addr); let Some(index) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; match target.as_ref() { Repr::Dynamic(data) if matches!(data.rtti().kind, RttiKind::Struct) => { - let Some(value) = vm_try!(data.get_field_ref(index.as_str())) else { - return err(VmErrorKind::ObjectIndexMissing { slot }); + let Some(value) = data.get_field_ref(index.as_str())? else { + return Err(VmError::new(VmErrorKind::ObjectIndexMissing { slot })); }; let value = value.clone(); - vm_try!(out.store(&mut self.stack, value)); - return VmResult::Ok(()); + out.store(&mut self.stack, value)?; + return Ok(()); } Repr::Any(value) if value.type_hash() == Object::HASH => { - let object = vm_try!(value.borrow_ref::()); + let object = value.borrow_ref::()?; let Some(value) = object.get(index.as_str()) else { - return err(VmErrorKind::ObjectIndexMissing { slot }); + return Err(VmError::new(VmErrorKind::ObjectIndexMissing { slot })); }; let value = value.clone(); - vm_try!(out.store(&mut self.stack, value)); - return VmResult::Ok(()); + out.store(&mut self.stack, value)?; + return Ok(()); } Repr::Any(..) => {} target => { - return err(VmErrorKind::UnsupportedObjectSlotIndexGet { + return Err(VmError::new(VmErrorKind::UnsupportedObjectSlotIndexGet { target: target.type_info(), field: index.clone(), - }); + })); } } let target = target.clone(); if let CallResult::Unsupported(target) = - vm_try!(self.call_field_fn(&Protocol::GET, target, index.hash(), &mut (), out)) + self.call_field_fn(&Protocol::GET, target, index.hash(), &mut (), out)? { let Some(field) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; - return err(VmErrorKind::UnsupportedObjectSlotIndexGet { + return Err(VmError::new(VmErrorKind::UnsupportedObjectSlotIndexGet { target: target.type_info(), field: field.clone(), - }); + })); } - VmResult::Ok(()) + Ok(()) } /// Operation to allocate an object. #[cfg_attr(feature = "bench", inline(never))] - fn op_object(&mut self, addr: InstAddress, slot: usize, out: Output) -> VmResult<()> { + fn op_object(&mut self, addr: Address, slot: usize, out: Output) -> Result<(), VmError> { let Some(keys) = self.unit.lookup_object_keys(slot) else { - return err(VmErrorKind::MissingStaticObjectKeys { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticObjectKeys { slot })); }; - let mut object = vm_try!(Object::with_capacity(keys.len())); - let values = vm_try!(self.stack.slice_at_mut(addr, keys.len())); + let mut object = Object::with_capacity(keys.len())?; + let values = self.stack.slice_at_mut(addr, keys.len())?; for (key, value) in keys.iter().zip(values) { - let key = vm_try!(String::try_from(key.as_str())); - vm_try!(object.insert(key, take(value))); + let key = String::try_from(key.as_str())?; + object.insert(key, take(value))?; } - vm_try!(out.store(&mut self.stack, object)); - VmResult::Ok(()) + out.store(&mut self.stack, object)?; + Ok(()) } /// Operation to allocate an object. #[cfg_attr(feature = "bench", inline(never))] - fn op_range(&mut self, range: InstRange, out: Output) -> VmResult<()> { + fn op_range(&mut self, range: InstRange, out: Output) -> Result<(), VmError> { let value = match range { InstRange::RangeFrom { start } => { let s = self.stack.at(start).clone(); - vm_try!(Value::new(RangeFrom::new(s.clone()))) - } - InstRange::RangeFull => { - vm_try!(Value::new(RangeFull::new())) + Value::new(RangeFrom::new(s.clone()))? } + InstRange::RangeFull => Value::new(RangeFull::new())?, InstRange::RangeInclusive { start, end } => { let s = self.stack.at(start).clone(); let e = self.stack.at(end).clone(); - vm_try!(Value::new(RangeInclusive::new(s.clone(), e.clone()))) + Value::new(RangeInclusive::new(s.clone(), e.clone()))? } InstRange::RangeToInclusive { end } => { let e = self.stack.at(end).clone(); - vm_try!(Value::new(RangeToInclusive::new(e.clone()))) + Value::new(RangeToInclusive::new(e.clone()))? } InstRange::RangeTo { end } => { let e = self.stack.at(end).clone(); - vm_try!(Value::new(RangeTo::new(e.clone()))) + Value::new(RangeTo::new(e.clone()))? } InstRange::Range { start, end } => { let s = self.stack.at(start).clone(); let e = self.stack.at(end).clone(); - vm_try!(Value::new(Range::new(s.clone(), e.clone()))) + Value::new(Range::new(s.clone(), e.clone()))? } }; - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + out.store(&mut self.stack, value)?; + Ok(()) } /// Operation to allocate an object struct. #[cfg_attr(feature = "bench", inline(never))] - fn op_struct(&mut self, addr: InstAddress, hash: Hash, out: Output) -> VmResult<()> { + fn op_struct(&mut self, addr: Address, hash: Hash, out: Output) -> Result<(), VmError> { let Some(rtti) = self.unit.lookup_rtti(&hash) else { - return err(VmErrorKind::MissingRtti { hash }); + return Err(VmError::new(VmErrorKind::MissingRtti { hash })); }; - let values = vm_try!(self.stack.slice_at_mut(addr, rtti.fields.len())); - let value = vm_try!(Dynamic::new(rtti.clone(), values.iter_mut().map(take))); - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + let values = self.stack.slice_at_mut(addr, rtti.fields.len())?; + let value = AnySequence::new(rtti.clone(), values.iter_mut().map(take))?; + out.store(&mut self.stack, value)?; + Ok(()) } /// Operation to allocate a constant value from an array of values. #[cfg_attr(feature = "bench", inline(never))] fn op_const_construct( &mut self, - addr: InstAddress, + addr: Address, hash: Hash, count: usize, out: Output, - ) -> VmResult<()> { - let values = vm_try!(self.stack.slice_at_mut(addr, count)); + ) -> Result<(), VmError> { + let values = self.stack.slice_at_mut(addr, count)?; let Some(construct) = self.context.construct(&hash) else { - return err(VmErrorKind::MissingConstantConstructor { hash }); + return Err(VmError::new(VmErrorKind::MissingConstantConstructor { + hash, + })); }; - let value = vm_try!(construct.runtime_construct(values)); - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(()) + let value = construct.runtime_construct(values)?; + out.store(&mut self.stack, value)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_string(&mut self, slot: usize, out: Output) -> VmResult<()> { + fn op_string(&mut self, slot: usize, out: Output) -> Result<(), VmError> { let Some(string) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; - vm_try!(out.store(&mut self.stack, string.as_str())); - VmResult::Ok(()) + out.store(&mut self.stack, string.as_str())?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_bytes(&mut self, slot: usize, out: Output) -> VmResult<()> { + fn op_bytes(&mut self, slot: usize, out: Output) -> Result<(), VmError> { let Some(bytes) = self.unit.lookup_bytes(slot) else { - return err(VmErrorKind::MissingStaticBytes { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticBytes { slot })); }; - vm_try!(out.store(&mut self.stack, bytes)); - VmResult::Ok(()) + out.store(&mut self.stack, bytes)?; + Ok(()) } /// Optimize operation to perform string concatenation. #[cfg_attr(feature = "bench", inline(never))] fn op_string_concat( &mut self, - addr: InstAddress, + addr: Address, len: usize, size_hint: usize, out: Output, - ) -> VmResult<()> { - let values = vm_try!(self.stack.slice_at(addr, len)); - let values = vm_try!(values.iter().cloned().try_collect::>()); + ) -> Result<(), VmError> { + let values = self.stack.slice_at(addr, len)?; + let values = values.iter().cloned().try_collect::>()?; - let mut s = vm_try!(String::try_with_capacity(size_hint)); + let mut s = String::try_with_capacity(size_hint)?; - let result = Formatter::format_with(&mut s, |f| { + Formatter::format_with(&mut s, |f| { for value in values { - vm_try!(value.display_fmt_with(f, &mut *self)); + value.display_fmt_with(f, &mut *self)?; } - VmResult::Ok(()) - }); + Ok::<_, VmError>(()) + })?; - vm_try!(result); - vm_try!(out.store(&mut self.stack, s)); - VmResult::Ok(()) + out.store(&mut self.stack, s)?; + Ok(()) } /// Push a format specification onto the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_format(&mut self, addr: InstAddress, spec: FormatSpec, out: Output) -> VmResult<()> { + fn op_format(&mut self, addr: Address, spec: FormatSpec, out: Output) -> Result<(), VmError> { let value = self.stack.at(addr).clone(); - vm_try!(out.store(&mut self.stack, || Format { value, spec })); - VmResult::Ok(()) + out.store(&mut self.stack, || Format { value, spec })?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_is_unit(&mut self, addr: InstAddress, out: Output) -> VmResult<()> { + fn op_is_unit(&mut self, addr: Address, out: Output) -> Result<(), VmError> { let value = self.stack.at(addr); let is_unit = matches!(value.as_inline(), Some(Inline::Unit)); - vm_try!(out.store(&mut self.stack, is_unit)); - VmResult::Ok(()) + out.store(&mut self.stack, is_unit)?; + Ok(()) } /// Perform the try operation on the given stack location. #[cfg_attr(feature = "bench", inline(never))] - fn op_try(&mut self, addr: InstAddress, out: Output) -> VmResult> { + fn op_try(&mut self, addr: Address, out: Output) -> Result, VmError> { let result = 'out: { let value = { let value = self.stack.at(addr); @@ -2453,12 +2440,12 @@ impl Vm { if let Repr::Any(value) = value.as_ref() { match value.type_hash() { Result::::HASH => { - let result = vm_try!(value.borrow_ref::>()); - break 'out vm_try!(result::result_try(&result)); + let result = value.borrow_ref::>()?; + break 'out result::result_try(&result)?; } Option::::HASH => { - let option = vm_try!(value.borrow_ref::>()); - break 'out vm_try!(option::option_try(&option)); + let option = value.borrow_ref::>()?; + break 'out option::option_try(&option)?; } _ => {} } @@ -2467,27 +2454,27 @@ impl Vm { value.clone() }; - match vm_try!(self.try_call_protocol_fn(&Protocol::TRY, value, &mut ())) { - CallResultOnly::Ok(value) => vm_try!(ControlFlow::from_value(value)), + match self.try_call_protocol_fn(&Protocol::TRY, value, &mut ())? { + CallResultOnly::Ok(value) => ControlFlow::from_value(value)?, CallResultOnly::Unsupported(target) => { - return err(VmErrorKind::UnsupportedTryOperand { + return Err(VmError::new(VmErrorKind::UnsupportedTryOperand { actual: target.type_info(), - }) + })); } } }; match result { ControlFlow::Continue(value) => { - vm_try!(out.store(&mut self.stack, value)); - VmResult::Ok(None) + out.store(&mut self.stack, value)?; + Ok(None) } - ControlFlow::Break(error) => VmResult::Ok(vm_try!(self.op_return_internal(error))), + ControlFlow::Break(error) => Ok(self.op_return_internal(error)?), } } #[cfg_attr(feature = "bench", inline(never))] - fn op_eq_character(&mut self, addr: InstAddress, value: char, out: Output) -> VmResult<()> { + fn op_eq_character(&mut self, addr: Address, value: char, out: Output) -> Result<(), VmError> { let v = self.stack.at(addr); let is_match = match v.as_inline() { @@ -2495,12 +2482,12 @@ impl Vm { _ => false, }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_eq_unsigned(&mut self, addr: InstAddress, value: u64, out: Output) -> VmResult<()> { + fn op_eq_unsigned(&mut self, addr: Address, value: u64, out: Output) -> Result<(), VmError> { let v = self.stack.at(addr); let is_match = match v.as_inline() { @@ -2508,23 +2495,23 @@ impl Vm { _ => false, }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_eq_signed(&mut self, addr: InstAddress, value: i64, out: Output) -> VmResult<()> { + fn op_eq_signed(&mut self, addr: Address, value: i64, out: Output) -> Result<(), VmError> { let is_match = match self.stack.at(addr).as_inline() { Some(Inline::Signed(actual)) => *actual == value, _ => false, }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_eq_bool(&mut self, addr: InstAddress, value: bool, out: Output) -> VmResult<()> { + fn op_eq_bool(&mut self, addr: Address, value: bool, out: Output) -> Result<(), VmError> { let v = self.stack.at(addr); let is_match = match v.as_inline() { @@ -2532,52 +2519,52 @@ impl Vm { _ => false, }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } /// Test if the top of stack is equal to the string at the given static /// string slot. #[cfg_attr(feature = "bench", inline(never))] - fn op_eq_string(&mut self, addr: InstAddress, slot: usize, out: Output) -> VmResult<()> { + fn op_eq_string(&mut self, addr: Address, slot: usize, out: Output) -> Result<(), VmError> { let v = self.stack.at(addr); let is_match = 'out: { - let Some(actual) = vm_try!(v.try_borrow_ref::()) else { + let Some(actual) = v.try_borrow_ref::()? else { break 'out false; }; let Some(string) = self.unit.lookup_string(slot) else { - return err(VmErrorKind::MissingStaticString { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticString { slot })); }; actual.as_str() == string.as_str() }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } /// Test if the top of stack is equal to the string at the given static /// bytes slot. #[cfg_attr(feature = "bench", inline(never))] - fn op_eq_bytes(&mut self, addr: InstAddress, slot: usize, out: Output) -> VmResult<()> { + fn op_eq_bytes(&mut self, addr: Address, slot: usize, out: Output) -> Result<(), VmError> { let v = self.stack.at(addr); let is_match = 'out: { - let Some(value) = vm_try!(v.try_borrow_ref::()) else { + let Some(value) = v.try_borrow_ref::()? else { break 'out false; }; let Some(bytes) = self.unit.lookup_bytes(slot) else { - return err(VmErrorKind::MissingStaticBytes { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticBytes { slot })); }; value.as_slice() == bytes }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] @@ -2586,29 +2573,29 @@ impl Vm { ty: TypeCheck, len: usize, exact: bool, - addr: InstAddress, + addr: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let value = self.stack.at(addr); - let result = vm_try!(self.on_tuple(ty, value, move |tuple| { + let result = self.on_tuple(ty, value, move |tuple| { if exact { tuple.len() == len } else { tuple.len() >= len } - })); + })?; - vm_try!(out.store(&mut self.stack, result.unwrap_or_default())); - VmResult::Ok(()) + out.store(&mut self.stack, result.unwrap_or_default())?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] - fn op_match_type(&mut self, hash: Hash, addr: InstAddress, out: Output) -> VmResult<()> { + fn op_match_type(&mut self, hash: Hash, addr: Address, out: Output) -> Result<(), VmError> { let value = self.stack.at(addr); let is_match = value.type_hash() == hash; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] @@ -2616,9 +2603,9 @@ impl Vm { &mut self, enum_hash: Hash, variant_hash: Hash, - addr: InstAddress, + addr: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let value = self.stack.at(addr); let is_match = 'out: { @@ -2628,8 +2615,7 @@ impl Vm { } Repr::Any(any) => match enum_hash { Result::::HASH => { - let Some(result) = vm_try!(any.try_borrow_ref::>()) - else { + let Some(result) = any.try_borrow_ref::>()? else { break 'out false; }; @@ -2640,7 +2626,7 @@ impl Vm { }; } Option::::HASH => { - let Some(option) = vm_try!(any.try_borrow_ref::>()) else { + let Some(option) = any.try_borrow_ref::>()? else { break 'out false; }; @@ -2663,27 +2649,27 @@ impl Vm { let value = value.clone(); - match vm_try!(self.try_call_protocol_fn( + match self.try_call_protocol_fn( &Protocol::IS_VARIANT, value, - &mut Some((variant_hash,)) - )) { - CallResultOnly::Ok(value) => vm_try!(bool::from_value(value)), + &mut Some((variant_hash,)), + )? { + CallResultOnly::Ok(value) => bool::from_value(value)?, CallResultOnly::Unsupported(..) => false, } }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_match_builtin( &mut self, type_check: TypeCheck, - addr: InstAddress, + addr: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let value = self.stack.at(addr); let is_match = match value.as_ref() { @@ -2699,8 +2685,8 @@ impl Vm { }, }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] @@ -2708,9 +2694,9 @@ impl Vm { &mut self, slot: usize, exact: bool, - addr: InstAddress, + addr: Address, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { fn test(object: &Object, keys: &[alloc::String], exact: bool) -> bool { if exact { if object.len() != keys.len() { @@ -2731,10 +2717,10 @@ impl Vm { let value = self.stack.at(addr); - let is_match = match vm_try!(value.try_borrow_ref::()) { + let is_match = match value.try_borrow_ref::()? { Some(object) => { let Some(keys) = self.unit.lookup_object_keys(slot) else { - return err(VmErrorKind::MissingStaticObjectKeys { slot }); + return Err(VmError::new(VmErrorKind::MissingStaticObjectKeys { slot })); }; test(&object, keys, exact) @@ -2742,40 +2728,37 @@ impl Vm { None => false, }; - vm_try!(out.store(&mut self.stack, is_match)); - VmResult::Ok(()) + out.store(&mut self.stack, is_match)?; + Ok(()) } /// Push the given variant onto the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_variant(&mut self, addr: InstAddress, variant: InstVariant, out: Output) -> VmResult<()> { + fn op_variant( + &mut self, + addr: Address, + variant: InstVariant, + out: Output, + ) -> Result<(), VmError> { match variant { InstVariant::Some => { let some = self.stack.at(addr).clone(); - vm_try!(out.store(&mut self.stack, || Value::try_from(Some(some)))); + out.store(&mut self.stack, || Value::try_from(Some(some)))?; } InstVariant::None => { - vm_try!(out.store(&mut self.stack, || Value::try_from(None))); - } - InstVariant::Ok => { - let ok = self.stack.at(addr).clone(); - vm_try!(out.store(&mut self.stack, || Value::try_from(Ok(ok)))); - } - InstVariant::Err => { - let err = self.stack.at(addr).clone(); - vm_try!(out.store(&mut self.stack, || Value::try_from(Err(err)))); + out.store(&mut self.stack, || Value::try_from(None))?; } } - VmResult::Ok(()) + Ok(()) } /// Load a function as a value onto the stack. #[cfg_attr(feature = "bench", inline(never))] - fn op_load_fn(&mut self, hash: Hash, out: Output) -> VmResult<()> { - let function = vm_try!(self.lookup_function_by_hash(hash)); - vm_try!(out.store(&mut self.stack, function)); - VmResult::Ok(()) + fn op_load_fn(&mut self, hash: Hash, out: Output) -> Result<(), VmError> { + let function = self.lookup_function_by_hash(hash)?; + out.store(&mut self.stack, function)?; + Ok(()) } /// Construct a closure on the top of the stack. @@ -2783,10 +2766,10 @@ impl Vm { fn op_closure( &mut self, hash: Hash, - addr: InstAddress, + addr: Address, count: usize, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let Some(UnitFn::Offset { offset, call, @@ -2794,22 +2777,22 @@ impl Vm { captures: Some(captures), }) = self.unit.function(&hash) else { - return err(VmErrorKind::MissingFunction { hash }); + return Err(VmError::new(VmErrorKind::MissingFunction { hash })); }; if *captures != count { - return err(VmErrorKind::BadEnvironmentCount { + return Err(VmError::new(VmErrorKind::BadEnvironmentCount { expected: *captures, actual: count, - }); + })); } - let environment = vm_try!(self.stack.slice_at(addr, count)); - let environment = vm_try!(environment + let environment = self.stack.slice_at(addr, count)?; + let environment = environment .iter() .cloned() - .try_collect::>()); - let environment = vm_try!(environment.try_into_boxed_slice()); + .try_collect::>()?; + let environment = environment.try_into_boxed_slice()?; let function = Function::from_vm_closure( self.context.clone(), @@ -2821,20 +2804,26 @@ impl Vm { hash, ); - vm_try!(out.store(&mut self.stack, function)); - VmResult::Ok(()) + out.store(&mut self.stack, function)?; + Ok(()) } /// Implementation of a function call. #[cfg_attr(feature = "bench", inline(never))] - fn op_call(&mut self, hash: Hash, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { + fn op_call( + &mut self, + hash: Hash, + addr: Address, + args: usize, + out: Output, + ) -> Result<(), VmError> { let Some(info) = self.unit.function(&hash) else { let Some(handler) = self.context.function(&hash) else { - return err(VmErrorKind::MissingFunction { hash }); + return Err(VmError::new(VmErrorKind::MissingFunction { hash })); }; - vm_try!(handler(&mut self.stack, addr, args, out)); - return VmResult::Ok(()); + handler.call(&mut self.stack, addr, args, out)?; + return Ok(()); }; match info { @@ -2844,36 +2833,36 @@ impl Vm { args: expected, .. } => { - vm_try!(check_args(args, *expected)); - vm_try!(self.call_offset_fn(*offset, *call, addr, args, Isolated::None, out)); + check_args(args, *expected)?; + self.call_offset_fn(*offset, *call, addr, args, Isolated::None, out)?; } UnitFn::EmptyStruct { hash } => { - vm_try!(check_args(args, 0)); + check_args(args, 0)?; let Some(rtti) = self.unit.lookup_rtti(hash) else { - return err(VmErrorKind::MissingRtti { hash: *hash }); + return Err(VmError::new(VmErrorKind::MissingRtti { hash: *hash })); }; - vm_try!(out.store(&mut self.stack, || Value::empty_struct(rtti.clone()))); + out.store(&mut self.stack, || Value::empty_struct(rtti.clone()))?; } UnitFn::TupleStruct { hash, args: expected, } => { - vm_try!(check_args(args, *expected)); + check_args(args, *expected)?; let Some(rtti) = self.unit.lookup_rtti(hash) else { - return err(VmErrorKind::MissingRtti { hash: *hash }); + return Err(VmError::new(VmErrorKind::MissingRtti { hash: *hash })); }; - let tuple = vm_try!(self.stack.slice_at_mut(addr, args)); + let tuple = self.stack.slice_at_mut(addr, args)?; let data = tuple.iter_mut().map(take); - let value = vm_try!(Dynamic::new(rtti.clone(), data)); - vm_try!(out.store(&mut self.stack, value)); + let value = AnySequence::new(rtti.clone(), data)?; + out.store(&mut self.stack, value)?; } } - VmResult::Ok(()) + Ok(()) } /// Call a function at the given offset with the given number of arguments. @@ -2882,30 +2871,30 @@ impl Vm { &mut self, offset: usize, call: Call, - addr: InstAddress, + addr: Address, args: usize, out: Output, - ) -> VmResult<()> { - vm_try!(self.call_offset_fn(offset, call, addr, args, Isolated::None, out)); - VmResult::Ok(()) + ) -> Result<(), VmError> { + self.call_offset_fn(offset, call, addr, args, Isolated::None, out)?; + Ok(()) } #[cfg_attr(feature = "bench", inline(never))] fn op_call_associated( &mut self, hash: Hash, - addr: InstAddress, + addr: Address, args: usize, out: Output, - ) -> VmResult<()> { + ) -> Result<(), VmError> { let instance = self.stack.at(addr); let type_hash = instance.type_hash(); let hash = Hash::associated_function(type_hash, hash); if let Some(handler) = self.context.function(&hash) { - vm_try!(self.called_function_hook(hash)); - vm_try!(handler(&mut self.stack, addr, args, out)); - return VmResult::Ok(()); + self.called_function_hook(hash)?; + handler.call(&mut self.stack, addr, args, out)?; + return Ok(()); } if let Some(UnitFn::Offset { @@ -2915,76 +2904,76 @@ impl Vm { .. }) = self.unit.function(&hash) { - vm_try!(self.called_function_hook(hash)); - vm_try!(check_args(args, *expected)); - vm_try!(self.call_offset_fn(*offset, *call, addr, args, Isolated::None, out)); - return VmResult::Ok(()); + self.called_function_hook(hash)?; + check_args(args, *expected)?; + self.call_offset_fn(*offset, *call, addr, args, Isolated::None, out)?; + return Ok(()); } - err(VmErrorKind::MissingInstanceFunction { + Err(VmError::new(VmErrorKind::MissingInstanceFunction { instance: instance.type_info(), hash, - }) + })) } #[cfg_attr(feature = "bench", inline(never))] #[tracing::instrument(skip(self))] fn op_call_fn( &mut self, - function: InstAddress, - addr: InstAddress, + function: Address, + addr: Address, args: usize, out: Output, - ) -> VmResult> { + ) -> Result, VmError> { let function = self.stack.at(function); match function.as_ref() { Repr::Inline(Inline::Type(ty)) => { - vm_try!(self.op_call(ty.into_hash(), addr, args, out)); - VmResult::Ok(None) + self.op_call(ty.into_hash(), addr, args, out)?; + Ok(None) } Repr::Any(value) if value.type_hash() == Function::HASH => { let value = value.clone(); - let f = vm_try!(value.borrow_ref::()); + let f = value.borrow_ref::()?; f.call_with_vm(self, addr, args, out) } - value => err(VmErrorKind::UnsupportedCallFn { + value => Err(VmError::new(VmErrorKind::UnsupportedCallFn { actual: value.type_info(), - }), + })), } } #[cfg_attr(feature = "bench", inline(never))] - fn op_iter_next(&mut self, addr: InstAddress, jump: usize, out: Output) -> VmResult<()> { + fn op_iter_next(&mut self, addr: Address, jump: usize, out: Output) -> Result<(), VmError> { let value = self.stack.at(addr); let some = match value.as_ref() { Repr::Any(value) => match value.type_hash() { Option::::HASH => { - let option = vm_try!(value.borrow_ref::>()); + let option = value.borrow_ref::>()?; let Some(some) = &*option else { - self.ip = vm_try!(self.unit.translate(jump)); - return VmResult::Ok(()); + self.ip = self.unit.translate(jump)?; + return Ok(()); }; some.clone() } _ => { - return err(VmErrorKind::UnsupportedIterNextOperand { + return Err(VmError::new(VmErrorKind::UnsupportedIterNextOperand { actual: value.type_info(), - }); + })); } }, actual => { - return err(VmErrorKind::UnsupportedIterNextOperand { + return Err(VmError::new(VmErrorKind::UnsupportedIterNextOperand { actual: actual.type_info(), - }); + })); } }; - vm_try!(out.store(&mut self.stack, some)); - VmResult::Ok(()) + out.store(&mut self.stack, some)?; + Ok(()) } /// Call the provided closure within the context of this virtual machine. @@ -2997,7 +2986,7 @@ impl Vm { /// use rune::runtime::{Formatter, VmError}; /// /// fn use_with(vm: &Vm, output: &Value, f: &mut Formatter) -> Result<(), VmError> { - /// vm.with(|| output.display_fmt(f)).into_result()?; + /// vm.with(|| output.display_fmt(f))?; /// Ok(()) /// } /// ``` @@ -3010,7 +2999,10 @@ impl Vm { } /// Evaluate a single instruction. - pub(crate) fn run(&mut self, diagnostics: Option<&mut dyn VmDiagnostics>) -> VmResult { + pub(crate) fn run( + &mut self, + diagnostics: Option<&mut dyn VmDiagnostics>, + ) -> Result { let mut vm_diagnostics_obj; let diagnostics = match diagnostics { @@ -3029,14 +3021,14 @@ impl Vm { loop { if !budget.take() { - return VmResult::Ok(VmHalt::Limited); + return Ok(VmHalt::Limited); } - let Some((inst, inst_len)) = vm_try!(self.unit.instruction_at(self.ip)) else { - return VmResult::err(VmErrorKind::IpOutOfBounds { + let Some((inst, inst_len)) = self.unit.instruction_at(self.ip)? else { + return Err(VmError::new(VmErrorKind::IpOutOfBounds { ip: self.ip, length: self.unit.instructions().end(), - }); + })); }; tracing::trace!(ip = ?self.ip, ?inst); @@ -3044,295 +3036,295 @@ impl Vm { self.ip = self.ip.wrapping_add(inst_len); self.last_ip_len = inst_len as u8; - match inst { - Inst::Allocate { size } => { - vm_try!(self.op_allocate(size)); + match inst.kind { + inst::Kind::Allocate { size } => { + self.op_allocate(size)?; } - Inst::Not { addr, out } => { - vm_try!(self.op_not(addr, out)); + inst::Kind::Not { addr, out } => { + self.op_not(addr, out)?; } - Inst::Neg { addr, out } => { - vm_try!(self.op_neg(addr, out)); + inst::Kind::Neg { addr, out } => { + self.op_neg(addr, out)?; } - Inst::Closure { + inst::Kind::Closure { hash, addr, count, out, } => { - vm_try!(self.op_closure(hash, addr, count, out)); + self.op_closure(hash, addr, count, out)?; } - Inst::Call { + inst::Kind::Call { hash, addr, args, out, } => { - vm_try!(self.op_call(hash, addr, args, out)); + self.op_call(hash, addr, args, out)?; } - Inst::CallOffset { + inst::Kind::CallOffset { offset, call, addr, args, out, } => { - vm_try!(self.op_call_offset(offset, call, addr, args, out)); + self.op_call_offset(offset, call, addr, args, out)?; } - Inst::CallAssociated { + inst::Kind::CallAssociated { hash, addr, args, out, } => { - vm_try!(self.op_call_associated(hash, addr, args, out)); + self.op_call_associated(hash, addr, args, out)?; } - Inst::CallFn { + inst::Kind::CallFn { function, addr, args, out, } => { - if let Some(reason) = vm_try!(self.op_call_fn(function, addr, args, out)) { - return VmResult::Ok(reason); + if let Some(reason) = self.op_call_fn(function, addr, args, out)? { + return Ok(reason); } } - Inst::LoadInstanceFn { addr, hash, out } => { - vm_try!(self.op_load_instance_fn(addr, hash, out)); + inst::Kind::LoadInstanceFn { addr, hash, out } => { + self.op_load_instance_fn(addr, hash, out)?; } - Inst::IndexGet { target, index, out } => { - vm_try!(self.op_index_get(target, index, out)); + inst::Kind::IndexGet { target, index, out } => { + self.op_index_get(target, index, out)?; } - Inst::TupleIndexSet { + inst::Kind::TupleIndexSet { target, index, value, } => { - vm_try!(self.op_tuple_index_set(target, index, value)); + self.op_tuple_index_set(target, index, value)?; } - Inst::TupleIndexGetAt { addr, index, out } => { - vm_try!(self.op_tuple_index_get_at(addr, index, out)); + inst::Kind::TupleIndexGetAt { addr, index, out } => { + self.op_tuple_index_get_at(addr, index, out)?; } - Inst::ObjectIndexSet { + inst::Kind::ObjectIndexSet { target, slot, value, } => { - vm_try!(self.op_object_index_set(target, slot, value)); + self.op_object_index_set(target, slot, value)?; } - Inst::ObjectIndexGetAt { addr, slot, out } => { - vm_try!(self.op_object_index_get_at(addr, slot, out)); + inst::Kind::ObjectIndexGetAt { addr, slot, out } => { + self.op_object_index_get_at(addr, slot, out)?; } - Inst::IndexSet { + inst::Kind::IndexSet { target, index, value, } => { - vm_try!(self.op_index_set(target, index, value)); + self.op_index_set(target, index, value)?; } - Inst::Return { addr } => { - if let Some(out) = vm_try!(self.op_return(addr)) { - return VmResult::Ok(VmHalt::Exited(out.as_addr())); + inst::Kind::Return { addr } => { + if let Some(out) = self.op_return(addr)? { + return Ok(VmHalt::Exited(out.as_addr())); } } - Inst::ReturnUnit => { - if let Some(out) = vm_try!(self.op_return_unit()) { - return VmResult::Ok(VmHalt::Exited(out.as_addr())); + inst::Kind::ReturnUnit => { + if let Some(out) = self.op_return_unit()? { + return Ok(VmHalt::Exited(out.as_addr())); } } - Inst::Await { addr, out } => { - let future = vm_try!(self.op_await(addr)); - return VmResult::Ok(VmHalt::Awaited(Awaited::Future(future, out))); + inst::Kind::Await { addr, out } => { + let future = self.op_await(addr)?; + return Ok(VmHalt::Awaited(Awaited::Future(future, out))); } - Inst::Select { addr, len, value } => { - if let Some(select) = vm_try!(self.op_select(addr, len, value)) { - return VmResult::Ok(VmHalt::Awaited(Awaited::Select(select, value))); + inst::Kind::Select { addr, len, value } => { + if let Some(select) = self.op_select(addr, len, value)? { + return Ok(VmHalt::Awaited(Awaited::Select(select, value))); } } - Inst::LoadFn { hash, out } => { - vm_try!(self.op_load_fn(hash, out)); + inst::Kind::LoadFn { hash, out } => { + self.op_load_fn(hash, out)?; } - Inst::Store { value, out } => { - vm_try!(self.op_store(value, out)); + inst::Kind::Store { value, out } => { + self.op_store(value, out)?; } - Inst::Copy { addr, out } => { - vm_try!(self.op_copy(addr, out)); + inst::Kind::Copy { addr, out } => { + self.op_copy(addr, out)?; } - Inst::Move { addr, out } => { - vm_try!(self.op_move(addr, out)); + inst::Kind::Move { addr, out } => { + self.op_move(addr, out)?; } - Inst::Drop { set } => { - vm_try!(self.op_drop(set)); + inst::Kind::Drop { set } => { + self.op_drop(set)?; } - Inst::Swap { a, b } => { - vm_try!(self.op_swap(a, b)); + inst::Kind::Swap { a, b } => { + self.op_swap(a, b)?; } - Inst::Jump { jump } => { - vm_try!(self.op_jump(jump)); + inst::Kind::Jump { jump } => { + self.op_jump(jump)?; } - Inst::JumpIf { cond, jump } => { - vm_try!(self.op_jump_if(cond, jump)); + inst::Kind::JumpIf { cond, jump } => { + self.op_jump_if(cond, jump)?; } - Inst::JumpIfNot { cond, jump } => { - vm_try!(self.op_jump_if_not(cond, jump)); + inst::Kind::JumpIfNot { cond, jump } => { + self.op_jump_if_not(cond, jump)?; } - Inst::Vec { addr, count, out } => { - vm_try!(self.op_vec(addr, count, out)); + inst::Kind::Vec { addr, count, out } => { + self.op_vec(addr, count, out)?; } - Inst::Tuple { addr, count, out } => { - vm_try!(self.op_tuple(addr, count, out)); + inst::Kind::Tuple { addr, count, out } => { + self.op_tuple(addr, count, out)?; } - Inst::Tuple1 { addr, out } => { - vm_try!(self.op_tuple_n(&addr[..], out)); + inst::Kind::Tuple1 { addr, out } => { + self.op_tuple_n(&addr[..], out)?; } - Inst::Tuple2 { addr, out } => { - vm_try!(self.op_tuple_n(&addr[..], out)); + inst::Kind::Tuple2 { addr, out } => { + self.op_tuple_n(&addr[..], out)?; } - Inst::Tuple3 { addr, out } => { - vm_try!(self.op_tuple_n(&addr[..], out)); + inst::Kind::Tuple3 { addr, out } => { + self.op_tuple_n(&addr[..], out)?; } - Inst::Tuple4 { addr, out } => { - vm_try!(self.op_tuple_n(&addr[..], out)); + inst::Kind::Tuple4 { addr, out } => { + self.op_tuple_n(&addr[..], out)?; } - Inst::Environment { addr, count, out } => { - vm_try!(self.op_environment(addr, count, out)); + inst::Kind::Environment { addr, count, out } => { + self.op_environment(addr, count, out)?; } - Inst::Object { addr, slot, out } => { - vm_try!(self.op_object(addr, slot, out)); + inst::Kind::Object { addr, slot, out } => { + self.op_object(addr, slot, out)?; } - Inst::Range { range, out } => { - vm_try!(self.op_range(range, out)); + inst::Kind::Range { range, out } => { + self.op_range(range, out)?; } - Inst::Struct { addr, hash, out } => { - vm_try!(self.op_struct(addr, hash, out)); + inst::Kind::Struct { addr, hash, out } => { + self.op_struct(addr, hash, out)?; } - Inst::ConstConstruct { + inst::Kind::ConstConstruct { addr, hash, count, out, } => { - vm_try!(self.op_const_construct(addr, hash, count, out)); + self.op_const_construct(addr, hash, count, out)?; } - Inst::String { slot, out } => { - vm_try!(self.op_string(slot, out)); + inst::Kind::String { slot, out } => { + self.op_string(slot, out)?; } - Inst::Bytes { slot, out } => { - vm_try!(self.op_bytes(slot, out)); + inst::Kind::Bytes { slot, out } => { + self.op_bytes(slot, out)?; } - Inst::StringConcat { + inst::Kind::StringConcat { addr, len, size_hint, out, } => { - vm_try!(self.op_string_concat(addr, len, size_hint, out)); + self.op_string_concat(addr, len, size_hint, out)?; } - Inst::Format { addr, spec, out } => { - vm_try!(self.op_format(addr, spec, out)); + inst::Kind::Format { addr, spec, out } => { + self.op_format(addr, spec, out)?; } - Inst::IsUnit { addr, out } => { - vm_try!(self.op_is_unit(addr, out)); + inst::Kind::IsUnit { addr, out } => { + self.op_is_unit(addr, out)?; } - Inst::Try { addr, out } => { - if let Some(out) = vm_try!(self.op_try(addr, out)) { - return VmResult::Ok(VmHalt::Exited(out.as_addr())); + inst::Kind::Try { addr, out } => { + if let Some(out) = self.op_try(addr, out)? { + return Ok(VmHalt::Exited(out.as_addr())); } } - Inst::EqChar { addr, value, out } => { - vm_try!(self.op_eq_character(addr, value, out)); + inst::Kind::EqChar { addr, value, out } => { + self.op_eq_character(addr, value, out)?; } - Inst::EqUnsigned { addr, value, out } => { - vm_try!(self.op_eq_unsigned(addr, value, out)); + inst::Kind::EqUnsigned { addr, value, out } => { + self.op_eq_unsigned(addr, value, out)?; } - Inst::EqSigned { addr, value, out } => { - vm_try!(self.op_eq_signed(addr, value, out)); + inst::Kind::EqSigned { addr, value, out } => { + self.op_eq_signed(addr, value, out)?; } - Inst::EqBool { + inst::Kind::EqBool { addr, value: boolean, out, } => { - vm_try!(self.op_eq_bool(addr, boolean, out)); + self.op_eq_bool(addr, boolean, out)?; } - Inst::EqString { addr, slot, out } => { - vm_try!(self.op_eq_string(addr, slot, out)); + inst::Kind::EqString { addr, slot, out } => { + self.op_eq_string(addr, slot, out)?; } - Inst::EqBytes { addr, slot, out } => { - vm_try!(self.op_eq_bytes(addr, slot, out)); + inst::Kind::EqBytes { addr, slot, out } => { + self.op_eq_bytes(addr, slot, out)?; } - Inst::MatchSequence { + inst::Kind::MatchSequence { type_check, len, exact, addr, out, } => { - vm_try!(self.op_match_sequence(type_check, len, exact, addr, out)); + self.op_match_sequence(type_check, len, exact, addr, out)?; } - Inst::MatchType { hash, addr, out } => { - vm_try!(self.op_match_type(hash, addr, out)); + inst::Kind::MatchType { hash, addr, out } => { + self.op_match_type(hash, addr, out)?; } - Inst::MatchVariant { + inst::Kind::MatchVariant { enum_hash, variant_hash, addr, out, } => { - vm_try!(self.op_match_variant(enum_hash, variant_hash, addr, out)); + self.op_match_variant(enum_hash, variant_hash, addr, out)?; } - Inst::MatchBuiltIn { + inst::Kind::MatchBuiltIn { type_check, addr, out, } => { - vm_try!(self.op_match_builtin(type_check, addr, out)); + self.op_match_builtin(type_check, addr, out)?; } - Inst::MatchObject { + inst::Kind::MatchObject { slot, exact, addr, out, } => { - vm_try!(self.op_match_object(slot, exact, addr, out)); + self.op_match_object(slot, exact, addr, out)?; } - Inst::Yield { addr, out } => { - return VmResult::Ok(VmHalt::Yielded(Some(addr), out)); + inst::Kind::Yield { addr, out } => { + return Ok(VmHalt::Yielded(Some(addr), out)); } - Inst::YieldUnit { out } => { - return VmResult::Ok(VmHalt::Yielded(None, out)); + inst::Kind::YieldUnit { out } => { + return Ok(VmHalt::Yielded(None, out)); } - Inst::Variant { addr, variant, out } => { - vm_try!(self.op_variant(addr, variant, out)); + inst::Kind::Variant { addr, variant, out } => { + self.op_variant(addr, variant, out)?; } - Inst::Op { op, a, b, out } => { - vm_try!(self.op_op(op, a, b, out)); + inst::Kind::Op { op, a, b, out } => { + self.op_op(op, a, b, out)?; } - Inst::Arithmetic { op, a, b, out } => { - vm_try!(self.op_arithmetic(op, a, b, out)); + inst::Kind::Arithmetic { op, a, b, out } => { + self.op_arithmetic(op, a, b, out)?; } - Inst::Bitwise { op, a, b, out } => { - vm_try!(self.op_bitwise(op, a, b, out)); + inst::Kind::Bitwise { op, a, b, out } => { + self.op_bitwise(op, a, b, out)?; } - Inst::Shift { op, a, b, out } => { - vm_try!(self.op_shift(op, a, b, out)); + inst::Kind::Shift { op, a, b, out } => { + self.op_shift(op, a, b, out)?; } - Inst::AssignArithmetic { op, target, rhs } => { - vm_try!(self.op_assign_arithmetic(op, target, rhs)); + inst::Kind::AssignArithmetic { op, target, rhs } => { + self.op_assign_arithmetic(op, target, rhs)?; } - Inst::AssignBitwise { op, target, rhs } => { - vm_try!(self.op_assign_bitwise(op, target, rhs)); + inst::Kind::AssignBitwise { op, target, rhs } => { + self.op_assign_bitwise(op, target, rhs)?; } - Inst::AssignShift { op, target, rhs } => { - vm_try!(self.op_assign_shift(op, target, rhs)); + inst::Kind::AssignShift { op, target, rhs } => { + self.op_assign_shift(op, target, rhs)?; } - Inst::IterNext { addr, jump, out } => { - vm_try!(self.op_iter_next(addr, jump, out)); + inst::Kind::IterNext { addr, jump, out } => { + self.op_iter_next(addr, jump, out)?; } - Inst::Panic { reason } => { - return err(VmErrorKind::Panic { + inst::Kind::Panic { reason } => { + return Err(VmError::new(VmErrorKind::Panic { reason: Panic::from(reason), - }); + })); } } } @@ -3436,7 +3428,7 @@ fn target_value<'a>( stack: &'a mut Stack, unit: &Unit, target: InstTarget, - rhs: InstAddress, + rhs: Address, ) -> Result, VmErrorKind> { match target { InstTarget::Address(addr) => match stack.pair(addr, rhs)? { diff --git a/crates/rune/src/runtime/vm_call.rs b/crates/rune/src/runtime/vm_call.rs index 6ae655120..74c65b40a 100644 --- a/crates/rune/src/runtime/vm_call.rs +++ b/crates/rune/src/runtime/vm_call.rs @@ -1,10 +1,10 @@ -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate::alloc::prelude::*; use crate::runtime::vm_execution::VmExecutionState; use crate::runtime::{ - Call, Future, Generator, Output, RuntimeContext, Stack, Stream, Unit, Value, Vm, VmErrorKind, - VmExecution, VmResult, + Call, Future, Generator, Output, RuntimeContext, Stack, Stream, Unit, Value, Vm, VmError, + VmErrorKind, VmExecution, }; /// An instruction to push a virtual machine to the execution. @@ -38,53 +38,53 @@ impl VmCall { /// Encode the push itno an execution. #[tracing::instrument(skip_all)] - pub(crate) fn into_execution(self, execution: &mut VmExecution) -> VmResult<()> + pub(crate) fn into_execution(self, execution: &mut VmExecution) -> Result<(), VmError> where - T: AsRef + AsMut, + T: AsMut, { let out = self.out; let value = match self.call { Call::Async => { - let vm = vm_try!(self.build_vm(execution)); + let vm = self.build_vm(execution)?; let mut execution = vm.into_execution(); - vm_try!(Value::try_from(vm_try!(Future::new(async move { - execution.async_complete().await - })))) + Value::try_from(Future::new(async move { + execution.resume().await?.into_complete() + })?)? } Call::Immediate => { - vm_try!(execution.push_state(VmExecutionState { + execution.push_state(VmExecutionState { context: self.context, unit: self.unit, - })); + })?; - return VmResult::Ok(()); + return Ok(()); } Call::Stream => { - let vm = vm_try!(self.build_vm(execution)); - vm_try!(Value::try_from(Stream::new(vm))) + let vm = self.build_vm(execution)?; + Value::try_from(Stream::new(vm))? } Call::Generator => { - let vm = vm_try!(self.build_vm(execution)); - vm_try!(Value::try_from(Generator::new(vm))) + let vm = self.build_vm(execution)?; + Value::try_from(Generator::new(vm))? } }; - vm_try!(out.store(execution.vm_mut().stack_mut(), value)); - VmResult::Ok(()) + out.store(execution.vm_mut().stack_mut(), value)?; + Ok(()) } #[tracing::instrument(skip_all)] - fn build_vm(self, execution: &mut VmExecution) -> VmResult + fn build_vm(self, execution: &mut VmExecution) -> Result where - T: AsRef + AsMut, + T: AsMut, { let vm = execution.vm_mut(); - let new_stack = vm_try!(vm.stack_mut().drain().try_collect::()); + let new_stack = vm.stack_mut().drain().try_collect::()?; let Some(ip) = vm.pop_call_frame_from_call() else { - return VmResult::err(VmErrorKind::MissingCallFrame); + return Err(VmError::new(VmErrorKind::MissingCallFrame)); }; let context = self.context.unwrap_or_else(|| vm.context().clone()); @@ -92,6 +92,6 @@ impl VmCall { let mut vm = Vm::with_stack(context, unit, new_stack); vm.set_ip(ip); - VmResult::Ok(vm) + Ok(vm) } } diff --git a/crates/rune/src/runtime/vm_diagnostics.rs b/crates/rune/src/runtime/vm_diagnostics.rs index 404a0fb6f..418960d6e 100644 --- a/crates/rune/src/runtime/vm_diagnostics.rs +++ b/crates/rune/src/runtime/vm_diagnostics.rs @@ -1,23 +1,29 @@ use core::ptr::NonNull; use crate::hash::Hash; -use crate::runtime::VmResult; +use crate::runtime::VmError; use crate::Diagnostics; +/// A trait for runtime diagnostics in the virtual machine. pub trait VmDiagnostics { - fn function_used(&mut self, hash: Hash, at: usize) -> VmResult<()>; + /// Mark that a function has been used. + fn function_used(&mut self, hash: Hash, at: usize) -> Result<(), VmError>; + /// Returns the vtable for this diagnostics object. + #[doc(hidden)] fn vtable(&self) -> &'static VmDiagnosticsObjVtable; } impl VmDiagnostics for Diagnostics { - fn function_used(&mut self, hash: Hash, at: usize) -> VmResult<()> { - vm_try!(self.runtime_used_deprecated(at, hash)); - VmResult::Ok(()) + #[inline] + fn function_used(&mut self, hash: Hash, at: usize) -> Result<(), VmError> { + self.runtime_used_deprecated(at, hash)?; + Ok(()) } + #[inline] fn vtable(&self) -> &'static VmDiagnosticsObjVtable { - fn function_used_impl(ptr: NonNull<()>, hash: Hash, at: usize) -> VmResult<()> + fn function_used_impl(ptr: NonNull<()>, hash: Hash, at: usize) -> Result<(), VmError> where T: VmDiagnostics, { @@ -32,7 +38,7 @@ impl VmDiagnostics for Diagnostics { #[derive(Debug)] pub struct VmDiagnosticsObjVtable { - function_used: unsafe fn(NonNull<()>, hash: Hash, at: usize) -> VmResult<()>, + function_used: unsafe fn(NonNull<()>, hash: Hash, at: usize) -> Result<(), VmError>, } #[repr(C)] @@ -43,6 +49,7 @@ pub(crate) struct VmDiagnosticsObj { } impl VmDiagnosticsObj { + #[inline] pub(crate) fn new(trait_obj: &mut dyn VmDiagnostics) -> Self { let vtable = trait_obj.vtable(); @@ -52,7 +59,8 @@ impl VmDiagnosticsObj { } } - pub(crate) fn function_used(&mut self, hash: Hash, at: usize) -> VmResult<()> { + #[inline] + pub(crate) fn function_used(&mut self, hash: Hash, at: usize) -> Result<(), VmError> { unsafe { (self.vtable.function_used)(self.ptr, hash, at) } } } diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index 68ae35cea..f15dd4c51 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -1,22 +1,22 @@ use core::convert::Infallible; use core::fmt; -use ::rust_alloc::boxed::Box; -use ::rust_alloc::sync::Arc; +use rust_alloc::boxed::Box; +use rust_alloc::sync::Arc; use crate::alloc::error::CustomError; -use crate::alloc::prelude::*; use crate::alloc::{self, String}; -use crate::compile::meta; use crate::runtime::unit::{BadInstruction, BadJump}; -use crate::{Any, Hash, ItemBuf}; +use crate::{vm_error, Any, Hash, ItemBuf}; use super::{ - AccessError, AccessErrorKind, AnyObjError, AnyObjErrorKind, AnyTypeInfo, BoxedPanic, CallFrame, - DynArgsUsed, DynamicTakeError, ExecutionState, MaybeTypeOf, Panic, Protocol, SliceError, - StackError, StaticString, TypeInfo, TypeOf, Unit, Vm, VmHaltInfo, + AccessError, AccessErrorKind, AnyObjError, AnyObjErrorKind, AnySequenceTakeError, BoxedPanic, + CallFrame, DynArgsUsed, ExecutionState, Panic, Protocol, SliceError, StackError, StaticString, + TypeInfo, TypeOf, Unit, Vm, VmHaltInfo, }; +vm_error!(VmError); + /// A virtual machine error which includes tracing information. pub struct VmError { pub(crate) inner: Box, @@ -34,8 +34,8 @@ impl VmError { index: 0, kind: VmErrorKind::from(error), }, - chain: ::rust_alloc::vec::Vec::new(), - stacktrace: ::rust_alloc::vec::Vec::new(), + chain: rust_alloc::vec::Vec::new(), + stacktrace: rust_alloc::vec::Vec::new(), }), } } @@ -80,6 +80,40 @@ impl VmError { pub(crate) fn into_kind(self) -> VmErrorKind { self.inner.error.kind } + + /// Apply the given frame to the current result. + pub(crate) fn with_vm(result: Result, vm: &Vm) -> Result { + match result { + Ok(ok) => Ok(ok), + Err(mut err) => { + err.inner.stacktrace.push(VmErrorLocation { + unit: vm.unit().clone(), + ip: vm.last_ip(), + frames: vm.call_frames().to_vec(), + }); + + Err(err) + } + } + } + + /// Add auxilliary errors if appropriate. + #[inline] + pub(crate) fn with_error(mut self, error: E) -> Self + where + VmErrorKind: From, + { + #[cfg(feature = "emit")] + let index = self.inner.stacktrace.len(); + + self.inner.chain.push(VmErrorAt { + #[cfg(feature = "emit")] + index, + kind: VmErrorKind::from(error), + }); + + self + } } impl fmt::Display for VmError { @@ -101,61 +135,6 @@ impl fmt::Debug for VmError { impl core::error::Error for VmError {} -pub mod sealed { - use crate::runtime::VmResult; - pub trait Sealed {} - impl Sealed for VmResult {} - impl Sealed for Result {} -} - -/// Trait used to convert result types to [`VmResult`]. -#[doc(hidden)] -pub trait TryFromResult: self::sealed::Sealed { - /// The ok type produced by the conversion. - type Ok; - - /// The conversion method itself. - fn try_from_result(value: Self) -> VmResult; -} - -/// Helper to coerce one result type into [`VmResult`]. -/// -/// Despite being public, this is actually private API (`#[doc(hidden)]`). Use -/// at your own risk. -#[doc(hidden)] -#[inline(always)] -#[allow(clippy::unit_arg)] -pub fn try_result(result: T) -> VmResult -where - T: TryFromResult, -{ - T::try_from_result(result) -} - -impl TryFromResult for VmResult { - type Ok = T; - - #[inline] - fn try_from_result(value: Self) -> VmResult { - value - } -} - -impl TryFromResult for Result -where - VmError: From, -{ - type Ok = T; - - #[inline] - fn try_from_result(value: Self) -> VmResult { - match value { - Ok(ok) => VmResult::Ok(ok), - Err(err) => VmResult::Err(VmError::from(err)), - } - } -} - /// A single unit producing errors. #[derive(Debug)] #[non_exhaustive] @@ -165,7 +144,7 @@ pub struct VmErrorLocation { /// Frozen instruction pointer. pub ip: usize, /// All lower call frames before the unwind trigger point - pub frames: ::rust_alloc::vec::Vec, + pub frames: rust_alloc::vec::Vec, } #[derive(Debug)] @@ -201,145 +180,13 @@ impl fmt::Display for VmErrorAt { #[non_exhaustive] pub(crate) struct VmErrorInner { pub(crate) error: VmErrorAt, - pub(crate) chain: ::rust_alloc::vec::Vec, - pub(crate) stacktrace: ::rust_alloc::vec::Vec, + pub(crate) chain: rust_alloc::vec::Vec, + pub(crate) stacktrace: rust_alloc::vec::Vec, } /// A result produced by the virtual machine. -#[must_use] -pub enum VmResult { - /// A produced value. - Ok(T), - /// Multiple errors with locations included. - Err(VmError), -} - -impl VmResult { - /// Construct a result containing a panic. - #[inline] - pub fn panic(message: D) -> Self - where - D: 'static + BoxedPanic, - { - Self::err(Panic::custom(message)) - } - - /// Construct an expectation error. The actual type received is `actual`, - /// but we expected `E`. - #[inline] - pub fn expected(actual: TypeInfo) -> Self - where - E: ?Sized + TypeOf, - { - Self::Err(VmError::expected::(actual)) - } - - /// Test if the result is an ok. - #[inline] - pub fn is_ok(&self) -> bool { - matches!(self, Self::Ok(..)) - } - - /// Test if the result is an error. - #[inline] - pub fn is_err(&self) -> bool { - matches!(self, Self::Err(..)) - } - - /// Expect a value or panic. - #[inline] - #[track_caller] - pub fn expect(self, msg: &str) -> T { - self.into_result().expect(msg) - } - - /// Unwrap the interior value. - #[inline] - #[track_caller] - pub fn unwrap(self) -> T { - self.into_result().unwrap() - } - - /// Convert a [`VmResult`] into a [`Result`]. - #[inline] - pub fn into_result(self) -> Result { - match self { - Self::Ok(value) => Ok(value), - Self::Err(error) => Err(error), - } - } - - /// Construct a new error from a type that can be converted into a - /// [`VmError`]. - pub fn err(error: E) -> Self - where - VmError: From, - { - Self::Err(VmError::from(error)) - } - - /// Apply the given frame to the current result. - pub(crate) fn with_vm(self, vm: &Vm) -> Self { - match self { - Self::Ok(ok) => Self::Ok(ok), - Self::Err(mut err) => { - err.inner.stacktrace.push(VmErrorLocation { - unit: vm.unit().clone(), - ip: vm.last_ip(), - frames: vm.call_frames().to_vec(), - }); - - Self::Err(err) - } - } - } - - /// Add auxilliary errors if appropriate. - #[inline] - pub(crate) fn with_error(self, error: E) -> Self - where - E: FnOnce() -> O, - VmErrorKind: From, - { - match self { - Self::Ok(ok) => Self::Ok(ok), - Self::Err(mut err) => { - #[cfg(feature = "emit")] - let index = err.inner.stacktrace.len(); - - err.inner.chain.push(VmErrorAt { - #[cfg(feature = "emit")] - index, - kind: VmErrorKind::from(error()), - }); - - Self::Err(err) - } - } - } -} - -impl MaybeTypeOf for VmResult -where - T: MaybeTypeOf, -{ - #[inline] - fn maybe_type_of() -> alloc::Result { - T::maybe_type_of() - } -} - -cfg_std! { - impl ::std::process::Termination for VmResult { - #[inline] - fn report(self) -> ::std::process::ExitCode { - match self { - VmResult::Ok(_) => ::std::process::ExitCode::SUCCESS, - VmResult::Err(_) => ::std::process::ExitCode::FAILURE, - } - } - } -} +#[deprecated = "Use `Result` directly instead."] +pub type VmResult = Result; impl From for VmError where @@ -367,14 +214,11 @@ impl From<[VmErrorKind; N]> for VmError { fn from(kinds: [VmErrorKind; N]) -> Self { let mut it = kinds.into_iter(); - let first = match it.next() { - None => VmErrorKind::Panic { - reason: Panic::custom("Unknown error"), - }, - Some(first) => first, + let Some(first) = it.next() else { + return VmError::panic("Cannot construct an empty collection of errors"); }; - let mut chain = ::rust_alloc::vec::Vec::with_capacity(it.len()); + let mut chain = rust_alloc::vec::Vec::with_capacity(it.len()); for kind in it { chain.push(VmErrorAt { @@ -392,7 +236,7 @@ impl From<[VmErrorKind; N]> for VmError { kind: first, }, chain, - stacktrace: ::rust_alloc::vec::Vec::new(), + stacktrace: rust_alloc::vec::Vec::new(), }), } } @@ -405,6 +249,8 @@ impl From for VmErrorKind { } } +vm_error!(RuntimeError); + /// An opaque simple runtime error. #[cfg_attr(test, derive(PartialEq))] pub struct RuntimeError { @@ -478,58 +324,6 @@ impl RuntimeError { } } -#[allow(non_snake_case)] -impl RuntimeError { - #[doc(hidden)] - #[inline] - pub fn __rune_macros__missing_struct_field(target: &'static str, name: &'static str) -> Self { - Self::new(VmErrorKind::MissingStructField { target, name }) - } - - #[doc(hidden)] - #[inline] - pub fn __rune_macros__missing_variant(name: &str) -> alloc::Result { - Ok(Self::new(VmErrorKind::MissingVariant { - name: name.try_to_owned()?, - })) - } - - #[doc(hidden)] - #[inline] - pub fn __rune_macros__expected_variant(actual: TypeInfo) -> Self { - Self::new(VmErrorKind::ExpectedVariant { actual }) - } - - #[doc(hidden)] - #[inline] - pub fn __rune_macros__missing_variant_name() -> Self { - Self::new(VmErrorKind::MissingVariantName) - } - - #[doc(hidden)] - #[inline] - pub fn __rune_macros__missing_tuple_index(target: &'static str, index: usize) -> Self { - Self::new(VmErrorKind::MissingTupleIndex { target, index }) - } - - #[doc(hidden)] - #[inline] - pub fn __rune_macros__unsupported_object_field_get(target: AnyTypeInfo) -> Self { - Self::new(VmErrorKind::UnsupportedObjectFieldGet { - target: TypeInfo::from(target), - }) - } - - #[doc(hidden)] - #[inline] - pub fn __rune_macros__unsupported_tuple_index_get(target: AnyTypeInfo, index: usize) -> Self { - Self::new(VmErrorKind::UnsupportedTupleIndexGet { - target: TypeInfo::from(target), - index, - }) - } -} - impl fmt::Debug for RuntimeError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -544,12 +338,12 @@ impl From for RuntimeError { } } -impl From for RuntimeError { +impl From for RuntimeError { #[inline] - fn from(value: DynamicTakeError) -> Self { + fn from(value: AnySequenceTakeError) -> Self { match value { - DynamicTakeError::Access(error) => Self::from(error), - DynamicTakeError::Alloc(error) => Self::from(error), + AnySequenceTakeError::Access(error) => Self::from(error), + AnySequenceTakeError::Alloc(error) => Self::from(error), } } } @@ -576,13 +370,16 @@ impl From for RuntimeError { } impl From for RuntimeError { + #[inline] fn from(value: AnyObjError) -> Self { match value.into_kind() { + AnyObjErrorKind::Alloc(error) => Self::from(error), AnyObjErrorKind::Cast(expected, actual) => Self::new(VmErrorKind::Expected { expected: TypeInfo::any_type_info(expected), actual, }), AnyObjErrorKind::AccessError(error) => Self::from(error), + AnyObjErrorKind::NotOwned(type_info) => Self::new(VmErrorKind::NotOwned { type_info }), } } } @@ -679,6 +476,9 @@ pub(crate) enum VmErrorKind { MissingContextFunction { hash: Hash, }, + NotOwned { + type_info: TypeInfo, + }, MissingProtocolFunction { protocol: &'static Protocol, instance: TypeInfo, @@ -771,7 +571,6 @@ pub(crate) enum VmErrorKind { target: TypeInfo, index: VmIntegerRepr, }, - #[cfg(feature = "alloc")] MissingIndexKey { target: TypeInfo, }, @@ -830,13 +629,14 @@ pub(crate) enum VmErrorKind { actual: usize, expected: usize, }, + ExpectedVecLength { + actual: usize, + expected: usize, + }, ConstNotSupported { actual: TypeInfo, }, MissingInterfaceEnvironment, - ExpectedExecutionState { - actual: ExecutionState, - }, ExpectedExitedExecutionState { actual: ExecutionState, }, @@ -869,7 +669,6 @@ pub(crate) enum VmErrorKind { lhs: f64, rhs: f64, }, - #[cfg(feature = "alloc")] IllegalFloatOperation { value: f64, }, @@ -905,6 +704,9 @@ impl fmt::Display for VmErrorKind { VmErrorKind::MissingContextFunction { hash } => { write!(f, "Missing context function with hash `{hash}`") } + VmErrorKind::NotOwned { type_info } => { + write!(f, "Cannot use owned operations for {type_info}") + } VmErrorKind::MissingProtocolFunction { protocol, instance } => { write!(f, "Missing protocol function `{protocol}` for `{instance}`") } @@ -992,7 +794,6 @@ impl fmt::Display for VmErrorKind { VmErrorKind::MissingIndexInteger { target, index } => { write!(f, "Type `{target}` missing integer index `{index}`") } - #[cfg(feature = "alloc")] VmErrorKind::MissingIndexKey { target } => { write!(f, "Type `{target}` missing index") } @@ -1046,15 +847,16 @@ impl fmt::Display for VmErrorKind { f, "Expected a tuple of length `{expected}`, but found one with length `{actual}`", ), + VmErrorKind::ExpectedVecLength { actual, expected } => write!( + f, + "Expected a vector of length `{expected}`, but found one with length `{actual}`", + ), VmErrorKind::ConstNotSupported { actual } => { write!(f, "Type `{actual}` can't be converted to a constant value") } VmErrorKind::MissingInterfaceEnvironment => { write!(f, "Missing interface environment") } - VmErrorKind::ExpectedExecutionState { actual } => { - write!(f, "Expected resume execution state, but was {actual}") - } VmErrorKind::ExpectedExitedExecutionState { actual } => { write!(f, "Expected exited execution state, but was {actual}") } @@ -1090,7 +892,6 @@ impl fmt::Display for VmErrorKind { "Cannot perform a comparison of the floats {lhs} and {rhs}", ) } - #[cfg(feature = "alloc")] VmErrorKind::IllegalFloatOperation { value } => { write!(f, "Cannot perform operation on float `{value}`") } @@ -1111,12 +912,12 @@ impl From for VmErrorKind { } } -impl From for VmErrorKind { +impl From for VmErrorKind { #[inline] - fn from(value: DynamicTakeError) -> Self { + fn from(value: AnySequenceTakeError) -> Self { match value { - DynamicTakeError::Access(error) => Self::from(error), - DynamicTakeError::Alloc(error) => Self::from(error), + AnySequenceTakeError::Access(error) => Self::from(error), + AnySequenceTakeError::Alloc(error) => Self::from(error), } } } diff --git a/crates/rune/src/runtime/vm_execution.rs b/crates/rune/src/runtime/vm_execution.rs index 67c68b731..8c3638f48 100644 --- a/crates/rune/src/runtime/vm_execution.rs +++ b/crates/rune/src/runtime/vm_execution.rs @@ -1,18 +1,32 @@ use core::fmt; use core::future::Future; use core::mem::{replace, take}; +use core::pin::{pin, Pin}; +use core::task::{ready, Context, Poll, RawWaker, RawWakerVTable, Waker}; -use ::rust_alloc::sync::Arc; +use rust_alloc::sync::Arc; use crate::alloc::prelude::*; -use crate::runtime::budget; -use crate::runtime::{ - Generator, GeneratorState, InstAddress, Output, RuntimeContext, Stream, Unit, Value, Vm, - VmErrorKind, VmHalt, VmHaltInfo, VmResult, -}; +use crate::async_vm_try; +use crate::runtime::budget::Budget; +use crate::runtime::{budget, Awaited}; use crate::shared::AssertSend; -use super::VmDiagnostics; +use super::{ + Address, GeneratorState, Output, RuntimeContext, Unit, Value, Vm, VmDiagnostics, VmError, + VmErrorKind, VmHalt, VmHaltInfo, +}; + +static COMPLETE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| RawWaker::new(&(), &COMPLETE_WAKER_VTABLE), + |_| {}, + |_| {}, + |_| {}, +); + +// SAFETY: This waker does nothing. +static COMPLETE_WAKER: Waker = + unsafe { Waker::from_raw(RawWaker::new(&(), &COMPLETE_WAKER_VTABLE)) }; /// The state of an execution. We keep track of this because it's important to /// correctly interact with functions that yield (like generators and streams) @@ -28,7 +42,7 @@ pub(crate) enum ExecutionState { /// Suspended execution. Suspended, /// Execution exited. - Exited(Option), + Exited(Option
), } impl fmt::Display for ExecutionState { @@ -53,36 +67,46 @@ pub(crate) struct VmExecutionState { /// /// When an execution is dropped, the stack of the stack of the head machine /// will be cleared. -pub struct VmExecution -where - T: AsRef + AsMut, -{ +pub struct VmExecution { /// The current head vm which holds the execution. - head: T, + vm: T, /// The state of an execution. state: ExecutionState, /// Indicates the current stack of suspended contexts. states: Vec, } -impl VmExecution -where - T: AsRef + AsMut, -{ +impl VmExecution { + /// Get a reference to the current virtual machine. + pub fn vm(&self) -> &Vm + where + T: AsRef, + { + self.vm.as_ref() + } + + /// Get a mutable reference the current virtual machine. + pub fn vm_mut(&mut self) -> &mut Vm + where + T: AsMut, + { + self.vm.as_mut() + } + /// Construct an execution from a virtual machine. - pub(crate) fn new(head: T) -> Self { + pub(crate) fn new(vm: T) -> Self { Self { - head, + vm, state: ExecutionState::Initial, states: Vec::new(), } } +} - /// Test if the current execution state is resumed. - pub(crate) fn is_resumed(&self) -> bool { - matches!(self.state, ExecutionState::Resumed(..)) - } - +impl VmExecution +where + T: AsMut, +{ /// Coerce the current execution into a generator if appropriate. /// /// ``` @@ -105,15 +129,17 @@ where /// /// let mut n = 1i64; /// - /// while let Some(value) = generator.next().into_result()? { + /// while let Some(value) = generator.next()? { /// let value: i64 = rune::from_value(value)?; /// assert_eq!(value, n); /// n += 1; /// } /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn into_generator(self) -> Generator { - Generator::from_execution(self) + pub fn into_generator(self) -> VmGenerator { + VmGenerator { + execution: Some(self), + } } /// Coerce the current execution into a stream if appropriate. @@ -139,7 +165,7 @@ where /// /// let mut n = 1i64; /// - /// while let Some(value) = stream.next().await.into_result()? { + /// while let Some(value) = stream.next().await? { /// let value: i64 = rune::from_value(value)?; /// assert_eq!(value, n); /// n += 1; @@ -148,332 +174,102 @@ where /// # })?; /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn into_stream(self) -> Stream { - Stream::from_execution(self) - } - - /// Get a reference to the current virtual machine. - pub fn vm(&self) -> &Vm { - self.head.as_ref() - } - - /// Get a mutable reference the current virtual machine. - pub fn vm_mut(&mut self) -> &mut Vm { - self.head.as_mut() - } - - /// Complete the current execution without support for async instructions. - /// - /// This will error if the execution is suspended through yielding. - pub async fn async_complete(&mut self) -> VmResult { - match vm_try!(self.async_resume().await) { - GeneratorState::Complete(value) => VmResult::Ok(value), - GeneratorState::Yielded(..) => VmResult::err(VmErrorKind::Halted { - halt: VmHaltInfo::Yielded, - }), + pub fn into_stream(self) -> VmStream { + VmStream { + execution: Some(self), } } +} - /// Complete the current execution without support for async instructions. +impl VmExecution +where + T: AsMut, +{ + /// Synchronously complete the current execution. /// - /// If any async instructions are encountered, this will error. This will - /// also error if the execution is suspended through yielding. - pub fn complete(&mut self) -> VmResult { - self.complete_with_diagnostics(None) - } - - /// Complete the current execution without support for async instructions. + /// # Errors /// - /// If any async instructions are encountered, this will error. This will - /// also error if the execution is suspended through yielding. - pub fn complete_with_diagnostics( - &mut self, - diagnostics: Option<&mut dyn VmDiagnostics>, - ) -> VmResult { - match vm_try!(self.resume_with_diagnostics(diagnostics)) { - GeneratorState::Complete(value) => VmResult::Ok(value), - GeneratorState::Yielded(..) => VmResult::err(VmErrorKind::Halted { - halt: VmHaltInfo::Yielded, - }), - } - } - - /// Resume the current execution with the given value and resume - /// asynchronous execution. - pub async fn async_resume_with(&mut self, value: Value) -> VmResult { - let state = replace(&mut self.state, ExecutionState::Suspended); - - let ExecutionState::Resumed(out) = state else { - return VmResult::err(VmErrorKind::ExpectedExecutionState { actual: state }); - }; - - vm_try!(out.store(self.head.as_mut().stack_mut(), value)); - self.inner_async_resume(None).await - } - - /// Resume the current execution with support for async instructions. + /// If anything except the completion of the execution is encountered, this + /// will result in an error. /// - /// If the function being executed is a generator or stream this will resume - /// it while returning a unit from the current `yield`. - pub async fn async_resume(&mut self) -> VmResult { - self.async_resume_with_diagnostics(None).await + /// To handle other outcomes and more configurability see + /// [`VmExecution::resume`]. + pub fn complete(&mut self) -> Result { + self.resume().complete()?.into_complete() } - /// Resume the current execution with support for async instructions. + /// Asynchronously complete the current execution. /// - /// If the function being executed is a generator or stream this will resume - /// it while returning a unit from the current `yield`. - pub async fn async_resume_with_diagnostics( - &mut self, - diagnostics: Option<&mut dyn VmDiagnostics>, - ) -> VmResult { - if let ExecutionState::Resumed(out) = self.state { - vm_try!(out.store(self.head.as_mut().stack_mut(), Value::unit)); - } - - self.inner_async_resume(diagnostics).await - } - - async fn inner_async_resume( - &mut self, - mut diagnostics: Option<&mut dyn VmDiagnostics>, - ) -> VmResult { - loop { - let vm = self.head.as_mut(); - - match vm_try!(vm - .run(match diagnostics { - Some(ref mut value) => Some(&mut **value), - None => None, - }) - .with_vm(vm)) - { - VmHalt::Exited(addr) => { - self.state = ExecutionState::Exited(addr); - } - VmHalt::Awaited(awaited) => { - vm_try!(awaited.into_vm(vm).await); - continue; - } - VmHalt::VmCall(vm_call) => { - vm_try!(vm_call.into_execution(self)); - continue; - } - VmHalt::Yielded(addr, out) => { - let value = match addr { - Some(addr) => vm.stack().at(addr).clone(), - None => Value::unit(), - }; - - self.state = ExecutionState::Resumed(out); - return VmResult::Ok(GeneratorState::Yielded(value)); - } - halt => { - return VmResult::err(VmErrorKind::Halted { - halt: halt.into_info(), - }) - } - } - - if self.states.is_empty() { - let value = vm_try!(self.end()); - return VmResult::Ok(GeneratorState::Complete(value)); - } - - vm_try!(self.pop_state()); - } - } - - /// Resume the current execution with the given value and resume synchronous - /// execution. - #[tracing::instrument(skip_all, fields(?value))] - pub fn resume_with(&mut self, value: Value) -> VmResult { - let state = replace(&mut self.state, ExecutionState::Suspended); - - let ExecutionState::Resumed(out) = state else { - return VmResult::err(VmErrorKind::ExpectedExecutionState { actual: state }); - }; - - vm_try!(out.store(self.head.as_mut().stack_mut(), value)); - self.inner_resume(None) - } - - /// Resume the current execution without support for async instructions. + /// # Errors /// - /// If the function being executed is a generator or stream this will resume - /// it while returning a unit from the current `yield`. + /// If anything except the completion of the execution is encountered, this + /// will result in an error. /// - /// If any async instructions are encountered, this will error. - pub fn resume(&mut self) -> VmResult { - self.resume_with_diagnostics(None) + /// To handle other outcomes and more configurability see + /// [`VmExecution::resume`]. + pub async fn async_complete(&mut self) -> Result { + self.resume().await?.into_complete() } - /// Resume the current execution without support for async instructions. + /// Resume the current execution. /// - /// If the function being executed is a generator or stream this will resume - /// it while returning a unit from the current `yield`. + /// To complete this operation synchronously, use [`VmResume::complete`]. /// - /// If any async instructions are encountered, this will error. - #[tracing::instrument(skip_all, fields(diagnostics=diagnostics.is_some()))] - pub fn resume_with_diagnostics( - &mut self, - diagnostics: Option<&mut dyn VmDiagnostics>, - ) -> VmResult { - if let ExecutionState::Resumed(out) = replace(&mut self.state, ExecutionState::Suspended) { - vm_try!(out.store(self.head.as_mut().stack_mut(), Value::unit())); - } - - self.inner_resume(diagnostics) - } - - fn inner_resume( - &mut self, - mut diagnostics: Option<&mut dyn VmDiagnostics>, - ) -> VmResult { - loop { - let len = self.states.len(); - let vm = self.head.as_mut(); - - match vm_try!(vm - .run(match diagnostics { - Some(ref mut value) => Some(&mut **value), - None => None, - }) - .with_vm(vm)) - { - VmHalt::Exited(addr) => { - self.state = ExecutionState::Exited(addr); - } - VmHalt::VmCall(vm_call) => { - vm_try!(vm_call.into_execution(self)); - continue; - } - VmHalt::Yielded(addr, out) => { - let value = match addr { - Some(addr) => vm.stack().at(addr).clone(), - None => Value::unit(), - }; - - self.state = ExecutionState::Resumed(out); - return VmResult::Ok(GeneratorState::Yielded(value)); - } - halt => { - return VmResult::err(VmErrorKind::Halted { - halt: halt.into_info(), - }); - } - } - - if len == 0 { - let value = vm_try!(self.end()); - return VmResult::Ok(GeneratorState::Complete(value)); - } - - vm_try!(self.pop_state()); - } - } - - /// Step the single execution for one step without support for async - /// instructions. + /// ## Resume with a value /// - /// If any async instructions are encountered, this will error. - pub fn step(&mut self) -> VmResult> { - let len = self.states.len(); - let vm = self.head.as_mut(); - - match vm_try!(budget::with(1, || vm.run(None).with_vm(vm)).call()) { - VmHalt::Exited(addr) => { - self.state = ExecutionState::Exited(addr); - } - VmHalt::VmCall(vm_call) => { - vm_try!(vm_call.into_execution(self)); - return VmResult::Ok(None); - } - VmHalt::Limited => return VmResult::Ok(None), - halt => { - return VmResult::err(VmErrorKind::Halted { - halt: halt.into_info(), - }) - } - } - - if len == 0 { - let value = vm_try!(self.end()); - return VmResult::Ok(Some(value)); - } - - vm_try!(self.pop_state()); - VmResult::Ok(None) - } - - /// Step the single execution for one step with support for async - /// instructions. - pub async fn async_step(&mut self) -> VmResult> { - let vm = self.head.as_mut(); - - match vm_try!(budget::with(1, || vm.run(None).with_vm(vm)).call()) { - VmHalt::Exited(addr) => { - self.state = ExecutionState::Exited(addr); - } - VmHalt::Awaited(awaited) => { - vm_try!(awaited.into_vm(vm).await); - return VmResult::Ok(None); - } - VmHalt::VmCall(vm_call) => { - vm_try!(vm_call.into_execution(self)); - return VmResult::Ok(None); - } - VmHalt::Limited => return VmResult::Ok(None), - halt => { - return VmResult::err(VmErrorKind::Halted { - halt: halt.into_info(), - }); - } - } - - if self.states.is_empty() { - let value = vm_try!(self.end()); - return VmResult::Ok(Some(value)); + /// To resume an execution with a value, use [`VmResume::with_value`]. This + /// requires that the execution has yielded first, otherwise an error will + /// be produced. + /// + /// ## Resume with diagnostics + /// + /// To associated [`VmDiagnostics`] with the execution, use + /// [`VmResume::with_diagnostics`]. + pub fn resume(&mut self) -> VmResume<'_, 'static, T> { + VmResume { + execution: self, + diagnostics: None, + awaited: None, + init: Some(Value::empty()), } - - vm_try!(self.pop_state()); - VmResult::Ok(None) } /// End execution and perform debug checks. - pub(crate) fn end(&mut self) -> VmResult { + pub(crate) fn end(&mut self) -> Result { let ExecutionState::Exited(addr) = self.state else { - return VmResult::err(VmErrorKind::ExpectedExitedExecutionState { actual: self.state }); + return Err(VmError::new(VmErrorKind::ExpectedExitedExecutionState { + actual: self.state, + })); }; let value = match addr { - Some(addr) => self.head.as_ref().stack().at(addr).clone(), + Some(addr) => self.vm.as_mut().stack().at(addr).clone(), None => Value::unit(), }; debug_assert!(self.states.is_empty(), "Execution states should be empty"); - VmResult::Ok(value) + Ok(value) } /// Push a virtual machine state onto the execution. #[tracing::instrument(skip_all)] - pub(crate) fn push_state(&mut self, state: VmExecutionState) -> VmResult<()> { + pub(crate) fn push_state(&mut self, state: VmExecutionState) -> Result<(), VmError> { tracing::trace!("pushing suspended state"); - let vm = self.head.as_mut(); + let vm = self.vm.as_mut(); let context = state.context.map(|c| replace(vm.context_mut(), c)); let unit = state.unit.map(|u| replace(vm.unit_mut(), u)); - vm_try!(self.states.try_push(VmExecutionState { context, unit })); - VmResult::Ok(()) + self.states.try_push(VmExecutionState { context, unit })?; + Ok(()) } /// Pop a virtual machine state from the execution and transfer the top of /// the stack from the popped machine. #[tracing::instrument(skip_all)] - fn pop_state(&mut self) -> VmResult<()> { + fn pop_state(&mut self) -> Result<(), VmError> { tracing::trace!("popping suspended state"); - let state = vm_try!(self.states.pop().ok_or(VmErrorKind::NoRunningVm)); - let vm = self.head.as_mut(); + let state = self.states.pop().ok_or(VmErrorKind::NoRunningVm)?; + let vm = self.vm.as_mut(); if let Some(context) = state.context { *vm.context_mut() = context; @@ -483,18 +279,18 @@ where *vm.unit_mut() = unit; } - VmResult::Ok(()) + Ok(()) } } impl VmExecution<&mut Vm> { /// Convert the current execution into one which owns its virtual machine. pub fn into_owned(self) -> VmExecution { - let stack = take(self.head.stack_mut()); - let head = Vm::with_stack(self.head.context().clone(), self.head.unit().clone(), stack); + let stack = take(self.vm.stack_mut()); + let head = Vm::with_stack(self.vm.context().clone(), self.vm.unit().clone(), stack); VmExecution { - head, + vm: head, states: self.states, state: self.state, } @@ -521,47 +317,50 @@ impl VmSendExecution { /// This requires that the result of the Vm is converted into a /// [crate::FromValue] that also implements [Send], which prevents non-Send /// values from escaping from the virtual machine. - pub fn async_complete(mut self) -> impl Future> + Send + 'static { - let future = async move { - let result = vm_try!(self.0.async_resume().await); - - match result { - GeneratorState::Complete(value) => VmResult::Ok(value), - GeneratorState::Yielded(..) => VmResult::err(VmErrorKind::Halted { - halt: VmHaltInfo::Yielded, - }), - } - }; + pub fn complete(mut self) -> impl Future> + Send + 'static { + let future = async move { self.0.resume().await.and_then(VmOutcome::into_complete) }; // Safety: we wrap all APIs around the [VmExecution], preventing values // from escaping from contained virtual machine. unsafe { AssertSend::new(future) } } + /// Alias for [`VmSendExecution::complete`]. + #[deprecated = "Use `VmSendExecution::complete`"] + pub fn async_complete(self) -> impl Future> + Send + 'static { + self.complete() + } + /// Complete the current execution with support for async instructions. /// /// This requires that the result of the Vm is converted into a /// [crate::FromValue] that also implements [Send], which prevents non-Send /// values from escaping from the virtual machine. - pub fn async_complete_with_diagnostics( + pub fn complete_with_diagnostics( mut self, - diagnostics: Option<&mut dyn VmDiagnostics>, - ) -> impl Future> + Send + '_ { + diagnostics: &mut dyn VmDiagnostics, + ) -> impl Future> + Send + '_ { let future = async move { - let result = vm_try!(self.0.async_resume_with_diagnostics(diagnostics).await); - - match result { - GeneratorState::Complete(value) => VmResult::Ok(value), - GeneratorState::Yielded(..) => VmResult::err(VmErrorKind::Halted { - halt: VmHaltInfo::Yielded, - }), - } + self.0 + .resume() + .with_diagnostics(diagnostics) + .await + .and_then(VmOutcome::into_complete) }; // Safety: we wrap all APIs around the [VmExecution], preventing values // from escaping from contained virtual machine. unsafe { AssertSend::new(future) } } + + /// Alias for [`VmSendExecution::complete_with_diagnostics`]. + #[deprecated = "Use `VmSendExecution::complete_with_diagnostics`"] + pub fn async_complete_with_diagnostics( + self, + diagnostics: &mut dyn VmDiagnostics, + ) -> impl Future> + Send + '_ { + self.complete_with_diagnostics(diagnostics) + } } impl TryClone for VmExecution @@ -571,9 +370,296 @@ where #[inline] fn try_clone(&self) -> Result { Ok(Self { - head: self.head.try_clone()?, + vm: self.vm.try_clone()?, state: self.state, states: self.states.try_clone()?, }) } } + +/// The outcome of completing an execution through a [`VmResume`] operation. +#[non_exhaustive] +pub enum VmOutcome { + /// A value has been produced by the execution returning. + Complete(Value), + /// A value has been yielded by the execution. + Yielded(Value), + /// The execution has been limited. + Limited, +} + +impl VmOutcome { + /// Convert the outcome into a [`GeneratorState`]. + /// + /// # Errors + /// + /// If the execution is not in a state compatible with producing a generator + /// state, such as having been completed or yielded, this will produce an + /// error. + pub fn into_generator_state(self) -> Result { + match self { + VmOutcome::Complete(value) => Ok(GeneratorState::Complete(value)), + VmOutcome::Yielded(value) => Ok(GeneratorState::Yielded(value)), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } + } + + /// Convert the outcome into a completed value. + /// + /// # Errors + /// + /// If the execution hasn't returned, this will produce an error. + pub fn into_complete(self) -> Result { + match self { + VmOutcome::Complete(value) => Ok(value), + VmOutcome::Yielded(..) => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Yielded, + })), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } + } +} + +/// An execution that has been resumed. +/// +/// This can either be completed as a future, which allows the execution to +/// perform asynchronous operations, or it can be completed by calling +/// [`VmResume::complete`] which will produce an error in case asynchronous +/// operations that need to be suspended are encountered. +pub struct VmResume<'this, 'diag, T> { + execution: &'this mut VmExecution, + diagnostics: Option<&'diag mut dyn VmDiagnostics>, + init: Option, + awaited: Option, +} + +impl<'this, 'diag, T> VmResume<'this, 'diag, T> { + /// Associated a budget with the resumed execution. + pub fn with_budget(self, budget: usize) -> Budget { + budget::with(budget, self) + } + + /// Associate a value with the resumed execution. + /// + /// This is necessary to provide a value for a generator which has yielded. + pub fn with_value(self, value: Value) -> VmResume<'this, 'diag, T> { + Self { + init: Some(value), + ..self + } + } + + /// Associate diagnostics with the execution. + pub fn with_diagnostics<'a>( + self, + diagnostics: &'a mut dyn VmDiagnostics, + ) -> VmResume<'this, 'a, T> { + VmResume { + execution: self.execution, + diagnostics: Some(diagnostics), + init: self.init, + awaited: self.awaited, + } + } +} + +impl<'this, 'diag, T> VmResume<'this, 'diag, T> +where + T: AsMut, +{ + /// Try to synchronously complete the run, returning the generator state it produced. + /// + /// This will error if the execution is suspended through awaiting. + pub fn complete(self) -> Result { + let this = pin!(self); + let mut cx = Context::from_waker(&COMPLETE_WAKER); + + match this.poll(&mut cx) { + Poll::Ready(result) => result, + Poll::Pending => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Awaited, + })), + } + } +} + +impl<'this, 'diag, T> Future for VmResume<'this, 'diag, T> +where + T: AsMut, +{ + type Output = Result; + + #[inline] + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: We are ensuring that we never move this value or any + // projected fields. + let this = unsafe { Pin::get_unchecked_mut(self) }; + + if let Some(value) = this.init.take() { + let state = replace(&mut this.execution.state, ExecutionState::Suspended); + + if let ExecutionState::Resumed(out) = state { + let vm = this.execution.vm.as_mut(); + async_vm_try!(out.store(vm.stack_mut(), value)); + } + } + + loop { + let vm = this.execution.vm.as_mut(); + + if let Some(awaited) = &mut this.awaited { + let awaited = unsafe { Pin::new_unchecked(awaited) }; + async_vm_try!(ready!(awaited.poll(cx, vm))); + this.awaited = None; + } + + let result = vm.run(match this.diagnostics { + Some(ref mut value) => Some(&mut **value), + None => None, + }); + + match async_vm_try!(VmError::with_vm(result, vm)) { + VmHalt::Exited(addr) => { + this.execution.state = ExecutionState::Exited(addr); + } + VmHalt::Awaited(awaited) => { + this.awaited = Some(awaited); + continue; + } + VmHalt::VmCall(vm_call) => { + async_vm_try!(vm_call.into_execution(this.execution)); + continue; + } + VmHalt::Yielded(addr, out) => { + let value = match addr { + Some(addr) => vm.stack().at(addr).clone(), + None => Value::unit(), + }; + + this.execution.state = ExecutionState::Resumed(out); + return Poll::Ready(Ok(VmOutcome::Yielded(value))); + } + VmHalt::Limited => { + return Poll::Ready(Ok(VmOutcome::Limited)); + } + } + + if this.execution.states.is_empty() { + let value = async_vm_try!(this.execution.end()); + return Poll::Ready(Ok(VmOutcome::Complete(value))); + } + + async_vm_try!(this.execution.pop_state()); + } + } +} + +/// A [`VmExecution`] that can be used with a generator api. +pub struct VmGenerator { + execution: Option>, +} + +impl VmGenerator +where + T: AsMut, +{ + /// Get the next value produced by this generator. + /// + /// See [`VmExecution::into_generator`]. + pub fn next(&mut self) -> Result, VmError> { + let Some(execution) = &mut self.execution else { + return Ok(None); + }; + + let outcome = execution.resume().complete()?; + + match outcome { + VmOutcome::Complete(_) => { + self.execution = None; + Ok(None) + } + VmOutcome::Yielded(value) => Ok(Some(value)), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } + } + + /// Resume the generator with a value and get the next [`GeneratorState`]. + /// + /// See [`VmExecution::into_generator`]. + pub fn resume(&mut self, value: Value) -> Result { + let execution = self + .execution + .as_mut() + .ok_or(VmErrorKind::GeneratorComplete)?; + + let outcome = execution.resume().with_value(value).complete()?; + + match outcome { + VmOutcome::Complete(value) => { + self.execution = None; + Ok(GeneratorState::Complete(value)) + } + VmOutcome::Yielded(value) => Ok(GeneratorState::Yielded(value)), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } + } +} + +/// A [`VmExecution`] that can be used with a stream api. +pub struct VmStream { + execution: Option>, +} + +impl VmStream +where + T: AsMut, +{ + /// Get the next value produced by this stream. + /// + /// See [`VmExecution::into_stream`]. + pub async fn next(&mut self) -> Result, VmError> { + let Some(execution) = &mut self.execution else { + return Ok(None); + }; + + match execution.resume().await? { + VmOutcome::Complete(value) => { + self.execution = None; + Ok(Some(value)) + } + VmOutcome::Yielded(..) => Ok(None), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } + } + + /// Resume the stream with a value and return the next [`GeneratorState`]. + /// + /// See [`VmExecution::into_stream`]. + pub async fn resume(&mut self, value: Value) -> Result { + let execution = self + .execution + .as_mut() + .ok_or(VmErrorKind::GeneratorComplete)?; + + match execution.resume().with_value(value).await? { + VmOutcome::Complete(value) => { + self.execution = None; + Ok(GeneratorState::Complete(value)) + } + VmOutcome::Yielded(value) => Ok(GeneratorState::Yielded(value)), + VmOutcome::Limited => Err(VmError::new(VmErrorKind::Halted { + halt: VmHaltInfo::Limited, + })), + } + } +} diff --git a/crates/rune/src/runtime/vm_halt.rs b/crates/rune/src/runtime/vm_halt.rs index 3b544b48a..63611b69c 100644 --- a/crates/rune/src/runtime/vm_halt.rs +++ b/crates/rune/src/runtime/vm_halt.rs @@ -1,58 +1,39 @@ use core::fmt; -use crate::runtime::{Awaited, InstAddress, Output, VmCall}; +use crate::runtime::{Address, Awaited, Output, VmCall}; /// The reason why the virtual machine execution stopped. #[derive(Debug)] pub(crate) enum VmHalt { /// The virtual machine exited by running out of call frames, returning the given value. - Exited(Option), + Exited(Option
), /// The virtual machine exited because it ran out of execution quota. Limited, /// The virtual machine yielded. - Yielded(Option, Output), + Yielded(Option
, Output), /// The virtual machine awaited on the given future. Awaited(Awaited), /// Call into a new virtual machine. VmCall(VmCall), } -impl VmHalt { - /// Convert into cheap info enum which only described the reason. - pub(crate) fn into_info(self) -> VmHaltInfo { - match self { - Self::Exited(..) => VmHaltInfo::Exited, - Self::Limited => VmHaltInfo::Limited, - Self::Yielded(..) => VmHaltInfo::Yielded, - Self::Awaited(..) => VmHaltInfo::Awaited, - Self::VmCall(..) => VmHaltInfo::VmCall, - } - } -} - /// The reason why the virtual machine execution stopped. #[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. Limited, /// The virtual machine yielded. Yielded, /// The virtual machine awaited on the given future. Awaited, - /// Received instruction to push the inner virtual machine. - VmCall, } impl fmt::Display for VmHaltInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Exited => write!(f, "exited"), Self::Limited => write!(f, "limited"), Self::Yielded => write!(f, "yielded"), Self::Awaited => write!(f, "awaited"), - Self::VmCall => write!(f, "calling into other vm"), } } } diff --git a/crates/rune/src/shared/caller.rs b/crates/rune/src/shared/caller.rs index 6d0f7ca76..d4ec905d5 100644 --- a/crates/rune/src/shared/caller.rs +++ b/crates/rune/src/shared/caller.rs @@ -1,8 +1,6 @@ use core::marker::PhantomData; -use rust_alloc::sync::Arc; - -use crate::runtime::{FixedArgs, FunctionHandler, InstAddress, Output, VmResult}; +use crate::runtime::{Address, FixedArgs, FunctionHandler, Output, VmError}; use crate::FromValue; /// Helper struct to conveniently call native functions. @@ -11,7 +9,7 @@ use crate::FromValue; /// Otherwise it will panic. #[derive(Clone)] pub(crate) struct Caller { - handler: Arc, + handler: FunctionHandler, _marker: PhantomData<(A, T)>, } @@ -21,7 +19,7 @@ where T: FromValue, { /// Construct a new caller helper - pub(crate) fn new(handler: Arc) -> Self { + pub(crate) fn new(handler: FunctionHandler) -> Self { Self { handler, _marker: PhantomData, @@ -40,25 +38,21 @@ where } /// Perform a call. - pub(crate) fn call(&self, args: A) -> VmResult { + pub(crate) fn call(&self, args: A) -> Result { const { assert!(N > 0, "Must be used with non-zero arguments"); } - let mut args = vm_try!(args.into_array()); + let mut args = args.into_array()?; - vm_try!((self.handler)( - &mut args, - InstAddress::ZERO, - N, - Output::keep(0) - )); + self.handler + .call(&mut args, Address::ZERO, N, Output::keep(0))?; let Some(value) = args.into_iter().next() else { unreachable!(); }; - VmResult::Ok(vm_try!(T::from_value(value))) + Ok(T::from_value(value)?) } } diff --git a/crates/rune/src/shared/fixed_vec.rs b/crates/rune/src/shared/fixed_vec.rs index 1bff4912c..21c83b93b 100644 --- a/crates/rune/src/shared/fixed_vec.rs +++ b/crates/rune/src/shared/fixed_vec.rs @@ -43,6 +43,7 @@ impl FixedVec { } /// Try to push an element onto the fixed vector. + #[inline] pub(crate) fn try_push(&mut self, element: T) -> alloc::Result<()> { if self.len >= N { return Err(alloc::Error::CapacityOverflow); @@ -56,6 +57,8 @@ impl FixedVec { Ok(()) } + /// Clear the fixed vector. + #[inline] pub(crate) fn clear(&mut self) { if self.len == 0 { return; diff --git a/crates/rune/src/sources.rs b/crates/rune/src/sources.rs index 7d30a810c..96a45ab7e 100644 --- a/crates/rune/src/sources.rs +++ b/crates/rune/src/sources.rs @@ -1,6 +1,11 @@ use core::fmt; use core::num; +#[cfg(feature = "musli")] +use musli::{Decode, Encode}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + use crate as rune; use crate::alloc; use crate::alloc::path::Path; @@ -24,8 +29,7 @@ use codespan_reporting::files; /// } /// } /// }; -/// -/// Ok::<_, rune::support::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[macro_export] macro_rules! sources { @@ -45,6 +49,7 @@ pub struct Sources { impl Sources { /// Construct a new collection of sources. + #[inline] pub fn new() -> Self { Self { sources: Vec::new(), @@ -64,6 +69,7 @@ impl Sources { /// assert_ne!(id, id2); /// # Ok::<_, rune::support::Error>(()) /// ``` + #[inline] pub fn insert(&mut self, source: Source) -> alloc::Result { let id = SourceId::try_from(self.sources.len()).expect("could not build a source identifier"); @@ -87,35 +93,41 @@ impl Sources { /// assert_eq!(source.name(), ""); /// # Ok::<_, rune::support::Error>(()) /// ``` + #[inline] pub fn get(&self, id: SourceId) -> Option<&Source> { self.sources.get(id.into_index()) } /// Fetch name for the given source id. + #[inline] pub(crate) fn name(&self, id: SourceId) -> Option<&str> { let source = self.sources.get(id.into_index())?; Some(source.name()) } /// Fetch source for the given span. + #[inline] pub(crate) fn source(&self, id: SourceId, span: Span) -> Option<&str> { let source = self.sources.get(id.into_index())?; source.get(span.range()) } /// Access the optional path of the given source id. + #[inline] pub(crate) fn path(&self, id: SourceId) -> Option<&Path> { let source = self.sources.get(id.into_index())?; source.path() } /// Get all available source ids. + #[inline] pub(crate) fn source_ids(&self) -> impl Iterator { (0..self.sources.len()).map(|index| SourceId::new(index as u32)) } /// Iterate over all registered sources. #[cfg(feature = "cli")] + #[inline] pub(crate) fn iter(&self) -> impl Iterator { self.sources.iter() } @@ -127,23 +139,27 @@ impl<'a> files::Files<'a> for Sources { type Name = &'a str; type Source = &'a str; + #[inline] fn name(&'a self, file_id: SourceId) -> Result { let source = self.get(file_id).ok_or(files::Error::FileMissing)?; Ok(source.name()) } + #[inline] fn source(&'a self, file_id: SourceId) -> Result { let source = self.get(file_id).ok_or(files::Error::FileMissing)?; Ok(source.as_str()) } #[cfg(feature = "emit")] + #[inline] fn line_index(&self, file_id: SourceId, byte_index: usize) -> Result { let source = self.get(file_id).ok_or(files::Error::FileMissing)?; Ok(source.line_index(byte_index)) } #[cfg(feature = "emit")] + #[inline] fn line_range( &self, file_id: SourceId, @@ -168,6 +184,8 @@ impl<'a> files::Files<'a> for Sources { #[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[try_clone(copy)] #[repr(transparent)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] +#[cfg_attr(feature = "musli", derive(Encode, Decode), musli(transparent))] pub struct SourceId { index: u32, } @@ -177,34 +195,40 @@ impl SourceId { pub const EMPTY: Self = Self::empty(); /// Construct a source identifier from an index. + #[inline] pub const fn new(index: u32) -> Self { Self { index } } /// Define an empty source identifier that cannot reference a source. + #[inline] pub const fn empty() -> Self { Self { index: u32::MAX } } /// Access the source identifier as an index. + #[inline] pub fn into_index(self) -> usize { usize::try_from(self.index).expect("source id out of bounds") } } impl fmt::Debug for SourceId { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.index.fmt(f) } } impl fmt::Display for SourceId { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.index.fmt(f) } } impl Default for SourceId { + #[inline] fn default() -> Self { Self::empty() } @@ -213,29 +237,10 @@ impl Default for SourceId { impl TryFrom for SourceId { type Error = num::TryFromIntError; + #[inline] fn try_from(value: usize) -> Result { Ok(Self { index: u32::try_from(value)?, }) } } - -impl serde::Serialize for SourceId { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.index.serialize(serializer) - } -} - -impl<'de> serde::Deserialize<'de> for SourceId { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(Self { - index: u32::deserialize(deserializer)?, - }) - } -} diff --git a/crates/rune/src/support.rs b/crates/rune/src/support.rs index 4444b11c1..b9944e1d9 100644 --- a/crates/rune/src/support.rs +++ b/crates/rune/src/support.rs @@ -2,6 +2,7 @@ //! not intended for end-users and might change at any time. #[doc(inline)] +#[cfg(feature = "anyhow")] pub use anyhow::Context; #[cfg(not(feature = "std"))] @@ -37,6 +38,7 @@ pub(crate) mod no_std { impl Error { /// Create a new error object from a printable error message. + #[cfg(feature = "anyhow")] pub fn msg(message: M) -> Self where M: fmt::Display + fmt::Debug + Send + Sync + 'static, @@ -45,9 +47,26 @@ pub(crate) mod no_std { kind: ErrorKind::Custom(anyhow::Error::msg(message)), } } + + /// Create a new error object from a printable error message. + #[cfg(not(feature = "anyhow"))] + pub fn msg(message: M) -> Self + where + M: fmt::Display + fmt::Debug + Send + Sync + 'static, + { + match crate::alloc::fmt::try_format(format_args!("{message}")) { + Ok(string) => Self { + kind: ErrorKind::Custom(string), + }, + Err(error) => Self { + kind: ErrorKind::Alloc(error), + }, + } + } } impl From for Error { + #[inline] fn from(error: alloc::Error) -> Self { Self { kind: ErrorKind::Alloc(error), @@ -56,6 +75,7 @@ pub(crate) mod no_std { } impl From for Error { + #[inline] fn from(error: compile::ContextError) -> Self { Self { kind: ErrorKind::Context(error), @@ -64,6 +84,7 @@ pub(crate) mod no_std { } impl From for Error { + #[inline] fn from(error: compile::Error) -> Self { Self { kind: ErrorKind::Compile(error), @@ -72,6 +93,7 @@ pub(crate) mod no_std { } impl From for Error { + #[inline] fn from(error: build::BuildError) -> Self { Self { kind: ErrorKind::Build(error), @@ -80,6 +102,7 @@ pub(crate) mod no_std { } impl From for Error { + #[inline] fn from(error: runtime::VmError) -> Self { Self { kind: ErrorKind::Vm(error), @@ -88,6 +111,7 @@ pub(crate) mod no_std { } impl From for Error { + #[inline] fn from(error: runtime::RuntimeError) -> Self { Self { kind: ErrorKind::Runtime(error), @@ -95,7 +119,9 @@ pub(crate) mod no_std { } } + #[cfg(feature = "anyhow")] impl From for Error { + #[inline] fn from(error: anyhow::Error) -> Self { Self { kind: ErrorKind::Custom(error), @@ -105,6 +131,7 @@ pub(crate) mod no_std { #[cfg(test)] impl From for Error { + #[inline] fn from(error: tests::TestError) -> Self { Self { kind: ErrorKind::Test(error), @@ -113,6 +140,7 @@ pub(crate) mod no_std { } impl fmt::Display for Error { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.kind { ErrorKind::Alloc(error) => error.fmt(f), @@ -136,7 +164,10 @@ pub(crate) mod no_std { Build(build::BuildError), Vm(runtime::VmError), Runtime(runtime::RuntimeError), + #[cfg(feature = "anyhow")] Custom(anyhow::Error), + #[cfg(not(feature = "anyhow"))] + Custom(alloc::String), #[cfg(test)] Test(tests::TestError), } @@ -150,7 +181,10 @@ pub(crate) mod no_std { ErrorKind::Build(error) => Some(error), ErrorKind::Vm(error) => Some(error), ErrorKind::Runtime(error) => Some(error), + #[cfg(feature = "anyhow")] ErrorKind::Custom(error) => Some(error.as_ref()), + #[cfg(not(feature = "anyhow"))] + ErrorKind::Custom(..) => None, #[cfg(test)] ErrorKind::Test(error) => Some(error), } diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index 3554e35bc..1338a3e5b 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -17,29 +17,29 @@ pub(crate) mod prelude { pub(crate) use crate::module::InstallWith; pub(crate) use crate::parse; pub(crate) use crate::runtime::{ - self, Bytes, DynamicTuple, Formatter, Function, InstAddress, MaybeTypeOf, Object, Output, - OwnedTuple, Protocol, RawAnyGuard, Ref, Stack, Tuple, TypeHash, TypeInfo, TypeOf, - UnsafeToRef, VecTuple, VmErrorKind, VmResult, + self, Address, Bytes, DynamicTuple, Formatter, Function, MaybeTypeOf, Object, Output, + OwnedTuple, Protocol, RawAnyGuard, Ref, Shared, Stack, Tuple, TypeHash, TypeInfo, TypeOf, + UnsafeToRef, VecTuple, VmErrorKind, }; pub(crate) use crate::support::Result; pub(crate) use crate::tests::{eval, run}; pub(crate) use crate::{ - from_value, prepare, sources, span, vm_try, Any, Context, ContextError, Diagnostics, - FromValue, Hash, Item, ItemBuf, Module, Options, Source, Sources, Value, Vm, + from_value, prepare, sources, span, Any, Context, ContextError, Diagnostics, FromValue, + Hash, Item, ItemBuf, Module, Options, Source, Sources, Value, Vm, }; pub(crate) use futures_executor::block_on; - 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 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; -use ::rust_alloc::string::String; -use ::rust_alloc::sync::Arc; +use rust_alloc::string::String; +use rust_alloc::sync::Arc; use anyhow::{Context as _, Error, Result}; @@ -163,8 +163,9 @@ where vm.execute(["main"], args).map_err(TestError::VmError)? }; - let output = ::futures_executor::block_on(execute.async_complete()) - .into_result() + let output = ::futures_executor::block_on(execute.resume()) + .map_err(TestError::VmError)? + .into_complete() .map_err(TestError::VmError)?; crate::from_value(output).map_err(|error| TestError::VmError(error.into())) @@ -471,6 +472,8 @@ mod debug_fmt; #[cfg(not(miri))] mod deprecation; #[cfg(not(miri))] +mod derive_constructor; +#[cfg(not(miri))] mod destructuring; #[cfg(not(miri))] mod esoteric_impls; diff --git a/crates/rune/src/tests/bug_344.rs b/crates/rune/src/tests/bug_344.rs index 71348ab18..bfb10c154 100644 --- a/crates/rune/src/tests/bug_344.rs +++ b/crates/rune/src/tests/bug_344.rs @@ -29,8 +29,8 @@ fn bug_344_function() -> Result<()> { let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; - function(&mut stack, InstAddress::new(0), 1, Output::keep(0)).into_result()?; - assert_eq!(stack.at(InstAddress::new(0)).as_signed()?, 42); + function.call(&mut stack, Address::new(0), 1, Output::keep(0))?; + assert_eq!(stack.at(Address::new(0)).as_signed()?, 42); return Ok(()); fn function(check: &GuardCheck) -> i64 { @@ -63,9 +63,9 @@ fn bug_344_inst_fn() -> Result<()> { let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; stack.push(rune::to_value(GuardCheck::new())?)?; - function(&mut stack, InstAddress::ZERO, 2, Output::keep(0)).into_result()?; + function.call(&mut stack, Address::ZERO, 2, Output::keep(0))?; - assert_eq!(stack.at(InstAddress::ZERO).as_signed()?, 42); + assert_eq!(stack.at(Address::ZERO).as_signed()?, 42); Ok(()) } @@ -83,9 +83,9 @@ fn bug_344_async_function() -> Result<()> { let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; - function(&mut stack, InstAddress::ZERO, 1, Output::keep(0)).into_result()?; - let future = stack.at(InstAddress::ZERO).clone().into_future()?; - assert_eq!(block_on(future).into_result()?.as_signed()?, 42); + function.call(&mut stack, Address::ZERO, 1, Output::keep(0))?; + let future = stack.at(Address::ZERO).clone().into_future()?; + assert_eq!(block_on(future)?.as_signed()?, 42); return Ok(()); async fn function(check: Ref) -> i64 { @@ -97,10 +97,10 @@ fn bug_344_async_function() -> Result<()> { #[test] fn bug_344_async_inst_fn() -> Result<()> { #[rune::function(instance)] - async fn function(s: Ref, check: Ref) -> VmResult { + async fn function(s: Ref, check: Ref) -> i64 { s.ensure_not_dropped("self argument"); check.ensure_not_dropped("instance argument"); - VmResult::Ok(42) + 42 } let mut context = Context::new(); @@ -118,10 +118,10 @@ fn bug_344_async_inst_fn() -> Result<()> { let mut stack = Stack::new(); stack.push(rune::to_value(GuardCheck::new())?)?; stack.push(rune::to_value(GuardCheck::new())?)?; - function(&mut stack, InstAddress::new(0), 2, Output::keep(0)).into_result()?; + function.call(&mut stack, Address::new(0), 2, Output::keep(0))?; - let future = stack.at(InstAddress::new(0)).clone().into_future()?; - assert_eq!(block_on(future).into_result()?.as_signed()?, 42); + let future = stack.at(Address::new(0)).clone().into_future()?; + assert_eq!(block_on(future)?.as_signed()?, 42); Ok(()) } @@ -159,7 +159,7 @@ impl GuardCheck { } impl Any for GuardCheck {} -impl rune::__private::AnyMarker for GuardCheck {} +impl rune::__priv::AnyMarker for GuardCheck {} impl Named for GuardCheck { const ITEM: &'static Item = rune_macros::item!(GuardCheck); diff --git a/crates/rune/src/tests/bug_700.rs b/crates/rune/src/tests/bug_700.rs index 8ebe4ba81..1ea821bd2 100644 --- a/crates/rune/src/tests/bug_700.rs +++ b/crates/rune/src/tests/bug_700.rs @@ -19,7 +19,7 @@ pub fn test_bug_700() -> Result<()> { let value = vm.call(["main"], (42,))?; let function = from_value::(value)?; - let output: i64 = function.call(()).into_result()?; + let output: i64 = function.call(())?; assert_eq!(output, 42); // This should error, because the function is missing the environment variable. diff --git a/crates/rune/src/tests/debug_fmt.rs b/crates/rune/src/tests/debug_fmt.rs index 2003f01a2..e4f91d0c6 100644 --- a/crates/rune/src/tests/debug_fmt.rs +++ b/crates/rune/src/tests/debug_fmt.rs @@ -2,14 +2,16 @@ prelude!(); +use rune::alloc; + #[derive(Any, Debug)] #[rune(item = ::native_crate)] pub struct NativeStructWithProtocol; impl NativeStructWithProtocol { #[rune::function(protocol = DEBUG_FMT)] - fn debug_fmt(&self, f: &mut Formatter) -> VmResult<()> { - vm_write!(f, "{self:?}") + fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> { + write!(f, "{self:?}") } } diff --git a/crates/rune/src/tests/deprecation.rs b/crates/rune/src/tests/deprecation.rs index 235a84146..544a3255a 100644 --- a/crates/rune/src/tests/deprecation.rs +++ b/crates/rune/src/tests/deprecation.rs @@ -89,7 +89,7 @@ fn test_deprecation_warnings() -> Result<()> { ); let mut vm = Vm::new(Arc::new(context.runtime()?), unit.clone()); - vm.call_with_diagnostics(["main"], (), Some(&mut diagnostics))?; + vm.call_with_diagnostics(["main"], (), &mut diagnostics)?; // print diagnostics - just for manual check if !diagnostics.is_empty() { @@ -122,9 +122,7 @@ async fn test_deprecation_warnings_async() -> Result<()> { let vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let future = vm.send_execute(["main"], ())?; - let _ = future - .async_complete_with_diagnostics(Some(&mut diagnostics)) - .await; + let _ = future.complete_with_diagnostics(&mut diagnostics).await; // print diagnostics - just for manual check if !diagnostics.is_empty() { diff --git a/crates/rune/src/tests/derive_constructor.rs b/crates/rune/src/tests/derive_constructor.rs new file mode 100644 index 000000000..0bab7010a --- /dev/null +++ b/crates/rune/src/tests/derive_constructor.rs @@ -0,0 +1,103 @@ +#![allow(unused)] + +prelude!(); + +#[derive(Any)] +#[rune(constructor)] +struct Empty; + +#[derive(Any)] +#[rune(constructor)] +struct EmptyNamed {} + +#[derive(Any)] +#[rune(constructor)] +struct EmptyUnnamed {} + +#[derive(Any)] +#[rune(constructor)] +struct NamedZero { + a: i32, + b: String, +} + +#[derive(Any)] +#[rune(constructor)] +struct NamedOne { + #[rune(get)] + a: i32, + b: String, +} + +#[derive(Any)] +#[rune(constructor)] +struct NamedTwo { + #[rune(get)] + a: i32, + #[rune(get)] + b: String, +} + +#[derive(Any)] +#[rune(constructor)] +struct UnnamedZero(i32, String); + +#[derive(Any)] +#[rune(constructor)] +struct UnnamedOne(#[rune(get)] i32, String); + +#[derive(Any)] +#[rune(constructor)] +struct UnnamedTwo(#[rune(get)] i32, #[rune(get)] String); + +#[derive(Any)] +enum Enum { + #[rune(constructor)] + Empty, + #[rune(constructor)] + EmptyNamed {}, + #[rune(constructor)] + EmptyUnnamed {}, + #[rune(constructor)] + NamedZero { a: i32, b: String }, + #[rune(constructor)] + NamedOne { + #[rune(get)] + a: i32, + b: String, + }, + #[rune(constructor)] + NamedTwo { + #[rune(get)] + a: i32, + #[rune(get)] + b: String, + }, + #[rune(constructor)] + UnnamedZero(i32, String), + #[rune(constructor)] + UnnamedOne(#[rune(get)] i32, String), + #[rune(constructor)] + UnnamedTwo(#[rune(get)] i32, #[rune(get)] String), +} + +#[test] +fn module() { + let mut m = Module::new(); + m.ty::().unwrap(); + m.ty::().unwrap(); + m.ty::().unwrap(); + + m.ty::().unwrap(); + m.ty::().unwrap(); + m.ty::().unwrap(); + + m.ty::().unwrap(); + m.ty::().unwrap(); + m.ty::().unwrap(); + + m.ty::().unwrap(); + + let mut c = Context::new(); + c.install(m).unwrap(); +} diff --git a/crates/rune/src/tests/external_ops.rs b/crates/rune/src/tests/external_ops.rs index 9ceadfd7f..3680df4d6 100644 --- a/crates/rune/src/tests/external_ops.rs +++ b/crates/rune/src/tests/external_ops.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; use std::sync::Arc; #[test] -fn strut_assign() -> Result<()> { +fn struct_assign() -> Result<()> { macro_rules! test_case { ([$($op:tt)*], $protocol:ident, $derived:tt, $initial:literal, $arg:literal, $expected:literal) => {{ #[derive(Debug, Default, Any)] @@ -175,52 +175,29 @@ fn tuple_assign() -> Result<()> { } #[test] -#[ignore = "assembly currently doesn't know how to handle this"] -fn struct_ops() -> Result<()> { +fn struct_binary() -> Result<()> { macro_rules! test_case { ([$($op:tt)*], $protocol:ident, $derived:tt, $initial:literal, $arg:literal, $expected:literal) => {{ - #[derive(Debug, Default, Any)] + #[derive(Debug, Any)] struct External { value: i64, - field: i64, - #[rune($derived)] - derived: i64, - #[rune($derived = External::custom)] - custom: i64, } impl External { fn value(&self, value: i64) -> i64 { self.value $($op)* value } - - fn field(&self, value: i64) -> i64 { - self.field $($op)* value - } - - fn custom(&self, value: i64) -> i64 { - self.custom $($op)* value - } } let mut module = Module::new(); module.ty::()?; module.associated_function(&Protocol::$protocol, External::value)?; - module.field_function(&Protocol::$protocol, "field", External::field)?; let mut context = Context::default(); context.install(module)?; - let source = format!(r#" - pub fn type(number) {{ - let a = number {op} {arg}; - let b = number.field {op} {arg}; - let c = number.derived {op} {arg}; - let d = number.custom {op} {arg}; - (a, b, c, d) - }} - "#, op = stringify!($($op)*), arg = stringify!($arg)); + let source = format!("pub fn type(number) {{ number {op} {arg} }}", op = stringify!($($op)*), arg = stringify!($arg)); let mut sources = Sources::new(); sources.insert(Source::memory(source)?)?; @@ -233,21 +210,12 @@ fn struct_ops() -> Result<()> { let mut vm = Vm::new(Arc::new(context.runtime()?), unit); - let mut foo = External::default(); - foo.value = $initial; - foo.field = $initial; - foo.derived = $initial; - foo.custom = $initial; - - let output = vm.call(["type"], (&mut foo,))?; - let (a, b, c, d) = crate::from_value::<(i64, i64, i64, i64)>(output)?; + let foo = External { value: $initial }; + let output = vm.call(["type"], (foo,))?; + let value = crate::from_value::(output)?; let expected: i64 = $expected; - - assert_eq!(a, expected, "{a} != {expected} (value)"); - assert_eq!(b, expected, "{b} != {expected} (field)"); - assert_eq!(c, expected, "{c} != {expected} (derived)"); - assert_eq!(d, expected, "{d} != {expected} (custom)"); + assert_eq!(value, expected, "{value} != {expected} (value)"); }}; } @@ -264,6 +232,61 @@ fn struct_ops() -> Result<()> { Ok(()) } +#[test] +fn struct_unary() -> Result<()> { + macro_rules! test_case { + ([$($op:tt)*], $protocol:ident, $derived:tt, $ty:ty, $initial:literal, $expected:expr) => {{ + #[derive(Debug, Any)] + struct External { + value: $ty, + } + + impl External { + fn value(&self) -> External { + External { + value: $($op)*self.value, + } + } + } + + let mut module = Module::new(); + module.ty::()?; + module.associated_function(&Protocol::$protocol, External::value)?; + + let mut context = Context::default(); + context.install(module)?; + + let source = format!("pub fn type(value) {{ {op} value }}", op = stringify!($($op)*)); + + let mut sources = Sources::new(); + sources.insert(Source::memory(source)?)?; + + let unit = prepare(&mut sources) + .with_context(&context) + .build()?; + + let unit = Arc::new(unit); + + let mut vm = Vm::new(Arc::new(context.runtime()?), unit); + + let external = External { value: $initial }; + + let output = vm.call(["type"], (external,))?; + let External { value: actual } = crate::from_value(output)?; + + let expected: $ty = $expected; + assert_eq!(actual, expected); + }}; + } + + test_case!([-], NEG, neg, i64, 100, -100); + test_case!([-], NEG, neg, f64, 100.0, -100.0); + test_case!([!], NOT, not, i64, 100, !100); + test_case!([!], NOT, not, u64, 100, !100); + test_case!([!], NOT, not, bool, true, false); + Ok(()) +} + #[test] fn ordering_struct() -> Result<()> { macro_rules! test_case { diff --git a/crates/rune/src/tests/getter_setter.rs b/crates/rune/src/tests/getter_setter.rs index 9d0123581..a5dbb77ab 100644 --- a/crates/rune/src/tests/getter_setter.rs +++ b/crates/rune/src/tests/getter_setter.rs @@ -1,13 +1,17 @@ prelude!(); +use crate::alloc::String; + use std::sync::Arc; -#[derive(Any, Debug, Default)] +#[derive(Any, Debug)] struct Foo { #[rune(get, set, copy)] number: i64, #[rune(get, set)] string: String, + #[rune(get, set)] + shared_string: Shared, } #[test] @@ -23,6 +27,8 @@ fn test_getter_setter() -> Result<()> { pub fn main(foo) { foo.number = foo.number + 1; foo.string = format!("{} World", foo.string); + foo.shared_string = format!("{} Shared World", foo.shared_string); + foo.shared_string } } }; @@ -33,14 +39,17 @@ fn test_getter_setter() -> Result<()> { let mut foo = Foo { number: 42, - string: String::from("Hello"), + string: String::try_from("Hello")?, + shared_string: Shared::new(String::try_from("Hello")?)?, }; let output = vm.call(["main"], (&mut foo,))?; assert_eq!(foo.number, 43); assert_eq!(foo.string, "Hello World"); + assert_eq!(&*foo.shared_string.borrow_ref()?, "Hello Shared World"); - output.into_unit().unwrap(); + let string = output.downcast::().unwrap(); + assert_eq!(string, "Hello Shared World"); Ok(()) } diff --git a/crates/rune/src/tests/reference_error.rs b/crates/rune/src/tests/reference_error.rs index c6f09e1c4..1a11c1039 100644 --- a/crates/rune/src/tests/reference_error.rs +++ b/crates/rune/src/tests/reference_error.rs @@ -10,9 +10,7 @@ fn test_reference_error() -> Result<()> { } // NB: Calling this should error, since it's a mutable reference. - fn take_it(_: Ref) -> VmResult<()> { - VmResult::Ok(()) - } + fn take_it(_: Ref) {} let mut module = Module::new(); module.function("take_it", take_it).build()?; diff --git a/crates/rune/src/tests/vm_closures.rs b/crates/rune/src/tests/vm_closures.rs index ca278b63f..be98bedca 100644 --- a/crates/rune/src/tests/vm_closures.rs +++ b/crates/rune/src/tests/vm_closures.rs @@ -1,27 +1,27 @@ prelude!(); #[test] -fn test_closure_in_lit_vec() -> VmResult<()> { +fn test_closure_in_lit_vec() -> Result<()> { let ret: VecTuple<(i64, Function, Function, i64)> = eval(r#"let a = 4; [0, || 2, || 4, 3]"#); let (start, first, second, end) = ret.0; assert_eq!(0, start); - assert_eq!(2, vm_try!(first.call::(()))); - assert_eq!(4, vm_try!(second.call::(()))); + assert_eq!(2, first.call::(())?); + assert_eq!(4, second.call::(())?); assert_eq!(3, end); - VmResult::Ok(()) + Ok(()) } #[test] -fn test_closure_in_lit_tuple() -> VmResult<()> { +fn test_closure_in_lit_tuple() -> Result<()> { let ret: (i64, Function, Function, i64) = eval(r#"let a = 4; (0, || 2, || a, 3)"#); let (start, first, second, end) = ret; assert_eq!(0, start); - assert_eq!(2, vm_try!(first.call::(()))); - assert_eq!(4, vm_try!(second.call::(()))); + assert_eq!(2, first.call::(())?); + assert_eq!(4, second.call::(())?); assert_eq!(3, end); - VmResult::Ok(()) + Ok(()) } #[test] @@ -37,8 +37,8 @@ fn test_closure_in_lit_object() -> Result<()> { let proxy: Proxy = eval("let a = 4; #{a: 0, b: || 2, c: || a, d: 3}"); assert_eq!(0, proxy.a); - assert_eq!(2, proxy.b.call::(()).into_result()?); - assert_eq!(4, proxy.c.call::(()).into_result()?); + assert_eq!(2, proxy.b.call::(())?); + assert_eq!(4, proxy.c.call::(())?); 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 ad84bb2f1..f961d518c 100644 --- a/crates/rune/src/tests/vm_function.rs +++ b/crates/rune/src/tests/vm_function.rs @@ -27,7 +27,7 @@ fn test_function() { Custom::A }; - assert!(function.call::(()).into_result().is_err()); + assert!(function.call::(()).is_err()); let value: Value = function.call((1i64,)).unwrap(); assert!(rune::from_value::(value).is_ok()); @@ -37,7 +37,7 @@ fn test_function() { Custom }; - assert!(function.call::(()).into_result().is_err()); + assert!(function.call::(()).is_err()); let value: Value = function.call((1i64,)).unwrap(); assert!(crate::from_value::(value).is_ok()); @@ -46,7 +46,7 @@ fn test_function() { |a, b| a + b }; - assert!(function.call::((1i64,)).into_result().is_err()); + assert!(function.call::((1i64,)).is_err()); let value: Value = function.call((1i64, 2i64)).unwrap(); assert_eq!(value.as_signed().unwrap(), 3); @@ -59,7 +59,7 @@ fn test_function() { ) .unwrap(); - assert!(function.call::((1i64,)).into_result().is_err()); + assert!(function.call::((1i64,)).is_err()); let value: Value = function.call(()).unwrap(); assert_eq!(value.as_signed().unwrap(), 3); } diff --git a/crates/rune/src/worker/mod.rs b/crates/rune/src/worker/mod.rs index 979049274..8055c8656 100644 --- a/crates/rune/src/worker/mod.rs +++ b/crates/rune/src/worker/mod.rs @@ -186,7 +186,7 @@ impl<'a, 'arena> Worker<'a, 'arena> { }}; } - let as_function_body = self.q.options.function_body && !is_module; + let as_function_body = self.q.options.script && !is_module; #[allow(clippy::collapsible_else_if)] if self.q.options.v2 { diff --git a/crates/rune/src/workspace/error.rs b/crates/rune/src/workspace/error.rs index 1de5423ee..c1cf34480 100644 --- a/crates/rune/src/workspace/error.rs +++ b/crates/rune/src/workspace/error.rs @@ -18,7 +18,7 @@ pub struct WorkspaceError { impl WorkspaceError { /// Construct a new workspace error with the given span and kind. - #[allow(unused)] + #[inline] pub(crate) fn new(spanned: S, kind: K) -> Self where S: Spanned, @@ -31,6 +31,7 @@ impl WorkspaceError { } /// Construct a custom message as an error. + #[inline] pub fn msg(spanned: S, message: M) -> Self where S: Spanned, @@ -60,16 +61,19 @@ impl core::error::Error for WorkspaceError { } impl fmt::Display for WorkspaceError { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.kind, f) } } impl WorkspaceError { + #[inline] pub(crate) fn missing_field(span: Span, field: &'static str) -> Self { Self::new(span, WorkspaceErrorKind::MissingField { field }) } + #[inline] pub(crate) fn expected_array(span: Span) -> Self { Self::new(span, WorkspaceErrorKind::ExpectedArray) } @@ -80,6 +84,7 @@ where S: Spanned, WorkspaceErrorKind: From, { + #[inline] fn from(spanned: HasSpan) -> Self { Self::new(spanned.span(), spanned.into_inner()) } @@ -125,6 +130,7 @@ pub(crate) enum WorkspaceErrorKind { } impl core::error::Error for WorkspaceErrorKind { + #[inline] fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { WorkspaceErrorKind::GlobError { error, .. } => Some(error), @@ -137,6 +143,7 @@ impl core::error::Error for WorkspaceErrorKind { } impl fmt::Display for WorkspaceErrorKind { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { WorkspaceErrorKind::Custom { error } => error.fmt(f), @@ -175,32 +182,35 @@ impl fmt::Display for WorkspaceErrorKind { } impl From for WorkspaceErrorKind { + #[inline] fn from(error: anyhow::Error) -> Self { WorkspaceErrorKind::Custom { error } } } impl From for WorkspaceErrorKind { - #[allow(deprecated)] + #[inline] fn from(error: toml::de::Error) -> Self { WorkspaceErrorKind::Toml { error } } } impl From for WorkspaceErrorKind { - #[allow(deprecated)] + #[inline] fn from(error: serde_hashkey::Error) -> Self { WorkspaceErrorKind::Key { error } } } impl From for WorkspaceError { + #[inline] fn from(error: alloc::Error) -> Self { WorkspaceError::new(Span::empty(), error) } } impl From for WorkspaceErrorKind { + #[inline] fn from(error: alloc::Error) -> Self { WorkspaceErrorKind::AllocError { error } } diff --git a/examples/examples/checked_add_assign.rs b/examples/examples/checked_add_assign.rs index 86c76bf3f..9657f9fc9 100644 --- a/examples/examples/checked_add_assign.rs +++ b/examples/examples/checked_add_assign.rs @@ -1,4 +1,4 @@ -use rune::runtime::{VmError, VmResult}; +use rune::runtime::VmError; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, ContextError, Diagnostics, Module, Vm}; @@ -12,9 +12,12 @@ struct External { #[allow(clippy::unnecessary_lazy_evaluations)] impl External { - fn value_add_assign(&mut self, other: i64) -> VmResult<()> { - self.value = rune::vm_try!(self.value.checked_add(other).ok_or_else(VmError::overflow)); - VmResult::Ok(()) + fn value_add_assign(&mut self, other: i64) -> Result<(), VmError> { + self.value = self + .value + .checked_add(other) + .ok_or_else(VmError::overflow)?; + Ok(()) } } diff --git a/examples/examples/custom_instance_fn.rs b/examples/examples/custom_instance_fn.rs index ec26a2fc2..486905d27 100644 --- a/examples/examples/custom_instance_fn.rs +++ b/examples/examples/custom_instance_fn.rs @@ -37,7 +37,7 @@ async fn main() -> rune::support::Result<()> { let unit = result?; let mut vm = Vm::new(runtime, Arc::new(unit)); - let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; + let output = vm.execute(["main"], (33i64,))?.complete()?; let output: i64 = rune::from_value(output)?; println!("output: {}", output); diff --git a/examples/examples/lookup_function.rs b/examples/examples/lookup_function.rs index 55cd9cae0..88e449b61 100644 --- a/examples/examples/lookup_function.rs +++ b/examples/examples/lookup_function.rs @@ -26,13 +26,13 @@ fn main() -> rune::support::Result<()> { // Looking up an item from the source. let dynamic_max = vm.lookup_function(["max"])?; - let value = dynamic_max.call::((10, 20)).into_result()?; + let value = dynamic_max.call::((10, 20))?; assert_eq!(value, 20); let item = rune::item!(::std::i64::max); let max = vm.lookup_function(item)?; - let value = max.call::((10, 20)).into_result()?; + let value = max.call::((10, 20))?; assert_eq!(value, 20); Ok(()) } diff --git a/examples/examples/minimal.rs b/examples/examples/minimal.rs index c2626d40e..37855d792 100644 --- a/examples/examples/minimal.rs +++ b/examples/examples/minimal.rs @@ -29,7 +29,7 @@ fn main() -> rune::support::Result<()> { let unit = result?; let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); - let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; + let output = vm.execute(["main"], (33i64,))?.complete()?; let output: i64 = rune::from_value(output)?; println!("output: {}", output); diff --git a/examples/examples/parsing_in_macro.rs b/examples/examples/parsing_in_macro.rs index 8f1ecdad2..25508cd9e 100644 --- a/examples/examples/parsing_in_macro.rs +++ b/examples/examples/parsing_in_macro.rs @@ -38,7 +38,7 @@ pub fn main() -> rune::support::Result<()> { let unit = result?; let mut vm = Vm::new(runtime, Arc::new(unit)); - let output = vm.execute(["main"], ())?.complete().into_result()?; + let output = vm.execute(["main"], ())?.complete()?; let output: (u32, u32) = rune::from_value(output)?; println!("{:?}", output); diff --git a/examples/examples/proxy.rs b/examples/examples/proxy.rs index 84ef60dde..02ec20d88 100644 --- a/examples/examples/proxy.rs +++ b/examples/examples/proxy.rs @@ -47,10 +47,7 @@ fn main() -> rune::support::Result<()> { let input = MyBytes { bytes: vec![77, 77, 77, 77], }; - let output = vm - .execute(["passthrough"], (input,))? - .complete() - .into_result()?; + let output = vm.execute(["passthrough"], (input,))?.complete()?; let mut output: Proxy = rune::from_value(output)?; println!("field: {:?}", output.field); diff --git a/examples/examples/rune_function.rs b/examples/examples/rune_function.rs index 6e333969f..164460d8a 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::((1, 3)).into_result()?); - println!("{}", output.call::((2, 6)).into_result()?); + println!("{}", output.call::((1, 3))?); + println!("{}", output.call::((2, 6))?); Ok(()) } diff --git a/examples/examples/tokio_spawn.rs b/examples/examples/tokio_spawn.rs index 67c87c746..4c7282269 100644 --- a/examples/examples/tokio_spawn.rs +++ b/examples/examples/tokio_spawn.rs @@ -35,13 +35,13 @@ async fn main() -> rune::support::Result<()> { let execution = vm.try_clone()?.send_execute(["main"], (5u32,))?; let t1 = tokio::spawn(async move { - execution.async_complete().await.unwrap(); + execution.complete().await.unwrap(); println!("timer ticked"); }); let execution = vm.try_clone()?.send_execute(["main"], (2u32,))?; let t2 = tokio::spawn(async move { - execution.async_complete().await.unwrap(); + execution.complete().await.unwrap(); println!("timer ticked"); }); diff --git a/examples/examples/vec_args.rs b/examples/examples/vec_args.rs index 36fef395a..9a6415e9a 100644 --- a/examples/examples/vec_args.rs +++ b/examples/examples/vec_args.rs @@ -1,5 +1,5 @@ use rune::alloc::Vec; -use rune::runtime::{Function, VmResult}; +use rune::runtime::{Function, VmError}; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{ContextError, Diagnostics, Module, Value, Vm}; @@ -51,7 +51,7 @@ fn module() -> Result { m.function( "pass_along", - |func: Function, args: Vec| -> VmResult { func.call(args) }, + |func: Function, args: Vec| -> Result { func.call(args) }, ) .build()?; diff --git a/no-std/examples/minimal.rs b/no-std/examples/minimal.rs index b7bc7d43d..0bd5cce66 100644 --- a/no-std/examples/minimal.rs +++ b/no-std/examples/minimal.rs @@ -85,7 +85,7 @@ fn inner_main() -> rune::support::Result { let unit = result?; let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); - let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; + let output = vm.execute(["main"], (33i64,))?.complete()?; let output: i32 = rune::from_value(output)?; Ok((output != 43).into()) } diff --git a/scripts/rand.rn b/scripts/rand.rn index 20a9d1291..d60e33347 100644 --- a/scripts/rand.rn +++ b/scripts/rand.rn @@ -1,11 +1,15 @@ -let rng = rand::WyRand::new(); -let rand_int = rng.int(); -println!("Random int: {}", rand_int); -let rand_int_range = rng.int_range(-100, 100); -println!("Random int between -100 and 100: {}", rand_int_range); +let rng = rand::SmallRng::try_from_os_rng()?; +let v = rng.random::(); +println!("Random u64: {v}"); +let v = rng.random_range::(-100..100); +println!("Random i64 in range: {v}"); +let v = rng.random::(); +println!("Random char: {v:?}"); -let rng = rand::Pcg64::new(); -let rand_int = rng.int(); -println!("Random int: {}", rand_int); -let rand_int_range = rng.int_range(-100, 100); -println!("Random int between -100 and 100: {}", rand_int_range); +let rng = rand::StdRng::try_from_os_rng()?; +let v = rng.random::(); +println!("Random u64: {v}"); +let v = rng.random_range::(-100..100); +println!("Random i64 in range: {v}"); +let v = rng.random_range::('a'..'z'); +println!("Random char between 'a' and 'z': {v:?}");