diff --git a/book/src/traits.md b/book/src/traits.md index ea0180583..06b7f652a 100644 --- a/book/src/traits.md +++ b/book/src/traits.md @@ -121,16 +121,8 @@ let mut t = m.define_trait(["Iterator"])?; t.handler(|cx| { let next = cx.find(Protocol::NEXT)?; - cx.function_handler("next", &next)?; - - let size_hint = if let Some(size_hint) = cx.try_find(Protocol::SIZE_HINT)? { - cx.function_handler("size_hint", &size_hint)?; - size_hint - } else { - let size_hint = cx.function("size_hint", |_: Value| (0usize, None::))?; - cx.function_handler(Protocol::SIZE_HINT, &size_hint)?; - size_hint - }; + + let size_hint = cx.find_or_define(Protocol::SIZE_HINT, |_: Value| (0usize, None::))?; /* more methods */ Ok(()) diff --git a/crates/rune-core/src/protocol.rs b/crates/rune-core/src/protocol.rs index 43be73fce..fd6f45430 100644 --- a/crates/rune-core/src/protocol.rs +++ b/crates/rune-core/src/protocol.rs @@ -23,6 +23,9 @@ macro_rules! docstring { pub struct Protocol { /// The name of the builtin function. pub name: &'static str, + /// If this protocol defines an associated method, this is the name of that + /// method. + pub method: Option<&'static str>, /// The hash of the builtin function. pub hash: Hash, /// Representative expression for the protocol. @@ -94,6 +97,7 @@ macro_rules! define { $(#[$($meta:meta)*])* $vis:vis const $ident:ident: Protocol = Protocol { name: $name:expr, + method: $method:expr, hash: $hash:expr, repr: $repr:expr, doc: $doc:expr $(,)? @@ -105,6 +109,7 @@ macro_rules! define { $(#[$($meta)*])* $vis const $ident: Protocol = Protocol { name: $name, + method: $method, hash: Hash($hash), #[cfg(feature = "doc")] repr: $repr, @@ -143,6 +148,7 @@ define! { /// The function to access a field. pub const GET: Protocol = Protocol { name: "GET", + method: None, hash: 0x504007af1a8485a4u64, repr: Some("let output = $value"), doc: docstring! { @@ -153,6 +159,7 @@ define! { /// The function to set a field. pub const SET: Protocol = Protocol { name: "SET", + method: None, hash: 0x7d13d47fd8efef5au64, repr: Some("$value = input"), doc: docstring! { @@ -163,6 +170,7 @@ define! { /// The function to access an index. pub const INDEX_GET: Protocol = Protocol { name: "INDEX_GET", + method: None, hash: 0xadb5b27e2a4d2decu64, repr: Some("let output = $value[index]"), doc: docstring! { @@ -173,6 +181,7 @@ define! { /// The function to set an index. pub const INDEX_SET: Protocol = Protocol { name: "INDEX_SET", + method: None, hash: 0x162943f7bd03ad36u64, repr: Some("$value[index] = input"), doc: docstring! { @@ -183,6 +192,7 @@ define! { /// Check two types for partial equality. pub const PARTIAL_EQ: Protocol = Protocol { name: "PARTIAL_EQ", + method: Some("eq"), hash: 0x4b6bc4701445e318u64, repr: Some("if $value == b { }"), doc: docstring! { @@ -193,6 +203,7 @@ define! { /// Check two types for total equality. pub const EQ: Protocol = Protocol { name: "EQ", + method: None, hash: 0x418f5becbf885806u64, repr: Some("if $value == b { }"), doc: docstring! { @@ -203,6 +214,7 @@ define! { /// Perform an partial comparison between two values. pub const PARTIAL_CMP: Protocol = Protocol { name: "PARTIAL_CMP", + method: Some("partial_cmp"), hash: 0x8d4430991253343cu64, repr: Some("if $value < b { }"), doc: docstring! { @@ -213,6 +225,7 @@ define! { /// The protocol behind the `>` operator. pub const GT: Protocol = Protocol { name: "GT", + method: Some("gt"), hash: 0x29d9486ee6aa98ddu64, repr: Some("if $a > $b { }"), doc: docstring! { @@ -223,6 +236,7 @@ define! { /// The protocol behind the `>=` operator. pub const GE: Protocol = Protocol { name: "GE", + method: Some("ge"), hash: 0x2bb35b8f086340bu64, repr: Some("if $a >= $b { }"), doc: docstring! { @@ -233,6 +247,7 @@ define! { /// The protocol behind the `>` operator. pub const LT: Protocol = Protocol { name: "LT", + method: Some("lt"), hash: 0x82cb74423db0a3b6u64, repr: Some("if $a < $b { }"), doc: docstring! { @@ -243,6 +258,7 @@ define! { /// The protocol behind the `<=` operator. pub const LE: Protocol = Protocol { name: "LE", + method: Some("le"), hash: 0xcba7d52a7ca8c617u64, repr: Some("if $a <= $b { }"), doc: docstring! { @@ -252,6 +268,7 @@ define! { pub const MAX: Protocol = Protocol { name: "MAX", + method: Some("max"), hash: 0xca63c8386a41c812u64, repr: Some("$a.max($b)"), doc: docstring! { @@ -261,6 +278,7 @@ define! { pub const MIN: Protocol = Protocol { name: "MIN", + method: Some("min"), hash: 0x454f2aabc9d16509u64, repr: Some("$a.min($b)"), doc: docstring! { @@ -271,6 +289,7 @@ define! { /// Perform an total comparison between two values. pub const CMP: Protocol = Protocol { name: "CMP", + method: Some("cmp"), hash: 0x240f1b75466cd1a3u64, repr: Some("if $value < b { }"), doc: docstring! { @@ -281,6 +300,7 @@ define! { /// The function to implement for the addition operation. pub const ADD: Protocol = Protocol { name: "ADD", + method: None, hash: 0xe4ecf51fa0bf1076u64, repr: Some("let output = $value + b"), doc: docstring! { @@ -291,6 +311,7 @@ define! { /// The function to implement for the addition assign operation. pub const ADD_ASSIGN: Protocol = Protocol { name: "ADD_ASSIGN", + method: None, hash: 0x42451ccb0a2071a9u64, repr: Some("$value += b"), doc: docstring! { @@ -301,6 +322,7 @@ define! { /// The function to implement for the subtraction operation. pub const SUB: Protocol = Protocol { name: "SUB", + method: None, hash: 0x6fa86a5f18d0bf71u64, repr: Some("let output = $value - b"), doc: docstring! { @@ -311,6 +333,7 @@ define! { /// The function to implement for the subtraction assign operation. pub const SUB_ASSIGN: Protocol = Protocol { name: "SUB_ASSIGN", + method: None, hash: 0x5939bb56a1415284u64, repr: Some("$value -= b"), doc: docstring! { @@ -321,6 +344,7 @@ define! { /// The function to implement for the multiply operation. pub const MUL: Protocol = Protocol { name: "MUL", + method: None, hash: 0xb09e99dc94091d1cu64, repr: Some("let output = $value * b"), doc: docstring! { @@ -331,6 +355,7 @@ define! { /// The function to implement for the multiply assign operation. pub const MUL_ASSIGN: Protocol = Protocol { name: "MUL_ASSIGN", + method: None, hash: 0x29a54b727f980ebfu64, repr: Some("$value *= b"), doc: docstring! { @@ -341,6 +366,7 @@ define! { /// The function to implement for the division operation. pub const DIV: Protocol = Protocol { name: "DIV", + method: None, hash: 0xf26d6eea1afca6e8u64, repr: Some("let output = $value / b"), doc: docstring! { @@ -351,6 +377,7 @@ define! { /// The function to implement for the division assign operation. pub const DIV_ASSIGN: Protocol = Protocol { name: "DIV_ASSIGN", + method: None, hash: 0x4dd087a8281c04e6u64, repr: Some("$value /= b"), doc: docstring! { @@ -361,6 +388,7 @@ define! { /// The function to implement for the remainder operation. pub const REM: Protocol = Protocol { name: "REM", + method: None, hash: 0x5c6293639c74e671u64, repr: Some("let output = $value % b"), doc: docstring! { @@ -371,6 +399,7 @@ define! { /// The function to implement for the remainder assign operation. pub const REM_ASSIGN: Protocol = Protocol { name: "REM_ASSIGN", + method: None, hash: 0x3a8695980e77baf4u64, repr: Some("$value %= b"), doc: docstring! { @@ -381,6 +410,7 @@ define! { /// The function to implement for the bitwise and operation. pub const BIT_AND: Protocol = Protocol { name: "BIT_AND", + method: None, hash: 0x0e11f20d940eebe8u64, repr: Some("let output = $value & b"), doc: docstring! { @@ -391,6 +421,7 @@ define! { /// The function to implement for the bitwise and assign operation. pub const BIT_AND_ASSIGN: Protocol = Protocol { name: "BIT_AND_ASSIGN", + method: None, hash: 0x95cb1ba235dfb5ecu64, repr: Some("$value &= b"), doc: docstring! { @@ -401,6 +432,7 @@ define! { /// The function to implement for the bitwise xor operation. pub const BIT_XOR: Protocol = Protocol { name: "BIT_XOR", + method: None, hash: 0xa3099c54e1de4cbfu64, repr: Some("let output = $value ^ b"), doc: docstring! { @@ -411,6 +443,7 @@ define! { /// The function to implement for the bitwise xor assign operation. pub const BIT_XOR_ASSIGN: Protocol = Protocol { name: "BIT_XOR_ASSIGN", + method: None, hash: 0x01fa9706738f9867u64, repr: Some("$value ^= b"), doc: docstring! { @@ -421,6 +454,7 @@ define! { /// The function to implement for the bitwise or operation. pub const BIT_OR: Protocol = Protocol { name: "BIT_OR", + method: None, hash: 0x05010afceb4a03d0u64, repr: Some("let output = $value | b"), doc: docstring! { @@ -431,6 +465,7 @@ define! { /// The function to implement for the bitwise xor assign operation. pub const BIT_OR_ASSIGN: Protocol = Protocol { name: "BIT_OR_ASSIGN", + method: None, hash: 0x606d79ff1750a7ecu64, repr: Some("$value |= b"), doc: docstring! { @@ -441,6 +476,7 @@ define! { /// The function to implement for the bitwise shift left operation. pub const SHL: Protocol = Protocol { name: "SHL", + method: None, hash: 0x6845f7d0cc9e002du64, repr: Some("let output = $value << b"), doc: docstring! { @@ -451,6 +487,7 @@ define! { /// The function to implement for the bitwise shift left assign operation. pub const SHL_ASSIGN: Protocol = Protocol { name: "SHL_ASSIGN", + method: None, hash: 0xdc4702d0307ba27bu64, repr: Some("$value <<= b"), doc: docstring! { @@ -461,6 +498,7 @@ define! { /// The function to implement for the bitwise shift right operation. pub const SHR: Protocol = Protocol { name: "SHR", + method: None, hash: 0x6b485e8e6e58fbc8u64, repr: Some("let output = $value >> b"), doc: docstring! { @@ -471,6 +509,7 @@ define! { /// The function to implement for the bitwise shift right assign operation. pub const SHR_ASSIGN: Protocol = Protocol { name: "SHR_ASSIGN", + method: None, hash: 0x61ff7c46ff00e74au64, repr: Some("$value >>= b"), doc: docstring! { @@ -481,6 +520,7 @@ define! { /// Protocol function used by template strings. pub const DISPLAY_FMT: Protocol = Protocol { name: "DISPLAY_FMT", + method: None, hash: 0x811b62957ea9d9f9u64, repr: Some("println(\"{}\", $value)"), doc: docstring! { @@ -491,6 +531,7 @@ define! { /// Protocol function used by custom debug impls. pub const DEBUG_FMT: Protocol = Protocol { name: "DEBUG_FMT", + method: None, hash: 0x4064e3867aaa0717u64, repr: Some("println(\"{:?}\", $value)"), doc: docstring! { @@ -501,6 +542,7 @@ define! { /// Function used to convert an argument into an iterator. pub const INTO_ITER: Protocol = Protocol { name: "INTO_ITER", + method: None, hash: 0x15a85c8d774b4065u64, repr: Some("for item in $value { }"), doc: docstring! { @@ -511,6 +553,7 @@ define! { /// The function to call to continue iteration. pub const NEXT: Protocol = Protocol { name: "NEXT", + method: Some("next"), hash: 0xc3cde069de2ba320u64, repr: None, doc: docstring! { @@ -521,6 +564,7 @@ define! { /// The function to call to continue iteration at the nth element. pub const NTH: Protocol = Protocol { name: "NTH", + method: Some("nth"), hash: 0x6704550736c82a58u64, repr: None, doc: docstring! { @@ -531,6 +575,7 @@ define! { /// The function to call to continue iteration at the nth element form the back. pub const NTH_BACK: Protocol = Protocol { name: "NTH_BACK", + method: Some("nth_back"), hash: 0x4885ca2fd53a08c8u64, repr: None, doc: docstring! { @@ -541,6 +586,7 @@ define! { /// Protocol used when getting the size hint of an iterator. pub const SIZE_HINT: Protocol = Protocol { name: "SIZE_HINT", + method: Some("size_hint"), hash: 0x1a7b50baabc6e094u64, repr: Some("let output = $value.size_hint()"), doc: docstring! { @@ -551,6 +597,7 @@ define! { /// Protocol used when getting the exact length of an iterator. pub const LEN: Protocol = Protocol { name: "LEN", + method: Some("len"), hash: 0x52dd3b9489d39c42u64, repr: Some("let output = $value.len()"), doc: docstring! { @@ -561,6 +608,7 @@ define! { /// Protocol used when cloning a value. pub const NEXT_BACK: Protocol = Protocol { name: "NEXT_BACK", + method: Some("next_back"), hash: 0x91149fef42c0a8aeu64, repr: Some("let output = $value.next_back()"), doc: docstring! { @@ -573,6 +621,7 @@ define! { /// Signature: `fn(Value) -> Future`. pub const INTO_FUTURE: Protocol = Protocol { name: "INTO_FUTURE", + method: None, hash: 0x596e6428deabfda2u64, repr: Some("value.await"), doc: docstring! { @@ -583,6 +632,7 @@ define! { /// Coerce a value into a type name. This is stored as a constant. pub const INTO_TYPE_NAME: Protocol = Protocol { name: "INTO_TYPE_NAME", + method: None, hash: 0xbffd08b816c24682u64, repr: None, doc: docstring! { @@ -595,6 +645,7 @@ define! { /// Signature: `fn(self, usize) -> bool`. pub const IS_VARIANT: Protocol = Protocol { name: "IS_VARIANT", + method: None, hash: 0xc030d82bbd4dabe8u64, repr: None, doc: docstring! { @@ -613,6 +664,7 @@ define! { /// [`ControlFlow`]: core::ops::ControlFlow pub const TRY: Protocol = Protocol { name: "TRY", + method: None, hash: 0x5da1a80787003354u64, repr: Some("value?"), doc: docstring! { @@ -623,6 +675,7 @@ define! { /// Protocol used when calculating a hash. pub const HASH: Protocol = Protocol { name: "HASH", + method: None, hash: 0xf6cf2d9f416cef08u64, repr: Some("let output = hash($value)"), doc: docstring! { @@ -633,6 +686,7 @@ define! { /// Protocol used when cloning a value. pub const CLONE: Protocol = Protocol { name: "CLONE", + method: Some("clone"), hash: 0x2af2c875e36971eu64, repr: Some("let output = clone($value)"), doc: docstring! { diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index 09c7cd4fc..2f5956555 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -69,8 +69,8 @@ impl TraitContext<'_> { /// Find the given protocol function for the current type. /// /// This requires that the function is defined. - pub fn find(&self, name: impl ToInstance) -> Result, ContextError> { - let name = name.to_instance()?; + pub fn find(&mut self, protocol: Protocol) -> Result, ContextError> { + let name = protocol.to_instance()?; let hash = name .kind @@ -87,7 +87,13 @@ impl TraitContext<'_> { }); }; - Ok(handler.clone()) + let handler = handler.clone(); + + if let Some(method) = protocol.method { + self.function_handler(method, &handler)?; + } + + Ok(handler) } /// Try to find the given associated function. @@ -107,6 +113,28 @@ impl TraitContext<'_> { Ok(self.cx.functions.get(&hash).cloned()) } + /// Find or define a protocol function. + pub fn find_or_define( + &mut self, + protocol: Protocol, + function: F, + ) -> Result, ContextError> + where + F: Function, + { + let function = if let Some(function) = self.try_find(protocol)? { + function + } else { + self.function(protocol, function)? + }; + + if let Some(method) = protocol.method { + self.function_handler(method, &function)?; + } + + Ok(function) + } + /// Define a new associated function for the current type. pub fn function( &mut self, @@ -137,7 +165,7 @@ impl TraitContext<'_> { /// Define a new associated function for the current type using a raw /// handler. - pub fn function_handler( + fn function_handler( &mut self, name: impl ToInstance, handler: &Arc, diff --git a/crates/rune/src/function/mod.rs b/crates/rune/src/function/mod.rs index 1fc6be4a8..ce255871e 100644 --- a/crates/rune/src/function/mod.rs +++ b/crates/rune/src/function/mod.rs @@ -40,7 +40,7 @@ macro_rules! access_memory { /// implemented separately for plain and async functions. pub trait FunctionKind { /// Indicates if the function is async. - fn is_async() -> bool; + const IS_ASYNC: bool; } /// Marker for plain functions. @@ -48,10 +48,7 @@ pub trait FunctionKind { pub struct Plain; impl FunctionKind for Plain { - #[inline] - fn is_async() -> bool { - false - } + const IS_ASYNC: bool = false; } /// Marker for async functions. @@ -59,10 +56,7 @@ impl FunctionKind for Plain { pub struct Async; impl FunctionKind for Async { - #[inline] - fn is_async() -> bool { - true - } + const IS_ASYNC: bool = true; } /// Trait used to provide the [function][crate::module::Module::function] @@ -77,7 +71,7 @@ pub trait Function: 'static + Send + Sync { /// Get the number of arguments. #[doc(hidden)] - fn args() -> usize; + const ARGS: usize; /// Perform the vm call. #[doc(hidden)] @@ -107,7 +101,7 @@ pub trait InstanceFunction: 'static + Send + Sync { /// Get the number of arguments. #[doc(hidden)] - fn args() -> usize; + const ARGS: usize; /// Perform the vm call. #[doc(hidden)] @@ -130,10 +124,7 @@ macro_rules! impl_instance_function_traits { type Instance = Instance; type Return = T::Return; - #[inline] - fn args() -> usize { - >::args() - } + const ARGS: usize = >::ARGS; #[inline] fn fn_call(&self, memory: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { @@ -239,9 +230,7 @@ macro_rules! impl_function_traits { { type Return = U; - fn args() -> usize { - $count - } + const ARGS: usize = $count; #[allow(clippy::drop_non_drop)] fn fn_call(&self, memory: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { @@ -267,9 +256,7 @@ macro_rules! impl_function_traits { { type Return = U::Output; - fn args() -> usize { - $count - } + const ARGS: usize = $count; #[allow(clippy::drop_non_drop)] fn fn_call(&self, memory: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> { diff --git a/crates/rune/src/function_meta.rs b/crates/rune/src/function_meta.rs index ef8b93d2c..31c175efa 100644 --- a/crates/rune/src/function_meta.rs +++ b/crates/rune/src/function_meta.rs @@ -93,9 +93,9 @@ impl FunctionData { f.fn_call(stack, addr, args, output) }), #[cfg(feature = "doc")] - is_async: K::is_async(), + is_async: K::IS_ASYNC, #[cfg(feature = "doc")] - args: Some(F::args()), + args: Some(F::ARGS), #[cfg(feature = "doc")] argument_types: A::into_box()?, #[cfg(feature = "doc")] @@ -303,9 +303,9 @@ impl AssociatedFunctionData { f.fn_call(stack, addr, args, output) }), #[cfg(feature = "doc")] - is_async: K::is_async(), + is_async: K::IS_ASYNC, #[cfg(feature = "doc")] - args: Some(F::args()), + args: Some(F::ARGS), #[cfg(feature = "doc")] argument_types: A::into_box()?, #[cfg(feature = "doc")] @@ -327,9 +327,9 @@ impl AssociatedFunctionData { f.fn_call(stack, addr, args, output) }), #[cfg(feature = "doc")] - is_async: K::is_async(), + is_async: K::IS_ASYNC, #[cfg(feature = "doc")] - args: Some(F::args()), + args: Some(F::ARGS), #[cfg(feature = "doc")] argument_types: A::into_box()?, #[cfg(feature = "doc")] diff --git a/crates/rune/src/module/internal_enum.rs b/crates/rune/src/module/internal_enum.rs index b7b8206aa..ffb0a3e0c 100644 --- a/crates/rune/src/module/internal_enum.rs +++ b/crates/rune/src/module/internal_enum.rs @@ -44,7 +44,7 @@ impl InternalEnum { self.variants.try_push(Variant { name, type_check: Some(type_check), - fields: Some(Fields::Unnamed(C::args())), + fields: Some(Fields::Unnamed(C::ARGS)), constructor: Some(constructor), deprecated: None, docs: Docs::EMPTY, diff --git a/crates/rune/src/modules/clone.rs b/crates/rune/src/modules/clone.rs index df75b6486..a996b5880 100644 --- a/crates/rune/src/modules/clone.rs +++ b/crates/rune/src/modules/clone.rs @@ -31,8 +31,7 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let clone = cx.find(Protocol::CLONE)?; - cx.function_handler("clone", &clone)?; + _ = cx.find(Protocol::CLONE)?; Ok(()) })?; diff --git a/crates/rune/src/modules/cmp.rs b/crates/rune/src/modules/cmp.rs index f31b2cefc..283584256 100644 --- a/crates/rune/src/modules/cmp.rs +++ b/crates/rune/src/modules/cmp.rs @@ -170,9 +170,7 @@ pub fn module() -> Result { t.handler(|cx| { let partial_eq = cx.find(Protocol::PARTIAL_EQ)?; - cx.function_handler("eq", &partial_eq)?; - - let partial_eq = Caller::::new(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)))) @@ -393,70 +391,56 @@ pub fn module() -> Result { t.handler(|cx| { let partial_cmp = cx.find(Protocol::PARTIAL_CMP)?; - cx.function_handler("partial_cmp", &partial_cmp)?; - - let partial_cmp = Caller::>::new(partial_cmp); + let partial_cmp = Caller::<(Value, Value), 2, Option>::new(partial_cmp); - let lt = if let Some(lt) = cx.try_find(Protocol::LT)? { - lt - } else { + cx.find_or_define(Protocol::LT, { let partial_cmp = partial_cmp.clone(); - cx.function(Protocol::LT, move |a: Value, b: Value| { + move |a: Value, b: Value| { let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { return VmResult::Ok(false); }; VmResult::Ok(matches!(o, Ordering::Less)) - })? - }; + } + })?; - let le = if let Some(le) = cx.try_find(Protocol::LE)? { - le - } else { + cx.find_or_define(Protocol::LE, { let partial_cmp = partial_cmp.clone(); - cx.function(Protocol::LE, move |a: Value, b: Value| { + move |a: Value, b: Value| { let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { return VmResult::Ok(false); }; VmResult::Ok(matches!(o, Ordering::Less | Ordering::Equal)) - })? - }; + } + })?; - let gt = if let Some(gt) = cx.try_find(Protocol::GT)? { - gt - } else { + cx.find_or_define(Protocol::GT, { let partial_cmp = partial_cmp.clone(); - cx.function(Protocol::GT, move |a: Value, b: Value| { + move |a: Value, b: Value| { let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { return VmResult::Ok(false); }; VmResult::Ok(matches!(o, Ordering::Greater)) - })? - }; + } + })?; - let ge = if let Some(ge) = cx.try_find(Protocol::GE)? { - ge - } else { + cx.find_or_define(Protocol::GE, { let partial_cmp = partial_cmp.clone(); - cx.function(Protocol::GE, move |a: Value, b: Value| { + move |a: Value, b: Value| { let Some(o) = vm_try!(partial_cmp.call((a.clone(), b.clone()))) else { return VmResult::Ok(false); }; VmResult::Ok(matches!(o, Ordering::Greater | Ordering::Equal)) - })? - }; + } + })?; - cx.function_handler("lt", <)?; - cx.function_handler("le", &le)?; - cx.function_handler("gt", >)?; - cx.function_handler("ge", &ge)?; Ok(()) })?; @@ -609,39 +593,26 @@ pub fn module() -> Result { t.handler(|cx| { let cmp = cx.find(Protocol::CMP)?; - cx.function_handler("cmp", &cmp)?; - - let cmp = Caller::::new(cmp); + let cmp = Caller::<(Value, Value), 2, Ordering>::new(cmp); - let min = if let Some(min) = cx.try_find(Protocol::MIN)? { - min - } else { + cx.find_or_define(Protocol::MIN, { let cmp = cmp.clone(); - cx.function(Protocol::MIN, 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), - } - })? - }; - - cx.function_handler("min", &min)?; + 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), + } + })?; - let max = if let Some(max) = cx.try_find(Protocol::MAX)? { - max - } else { + cx.find_or_define(Protocol::MAX, { let cmp = cmp.clone(); - cx.function(Protocol::MAX, 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| match vm_try!(cmp.call((a.clone(), b.clone()))) { + Ordering::Less | Ordering::Equal => VmResult::Ok(b), + Ordering::Greater => VmResult::Ok(a), + } + })?; - cx.function_handler("max", &max)?; Ok(()) })?; diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index 689deb55c..fa93b4f36 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -155,8 +155,7 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let len = cx.find(Protocol::LEN)?; - cx.function_handler("len", &len)?; + _ = cx.find(Protocol::LEN)?; Ok(()) })?; @@ -204,26 +203,18 @@ pub fn module() -> Result { t.handler(|cx| { let next = cx.find(Protocol::NEXT)?; - cx.function_handler("next", &next)?; + let next = Caller::<(Value,), 1, Option>::new(next); - let size_hint = if let Some(size_hint) = cx.try_find(Protocol::SIZE_HINT)? { - size_hint - } else { - cx.function(Protocol::SIZE_HINT, |_: Value| (0usize, None::))? - }; - - cx.function_handler("size_hint", &size_hint)?; + let size_hint = + cx.find_or_define(Protocol::SIZE_HINT, |_: Value| (0usize, None::))?; - let next = Caller::>::new(next); - let size_hint = Caller::<(usize, Option)>::new(size_hint); + let size_hint = Caller::<(&Value,), 1, (usize, Option)>::new(size_hint); - let nth = if let Some(nth) = cx.try_find(Protocol::NTH)? { - nth - } else { + cx.find_or_define(Protocol::NTH, { let next = next.clone(); - cx.function(Protocol::NTH, move |iterator: Value, mut n: usize| loop { - let Some(value) = vm_try!(next.call((&iterator,))) else { + move |iter: Value, mut n: usize| loop { + let Some(value) = vm_try!(next.call((iter.clone(),))) else { break VmResult::Ok(None); }; @@ -232,10 +223,8 @@ pub fn module() -> Result { } n -= 1; - })? - }; - - cx.function_handler("nth", &nth)?; + } + })?; cx.function(Protocol::INTO_ITER, |value: Value| value)?; @@ -248,7 +237,7 @@ pub fn module() -> Result { let mut n = 0usize; loop { - if vm_try!(next.call((&iter,))).is_none() { + if vm_try!(next.call((iter.clone(),))).is_none() { break VmResult::Ok(n); }; @@ -262,7 +251,7 @@ pub fn module() -> Result { cx.function("fold", move |iter: Value, mut acc: Value, f: Function| { loop { - let Some(value) = vm_try!(next.call((&iter,))) else { + let Some(value) = vm_try!(next.call((iter.clone(),))) else { break VmResult::Ok(acc); }; @@ -275,11 +264,11 @@ 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,))) else { + let Some(mut acc) = vm_try!(next.call((iter.clone(),))) else { return VmResult::Ok(None); }; - while let Some(value) = vm_try!(next.call((&iter,))) { + while let Some(value) = vm_try!(next.call((iter.clone(),))) { acc = vm_try!(f.call((acc, value))); } @@ -291,7 +280,7 @@ pub fn module() -> Result { let next = next.clone(); cx.function("find", move |iter: Value, f: Function| loop { - let Some(value) = vm_try!(next.call((&iter,))) else { + let Some(value) = vm_try!(next.call((iter.clone(),))) else { break VmResult::Ok(None); }; @@ -305,7 +294,7 @@ pub fn module() -> Result { let next = next.clone(); cx.function("any", move |iter: Value, f: Function| loop { - let Some(value) = vm_try!(next.call((&iter,))) else { + let Some(value) = vm_try!(next.call((iter.clone(),))) else { break VmResult::Ok(false); }; @@ -319,7 +308,7 @@ pub fn module() -> Result { let next = next.clone(); cx.function("all", move |iter: Value, f: Function| loop { - let Some(value) = vm_try!(next.call((&iter,))) else { + let Some(value) = vm_try!(next.call((iter.clone(),))) else { break VmResult::Ok(true); }; @@ -372,7 +361,7 @@ pub fn module() -> Result { let (cap, _) = vm_try!(size_hint.call((&iter,))); let mut vec = vm_try!(Vec::with_capacity(cap)); - while let Some(value) = vm_try!(next.call((&iter,))) { + while let Some(value) = vm_try!(next.call((iter.clone(),))) { vm_try!(vec.push(value)); } @@ -390,7 +379,7 @@ pub fn module() -> Result { let (cap, _) = vm_try!(size_hint.call((&iter,))); let mut vec = vm_try!(Vec::with_capacity(cap)); - while let Some(value) = vm_try!(next.call((&iter,))) { + while let Some(value) = vm_try!(next.call((iter.clone(),))) { vm_try!(vec.push(value)); } @@ -409,7 +398,7 @@ pub fn module() -> Result { let (cap, _) = vm_try!(size_hint.call((&iter,))); let mut set = vm_try!(HashSet::with_capacity(cap)); - while let Some(value) = vm_try!(next.call((&iter,))) { + while let Some(value) = vm_try!(next.call((iter.clone(),))) { vm_try!(set.insert(value)); } @@ -428,7 +417,7 @@ pub fn module() -> Result { let (cap, _) = vm_try!(size_hint.call((&iter,))); let mut map = vm_try!(HashMap::with_capacity(cap)); - while let Some((key, value)) = vm_try!(next.call((&iter,))) { + while let Some((key, value)) = vm_try!(next.call((iter.clone(),))) { vm_try!(map.insert(key, value)); } @@ -447,7 +436,7 @@ pub fn module() -> Result { let (cap, _) = vm_try!(size_hint.call((&iter,))); let mut map = vm_try!(Object::with_capacity(cap)); - while let Some((key, value)) = vm_try!(next.call((&iter,))) { + while let Some((key, value)) = vm_try!(next.call((iter.clone(),))) { vm_try!(map.insert(key, value)); } @@ -466,7 +455,7 @@ pub fn module() -> Result { let (cap, _) = vm_try!(size_hint.call((&iter,))); let mut vec = vm_try!(alloc::Vec::try_with_capacity(cap)); - while let Some(value) = vm_try!(next.call((&iter,))) { + while let Some(value) = vm_try!(next.call((iter.clone(),))) { vm_try!(vec.try_push(value)); } @@ -483,7 +472,7 @@ pub fn module() -> Result { move |iter: Value| { let mut string = String::new(); - while let Some(value) = vm_try!(next.call((&iter,))) { + while let Some(value) = vm_try!(next.call((iter.clone(),))) { match vm_try!(value.borrow_ref_repr()) { BorrowRefRepr::Inline(Inline::Char(c)) => { vm_try!(string.try_push(*c)); @@ -1641,38 +1630,33 @@ pub fn module() -> Result { })?; t.handler(|cx| { - let _ = cx.find(Protocol::NEXT)?; let next_back = cx.find(Protocol::NEXT_BACK)?; - let nth_back = if let Some(nth_back) = cx.try_find(Protocol::NTH_BACK)? { - nth_back - } else { + cx.find_or_define(Protocol::NTH_BACK, { let next_back = next_back.clone(); - cx.function(Protocol::NTH_BACK, move |iterator: Value, mut n: usize| { - loop { - let mut memory = [iterator.clone()]; - - vm_try!(next_back( - &mut memory, - InstAddress::ZERO, - 1, - Output::keep(0) - )); - let [value] = memory; - - let Some(value) = vm_try!(Option::::from_value(value)) else { - break VmResult::Ok(None); - }; + move |iterator: Value, mut n: usize| loop { + let mut memory = [iterator.clone()]; - if n == 0 { - break VmResult::Ok(Some(value)); - } + vm_try!(next_back( + &mut memory, + InstAddress::ZERO, + 1, + Output::keep(0) + )); + let [value] = memory; - n -= 1; + let Some(value) = vm_try!(Option::::from_value(value)) else { + break VmResult::Ok(None); + }; + + if n == 0 { + break VmResult::Ok(Some(value)); } - })? - }; + + n -= 1; + } + })?; cx.raw_function("rev", |stack, addr, len, out| { let [value] = vm_try!(stack.slice_at(addr, len)) else { @@ -1690,8 +1674,6 @@ pub fn module() -> Result { VmResult::Ok(()) })?; - cx.function_handler("next_back", &next_back)?; - cx.function_handler("nth_back", &nth_back)?; Ok(()) })?; diff --git a/crates/rune/src/shared/caller.rs b/crates/rune/src/shared/caller.rs index 52417b57e..6d0f7ca76 100644 --- a/crates/rune/src/shared/caller.rs +++ b/crates/rune/src/shared/caller.rs @@ -10,13 +10,14 @@ use crate::FromValue; /// Note: This can only be used with functions that take at least one argument. /// Otherwise it will panic. #[derive(Clone)] -pub(crate) struct Caller { +pub(crate) struct Caller { handler: Arc, - _marker: PhantomData, + _marker: PhantomData<(A, T)>, } -impl Caller +impl Caller where + A: FixedArgs, T: FromValue, { /// Construct a new caller helper @@ -28,7 +29,7 @@ where } /// Modify the return value of the caller. - pub(crate) fn with_return(&self) -> Caller + pub(crate) fn with_return(&self) -> Caller where U: FromValue, { @@ -39,7 +40,7 @@ where } /// Perform a call. - pub(crate) fn call(&self, args: impl FixedArgs) -> VmResult { + pub(crate) fn call(&self, args: A) -> VmResult { const { assert!(N > 0, "Must be used with non-zero arguments"); } @@ -62,5 +63,5 @@ where } // SAFETY: The marker doesn't matter. -unsafe impl Send for Caller {} -unsafe impl Sync for Caller {} +unsafe impl Send for Caller {} +unsafe impl Sync for Caller {}