From e4c252d48e30b1e70e3cb585fa80c451b8ac6477 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Fri, 1 Nov 2024 04:59:11 +0100 Subject: [PATCH] rune: Store Generator and Stream in AnyObj instead of Mutable (relates #844) --- crates/rune-macros/src/any.rs | 131 +++++++-------- crates/rune-macros/src/context.rs | 6 +- crates/rune-macros/src/internals.rs | 1 - crates/rune/src/modules/generator.rs | 13 -- crates/rune/src/modules/mod.rs | 1 - crates/rune/src/modules/ops/generator.rs | 201 +++++++++++++++++++---- crates/rune/src/modules/stream.rs | 13 +- crates/rune/src/runtime/generator.rs | 22 ++- crates/rune/src/runtime/static_type.rs | 4 - crates/rune/src/runtime/stream.rs | 164 ++++++++++++++++-- crates/rune/src/runtime/value.rs | 46 +----- crates/rune/src/runtime/value/serde.rs | 2 - 12 files changed, 400 insertions(+), 204 deletions(-) delete mode 100644 crates/rune/src/modules/generator.rs diff --git a/crates/rune-macros/src/any.rs b/crates/rune-macros/src/any.rs index d1828834f..d96d718c7 100644 --- a/crates/rune-macros/src/any.rs +++ b/crates/rune-macros/src/any.rs @@ -553,12 +553,29 @@ where .. } = &tokens; - let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); + let empty; + let mut current; + let generic_names; - let generic_names = if attr.static_type.is_some() { - vec![] - } else { - generics.type_params().map(|v| &v.ident).collect::>() + 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 impl_named = if let [first_name, remainder @ ..] = &generic_names[..] { @@ -720,85 +737,51 @@ where } }); - let impl_from_value = 'out: { - if let Some(path) = attr.from_value { - let ty = match &attr.from_value_params { - Some(params) => quote!(#ident<#params>), - None if generics.params.is_empty() => quote!(#ident), - _ => break 'out None, - }; - - Some(quote! { - impl #from_value for #ty { - fn from_value(value: Value) -> #result { - #path(value) - } + let impl_from_value = attr.from_value.as_ref().map(|path| { + quote! { + impl #impl_generics #from_value for #ident #type_generics { + fn from_value(value: #value) -> #result { + #path(value) } - }) - } else { - None + } } - }; - - let impl_from_value_ref = 'out: { - if let Some(path) = attr.from_value_ref { - let ty = match &attr.from_value_params { - Some(params) => quote!(#ident<#params>), - None if generics.params.is_empty() => quote!(#ident), - _ => break 'out None, - }; - - Some(quote! { - impl #unsafe_to_ref for #ty { - type Guard = #raw_any_guard; + }); - unsafe fn unsafe_to_ref<'a>(value: #value) -> #vm_result<(&'a Self, Self::Guard)> { - let value = #vm_try!(#path(value)); - let (value, guard) = #ref_::into_raw(value); - #vm_result::Ok((value.as_ref(), guard)) - } - } + let impl_from_value_ref = attr.from_value_ref.as_ref().map(|path| quote! { + impl #impl_generics #unsafe_to_ref for #ident #type_generics { + type Guard = #raw_any_guard; - impl #from_value for #ref_<#ty> { - fn from_value(value: #value) -> #result { - #path(value) - } - } - }) - } else { - None + unsafe fn unsafe_to_ref<'a>(value: #value) -> #vm_result<(&'a Self, Self::Guard)> { + let value = #vm_try!(#path(value)); + let (value, guard) = #ref_::into_raw(value); + #vm_result::Ok((value.as_ref(), guard)) + } } - }; - let impl_from_value_mut = 'out: { - if let Some(path) = attr.from_value_mut { - let ty = match &attr.from_value_params { - Some(params) => quote!(#ident<#params>), - None if generics.params.is_empty() => quote!(#ident), - _ => break 'out None, - }; + impl #impl_generics #from_value for #ref_<#ident #type_generics> { + fn from_value(value: #value) -> #result { + #path(value) + } + } + }); - Some(quote! { - impl #unsafe_to_mut for #ty { - type Guard = #raw_any_guard; + let impl_from_value_mut = attr.from_value_mut.as_ref().map(|path| quote! { + impl #impl_generics #unsafe_to_mut for #ident #type_generics { + type Guard = #raw_any_guard; - unsafe fn unsafe_to_mut<'a>(value: #value) -> #vm_result<(&'a mut Self, Self::Guard)> { - let value = #vm_try!(#path(value)); - let (mut value, guard) = #mut_::into_raw(value); - #vm_result::Ok((value.as_mut(), guard)) - } - } + unsafe fn unsafe_to_mut<'a>(value: #value) -> #vm_result<(&'a mut Self, Self::Guard)> { + let value = #vm_try!(#path(value)); + let (mut value, guard) = #mut_::into_raw(value); + #vm_result::Ok((value.as_mut(), guard)) + } + } - impl #from_value for #mut_<#ty> { - fn from_value(value: #value) -> #result { - #path(value) - } - } - }) - } else { - None + impl #impl_generics #from_value for #mut_<#ident #type_generics> { + fn from_value(value: #value) -> #result { + #path(value) + } } - }; + }); quote! { #install_with diff --git a/crates/rune-macros/src/context.rs b/crates/rune-macros/src/context.rs index cd3b8158a..c8571c2f0 100644 --- a/crates/rune-macros/src/context.rs +++ b/crates/rune-macros/src/context.rs @@ -98,7 +98,7 @@ pub(crate) struct TypeAttr { /// Method to use to convert from value mut. pub(crate) from_value_mut: Option, /// Method to use to convert from value. - pub(crate) from_value_params: Option>, + pub(crate) impl_params: Option>, } /// Parsed #[const_value(..)] field attributes. @@ -610,11 +610,11 @@ impl Context { } else if meta.path == FROM_VALUE_MUT { meta.input.parse::()?; attr.from_value_mut = Some(meta.input.parse()?); - } else if meta.path == FROM_VALUE_PARAMS { + } else if meta.path.is_ident("impl_params") { meta.input.parse::()?; let content; syn::bracketed!(content in meta.input); - attr.from_value_params = + attr.impl_params = Some(syn::punctuated::Punctuated::parse_terminated(&content)?); } else { return Err(syn::Error::new_spanned( diff --git a/crates/rune-macros/src/internals.rs b/crates/rune-macros/src/internals.rs index 91bb39db7..6ccbfeac3 100644 --- a/crates/rune-macros/src/internals.rs +++ b/crates/rune-macros/src/internals.rs @@ -28,7 +28,6 @@ pub const STATIC_TYPE: Symbol = Symbol("static_type"); pub const FROM_VALUE: Symbol = Symbol("from_value"); pub const FROM_VALUE_REF: Symbol = Symbol("from_value_ref"); pub const FROM_VALUE_MUT: Symbol = Symbol("from_value_mut"); -pub const FROM_VALUE_PARAMS: Symbol = Symbol("from_value_params"); pub const GET: Symbol = Symbol("get"); pub const SET: Symbol = Symbol("set"); pub const COPY: Symbol = Symbol("copy"); diff --git a/crates/rune/src/modules/generator.rs b/crates/rune/src/modules/generator.rs deleted file mode 100644 index 6436a5cec..000000000 --- a/crates/rune/src/modules/generator.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Generators. - -use crate as rune; -use crate::{ContextError, Module}; - -/// Generators. -/// -/// Generator functionality has been moved into [::std::ops]. -#[deprecated = "Generators have been moved into std::ops"] -#[rune::module(::std::generator)] -pub fn module() -> Result { - Module::from_meta(self::module_meta) -} diff --git a/crates/rune/src/modules/mod.rs b/crates/rune/src/modules/mod.rs index 0297686b2..88817ae25 100644 --- a/crates/rune/src/modules/mod.rs +++ b/crates/rune/src/modules/mod.rs @@ -28,7 +28,6 @@ pub mod disable_io; pub mod f64; pub mod fmt; pub mod future; -pub mod generator; pub mod hash; pub mod i64; pub mod io; diff --git a/crates/rune/src/modules/ops/generator.rs b/crates/rune/src/modules/ops/generator.rs index fc372debc..3c8d0917c 100644 --- a/crates/rune/src/modules/ops/generator.rs +++ b/crates/rune/src/modules/ops/generator.rs @@ -1,8 +1,10 @@ //! Overloadable operators and associated types. use crate as rune; +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; use crate::runtime::generator::Iter; -use crate::runtime::{EnvProtocolCaller, Generator, GeneratorState, Value, VmResult}; +use crate::runtime::{EnvProtocolCaller, Formatter, Generator, GeneratorState, Value, VmResult}; use crate::{ContextError, Module}; /// Types related to generators. @@ -11,31 +13,14 @@ pub fn module() -> Result { let mut m = Module::from_meta(self::module_meta)?; { - m.ty::()?.docs(docstring! { - /// A generator produced by a generator function. - /// - /// Generator are functions or closures which contain the `yield` - /// expressions. - /// - /// # Examples - /// - /// ```rune - /// use std::ops::generator::Generator; - /// - /// let f = |n| { - /// yield n; - /// yield n + 1; - /// }; - /// - /// let g = f(10); - /// - /// assert!(g is Generator); - /// ``` - })?; - m.function_meta(generator_next)?; - m.function_meta(generator_resume)?; - m.function_meta(generator_iter)?; - m.function_meta(generator_into_iter)?; + m.ty::()?; + m.function_meta(generator_next__meta)?; + m.function_meta(generator_resume__meta)?; + m.function_meta(generator_iter__meta)?; + m.function_meta(generator_into_iter__meta)?; + m.function_meta(generator_debug__meta)?; + m.function_meta(generator_clone__meta)?; + m.implement_trait::(rune::item!(::std::clone::Clone))?; m.ty::()?.docs(docstring! { /// An iterator over a generator. @@ -49,11 +34,13 @@ pub fn module() -> Result { /// Enum indicating the state of a generator. })?; - m.function_meta(generator_state_partial_eq)?; + m.function_meta(generator_state_partial_eq__meta)?; m.implement_trait::(rune::item!(::std::cmp::PartialEq))?; - - m.function_meta(generator_state_eq)?; + m.function_meta(generator_state_eq__meta)?; m.implement_trait::(rune::item!(::std::cmp::Eq))?; + m.function_meta(generator_state_debug__meta)?; + m.function_meta(generator_state_clone__meta)?; + m.implement_trait::(rune::item!(::std::clone::Clone))?; } Ok(m) @@ -79,12 +66,36 @@ pub fn module() -> Result { /// assert_eq!(g.next(), Some(2)); /// assert_eq!(g.next(), None); /// `` -#[rune::function(instance, path = next)] +#[rune::function(keep, instance, path = next)] fn generator_next(this: &mut Generator) -> VmResult> { this.next() } -/// Advance a generator producing the next [`GeneratorState`]. +/// Resumes the execution of this generator. +/// +/// This function will resume execution of the generator or start execution if +/// it hasn't already. This call will return back into the generator's last +/// suspension point, resuming execution from the latest `yield`. The generator +/// will continue executing until it either yields or returns, at which point +/// this function will return. +/// +/// # Return value +/// +/// The `GeneratorState` enum returned from this function indicates what state +/// the generator is in upon returning. If the `Yielded` variant is returned +/// then the generator has reached a suspension point and a value has been +/// yielded out. Generators in this state are available for resumption at a +/// later point. +/// +/// If `Complete` is returned then the generator has completely finished with +/// the value provided. It is invalid for the generator to be resumed again. +/// +/// # Panics +/// +/// This function may panic if it is called after the `Complete` variant has +/// been returned previously. While generator literals in the language are +/// guaranteed to panic on resuming after `Complete`, this is not guaranteed for +/// all implementations of the `Generator`. /// /// # Examples /// @@ -102,7 +113,7 @@ fn generator_next(this: &mut Generator) -> VmResult> { /// assert_eq!(g.resume(1), GeneratorState::Yielded(3)); /// assert_eq!(g.resume(()), GeneratorState::Complete(())); /// `` -#[rune::function(instance, path = resume)] +#[rune::function(keep, instance, path = resume)] fn generator_resume(this: &mut Generator, value: Value) -> VmResult { this.resume(value) } @@ -121,18 +132,88 @@ fn generator_resume(this: &mut Generator, value: Value) -> VmResult(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// assert_eq!(count_numbers(Some(2)).iter().collect::(), [0, 1]); /// ``` -#[rune::function(instance, path = iter)] +#[rune::function(keep, instance, path = iter)] #[inline] fn generator_iter(this: Generator) -> Iter { this.rune_iter() } -#[rune::function(instance, protocol = INTO_ITER)] +/// Construct an iterator over a generator. +/// +/// # Examples +/// +/// ```rune +/// fn count_numbers(limit) { +/// for n in 0..limit { +/// yield n; +/// } +/// } +/// +/// let result = 0; +/// +/// for n in count_numbers(3) { +/// result += n; +/// } +/// +/// assert_eq!(result, 3); +/// ``` +#[rune::function(keep, instance, protocol = INTO_ITER)] #[inline] fn generator_into_iter(this: Generator) -> Iter { this.rune_iter() } +/// Debug print this generator. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::GeneratorState; +/// +/// fn generate() { +/// let n = yield 1; +/// yield 2 + n; +/// } +/// +/// let a = generate(); +/// +/// println!("{a:?}"); +/// `` +#[rune::function(keep, instance, protocol = STRING_DEBUG)] +fn generator_debug(this: &Generator, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{this:?}") +} + +/// Clone a generator. +/// +/// This clones the state of the generator too, allowing it to be resumed +/// independently. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::GeneratorState; +/// +/// fn generate() { +/// let n = yield 1; +/// yield 2 + n; +/// } +/// +/// let a = generate(); +/// +/// assert_eq!(a.resume(()), GeneratorState::Yielded(1)); +/// let b = a.clone(); +/// assert_eq!(a.resume(2), GeneratorState::Yielded(4)); +/// assert_eq!(b.resume(3), GeneratorState::Yielded(5)); +/// +/// assert_eq!(a.resume(()), GeneratorState::Complete(())); +/// 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())) +} + /// Test for partial equality over a generator state. /// /// # Examples @@ -151,7 +232,7 @@ fn generator_into_iter(this: Generator) -> Iter { /// assert_eq!(g.resume(1), GeneratorState::Yielded(3)); /// assert_eq!(g.resume(()), GeneratorState::Complete(())); /// `` -#[rune::function(instance, protocol = PARTIAL_EQ)] +#[rune::function(keep, instance, protocol = PARTIAL_EQ)] fn generator_state_partial_eq(this: &GeneratorState, other: &GeneratorState) -> VmResult { this.partial_eq_with(other, &mut EnvProtocolCaller) } @@ -175,7 +256,55 @@ fn generator_state_partial_eq(this: &GeneratorState, other: &GeneratorState) -> /// assert!(eq(g.resume(1), GeneratorState::Yielded(3))); /// assert!(eq(g.resume(()), GeneratorState::Complete(()))); /// `` -#[rune::function(instance, protocol = EQ)] +#[rune::function(keep, instance, protocol = EQ)] fn generator_state_eq(this: &GeneratorState, other: &GeneratorState) -> VmResult { this.eq_with(other, &mut EnvProtocolCaller) } + +/// Debug print this generator state. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::GeneratorState; +/// +/// let a = GeneratorState::Yielded(1); +/// let b = GeneratorState::Complete(()); +/// +/// println!("{a:?}"); +/// println!("{b:?}"); +/// `` +#[rune::function(keep, instance, protocol = STRING_DEBUG)] +fn generator_state_debug(this: &GeneratorState, f: &mut Formatter) -> VmResult<()> { + match this { + GeneratorState::Yielded(value) => { + vm_try!(vm_write!(f, "Yielded(")); + vm_try!(value.string_debug_with(f, &mut EnvProtocolCaller)); + vm_try!(vm_write!(f, ")")); + } + GeneratorState::Complete(value) => { + vm_try!(vm_write!(f, "Complete(")); + vm_try!(value.string_debug_with(f, &mut EnvProtocolCaller)); + vm_try!(vm_write!(f, ")")); + } + } + + VmResult::Ok(()) +} + +/// Clone a generator state. +/// +/// # Examples +/// +/// ```rune +/// use std::ops::GeneratorState; +/// +/// let a = GeneratorState::Yielded(1); +/// let b = a.clone(); +/// +/// assert_eq!(a, b); +/// `` +#[rune::function(keep, instance, protocol = CLONE)] +fn generator_state_clone(this: &GeneratorState) -> VmResult { + VmResult::Ok(vm_try!(this.try_clone())) +} diff --git a/crates/rune/src/modules/stream.rs b/crates/rune/src/modules/stream.rs index 3f7fc6bb7..c576978fb 100644 --- a/crates/rune/src/modules/stream.rs +++ b/crates/rune/src/modules/stream.rs @@ -7,9 +7,12 @@ use crate::{ContextError, Module}; /// Asynchronous streams. #[rune::module(::std::stream)] pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta)?; - module.ty::()?; - module.associated_function("next", Stream::next_shared)?; - module.associated_function("resume", Stream::resume_shared)?; - Ok(module) + 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)?; + m.function_meta(Stream::debug__meta)?; + m.function_meta(Stream::clone__meta)?; + m.implement_trait::(rune::item!(::std::clone::Clone))?; + Ok(m) } diff --git a/crates/rune/src/runtime/generator.rs b/crates/rune/src/runtime/generator.rs index 6a094eba4..dc9ee71fd 100644 --- a/crates/rune/src/runtime/generator.rs +++ b/crates/rune/src/runtime/generator.rs @@ -6,28 +6,26 @@ use crate::alloc::clone::TryClone; use crate::runtime::{GeneratorState, Value, Vm, VmError, VmErrorKind, VmExecution, VmResult}; use crate::Any; -/// The return value of a function producing a generator. +/// A generator produced by a generator function. /// -/// Functions which contain the `yield` keyword produces generators. +/// Generator are functions or closures which contain the `yield` expressions. /// /// # Examples /// /// ```rune /// use std::ops::generator::Generator; /// -/// fn generate() { -/// yield 1; -/// yield 2; -/// } +/// let f = |n| { +/// yield n; +/// yield n + 1; +/// }; /// -/// let g = generate(); -/// assert!(g is Generator) +/// let g = f(10); +/// +/// assert!(g is Generator); /// ``` #[derive(Any)] -#[rune(crate)] -#[rune(builtin, static_type = GENERATOR, from_value_params = [Vm])] -#[rune(from_value = Value::into_generator, from_value_ref = Value::into_generator_ref, from_value_mut = Value::into_generator_mut)] -#[rune(item = ::std::ops::generator)] +#[rune(crate, impl_params = [Vm], item = ::std::ops::generator)] pub struct Generator where T: AsRef + AsMut, diff --git a/crates/rune/src/runtime/static_type.rs b/crates/rune/src/runtime/static_type.rs index 3ea92086e..28330326e 100644 --- a/crates/rune/src/runtime/static_type.rs +++ b/crates/rune/src/runtime/static_type.rs @@ -192,10 +192,6 @@ static_type! { pub(crate) static [FUTURE, FUTURE_HASH] = ::std::future::Future {} - pub(crate) static [GENERATOR, GENERATOR_HASH] = ::std::ops::generator::Generator {} - - pub(crate) static [STREAM, STREAM_HASH] = ::std::stream::Stream {} - pub(crate) static [RESULT, RESULT_HASH] = ::std::result::Result { impl for Result; } diff --git a/crates/rune/src/runtime/stream.rs b/crates/rune/src/runtime/stream.rs index aec0e9c86..855cfc561 100644 --- a/crates/rune/src/runtime/stream.rs +++ b/crates/rune/src/runtime/stream.rs @@ -1,15 +1,34 @@ use core::fmt; +use crate as rune; use crate::alloc::clone::TryClone; -use crate::runtime::{GeneratorState, Mut, Value, Vm, VmErrorKind, VmExecution, VmResult}; +use crate::alloc::fmt::TryWrite; +use crate::runtime::{ + Formatter, GeneratorState, Mut, Value, Vm, VmErrorKind, VmExecution, VmResult, +}; use crate::Any; -/// A stream with a stored virtual machine. +/// A stream produced by an async generator function. +/// +/// Generator are async functions or closures which contain the `yield` +/// expressions. +/// +/// # Examples +/// +/// ```rune +/// use std::stream::Stream; +/// +/// let f = async |n| { +/// yield n; +/// yield n + 1; +/// }; +/// +/// let g = f(10); +/// +/// assert!(g is Stream); +/// ``` #[derive(Any)] -#[rune(crate)] -#[rune(builtin, static_type = STREAM, from_value_params = [Vm])] -#[rune(from_value = Value::into_stream, from_value_ref = Value::into_stream_ref, from_value_mut = Value::into_stream_mut)] -#[rune(item = ::std::stream)] +#[rune(impl_params = [Vm], item = ::std::stream)] pub struct Stream where T: AsRef + AsMut, @@ -56,11 +75,7 @@ where }) } - pub(crate) async fn next_shared(mut this: Mut>) -> VmResult> { - this.next().await - } - - /// Get the next value produced by this stream. + /// Resume the generator and return the next generator state. pub async fn resume(&mut self, value: Value) -> VmResult { let execution = vm_try!(self .execution @@ -79,13 +94,138 @@ where VmResult::Ok(state) } +} + +impl Stream { + /// Get the next value produced by this stream through an asynchronous + /// iterator-like protocol. + /// + /// This function will resume execution until a value is produced through + /// `GeneratorState::Yielded(value)`, at which point it will return + /// `Some(value)`. Once `GeneratorState::Complete` is returned `None` will + /// be returned. + /// + /// # Examples + /// + /// ```rune + /// use std::ops::GeneratorState; + /// + /// async fn generate() { + /// yield 1; + /// yield 2; + /// } + /// + /// let g = generate(); + /// + /// assert_eq!(g.next().await, Some(1)); + /// assert_eq!(g.next().await, Some(2)); + /// assert_eq!(g.next().await, None); + /// `` + #[rune::function(keep, instance, path = Self::next)] + pub(crate) async fn next_shared(mut this: Mut) -> VmResult> { + this.next().await + } + /// Resumes the execution of this stream. + /// + /// This function will resume execution of the stream or start execution if + /// it hasn't already. This call will return back into the stream's last + /// suspension point, resuming execution from the latest `yield`. The stream + /// will continue executing until it either yields or returns, at which + /// point this function will return. + /// + /// # Return value + /// + /// The `GeneratorState` enum returned from this function indicates what + /// state the stream is in upon returning. If the `Yielded` variant is + /// returned then the stream has reached a suspension point and a value has + /// been yielded out. Streams in this state are available for resumption at + /// a later point. + /// + /// If `Complete` is returned then the stream has completely finished with + /// the value provided. It is invalid for the stream to be resumed again. + /// + /// # Panics + /// + /// This function may panic if it is called after the `Complete` variant has + /// been returned previously. While stream literals in the language are + /// guaranteed to panic on resuming after `Complete`, this is not guaranteed + /// for all implementations of the `Stream`. + /// + /// # Examples + /// + /// ```rune + /// use std::ops::GeneratorState; + /// + /// async fn generate() { + /// let n = yield 1; + /// yield 2 + n; + /// } + /// + /// let g = generate(); + /// + /// assert_eq!(g.resume(()).await, GeneratorState::Yielded(1)); + /// assert_eq!(g.resume(1).await, GeneratorState::Yielded(3)); + /// assert_eq!(g.resume(()).await, GeneratorState::Complete(())); + /// `` + #[rune::function(keep, instance, path = Self::resume)] pub(crate) async fn resume_shared( - mut this: Mut>, + mut this: Mut, value: Value, ) -> VmResult { this.resume(value).await } + + /// Debug print this stream + /// + /// # Examples + /// + /// ```rune + /// use std::ops::GeneratorState; + /// + /// fn generate() { + /// let n = yield 1; + /// yield 2 + n; + /// } + /// + /// let a = generate(); + /// + /// println!("{a:?}"); + /// `` + #[rune::function(keep, instance, protocol = STRING_DEBUG)] + fn debug(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{self:?}") + } + + /// Clone a stream. + /// + /// This clones the state of the stream too, allowing it to be resumed + /// independently. + /// + /// # Examples + /// + /// ```rune + /// use std::ops::GeneratorState; + /// + /// async fn generate() { + /// let n = yield 1; + /// yield 2 + n; + /// } + /// + /// let a = generate(); + /// + /// assert_eq!(a.resume(()).await, GeneratorState::Yielded(1)); + /// let b = a.clone(); + /// assert_eq!(a.resume(2).await, GeneratorState::Yielded(4)); + /// assert_eq!(b.resume(3).await, GeneratorState::Yielded(5)); + /// + /// assert_eq!(a.resume(()).await, GeneratorState::Complete(())); + /// 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> { diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index 9ebbb6241..99e6a8cd7 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -33,9 +33,9 @@ use super::static_type; use super::{ AccessError, AnyObj, AnyObjDrop, BorrowMut, BorrowRef, CallResultOnly, ConstValue, ConstValueKind, DynGuardedArgs, EnvProtocolCaller, Formatter, FromValue, Function, Future, - Generator, IntoOutput, Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, Protocol, - ProtocolCaller, RawAnyObjGuard, Ref, RuntimeError, Shared, Snapshot, Stream, Type, TypeInfo, - Variant, Vec, VmErrorKind, VmIntegerRepr, VmResult, + IntoOutput, Iterator, MaybeTypeOf, Mut, Object, OwnedTuple, Protocol, ProtocolCaller, + RawAnyObjGuard, Ref, RuntimeError, Shared, Snapshot, Type, TypeInfo, Variant, Vec, VmErrorKind, + VmIntegerRepr, VmResult, }; #[cfg(feature = "alloc")] use super::{Hasher, Tuple}; @@ -423,8 +423,6 @@ impl Value { } RefRepr::Mutable(value) => match &*vm_try!(value.borrow_ref()) { Mutable::Object(value) => Mutable::Object(vm_try!(value.try_clone())), - Mutable::Stream(value) => Mutable::Stream(vm_try!(value.try_clone())), - Mutable::Generator(value) => Mutable::Generator(vm_try!(value.try_clone())), Mutable::Option(value) => Mutable::Option(vm_try!(value.try_clone())), Mutable::Result(value) => Mutable::Result(vm_try!(value.try_clone())), Mutable::EmptyStruct(value) => Mutable::EmptyStruct(vm_try!(value.try_clone())), @@ -496,12 +494,6 @@ impl Value { Mutable::Future(value) => { vm_try!(vm_write!(f, "{value:?}")); } - Mutable::Stream(value) => { - vm_try!(vm_write!(f, "{value:?}")); - } - Mutable::Generator(value) => { - vm_try!(vm_write!(f, "{value:?}")); - } Mutable::Option(value) => { vm_try!(vm_write!(f, "{value:?}")); } @@ -822,16 +814,6 @@ impl Value { into_function, } - into! { - /// Coerce into a [`Generator`]. - Generator(Generator), - into_generator_ref, - into_generator_mut, - borrow_generator_ref, - borrow_generator_mut, - into_generator, - } - into! { /// Coerce into [`Struct`] Struct(Struct), @@ -852,16 +834,6 @@ impl Value { into_object, } - into! { - /// Coerce into a [`Stream`]. - Stream(Stream), - into_stream_ref, - into_stream_mut, - borrow_stream_ref, - borrow_stream_mut, - into_stream, - } - into_base! { /// Coerce into a [`Future`]. Future(Future), @@ -1940,9 +1912,7 @@ from! { Struct => Struct, Variant => Variant, Object => Object, - Generator => Generator, Future => Future, - Stream => Stream, } any_from! { @@ -1953,6 +1923,8 @@ any_from! { super::GeneratorState, super::Vec, super::OwnedTuple, + super::Generator, + super::Stream, } from_container! { @@ -2080,10 +2052,6 @@ pub(crate) enum Mutable { Object(Object), /// A stored future. Future(Future), - /// A Stream. - Stream(Stream), - /// A stored generator. - Generator(Generator), /// An empty value indicating nothing. Option(Option), /// A stored result in a slot. @@ -2105,8 +2073,6 @@ impl Mutable { match self { Mutable::Object(..) => TypeInfo::static_type(static_type::OBJECT), Mutable::Future(..) => TypeInfo::static_type(static_type::FUTURE), - Mutable::Stream(..) => TypeInfo::static_type(static_type::STREAM), - Mutable::Generator(..) => TypeInfo::static_type(static_type::GENERATOR), Mutable::Option(..) => TypeInfo::static_type(static_type::OPTION), Mutable::Result(..) => TypeInfo::static_type(static_type::RESULT), Mutable::Function(..) => TypeInfo::static_type(static_type::FUNCTION), @@ -2125,8 +2091,6 @@ impl Mutable { match self { Mutable::Object(..) => static_type::OBJECT.hash, Mutable::Future(..) => static_type::FUTURE.hash, - Mutable::Stream(..) => static_type::STREAM.hash, - Mutable::Generator(..) => static_type::GENERATOR.hash, Mutable::Result(..) => static_type::RESULT.hash, Mutable::Option(..) => static_type::OPTION.hash, Mutable::Function(..) => static_type::FUNCTION.hash, diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index 0605a2c71..6c39f32c3 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -58,8 +58,6 @@ impl ser::Serialize for Value { Mutable::Variant(..) => Err(ser::Error::custom("cannot serialize variants")), Mutable::Result(..) => Err(ser::Error::custom("cannot serialize results")), Mutable::Future(..) => Err(ser::Error::custom("cannot serialize futures")), - Mutable::Stream(..) => Err(ser::Error::custom("cannot serialize streams")), - Mutable::Generator(..) => Err(ser::Error::custom("cannot serialize generators")), Mutable::Function(..) => { Err(ser::Error::custom("cannot serialize function pointers")) }