diff --git a/crates/rune-macros/Cargo.toml b/crates/rune-macros/Cargo.toml index 989f18f60..5638ba35b 100644 --- a/crates/rune-macros/Cargo.toml +++ b/crates/rune-macros/Cargo.toml @@ -18,9 +18,5 @@ syn = { version = "2.0.15", features = ["full"] } quote = "1.0.26" proc-macro2 = { version = "1.0.56", features = ["span-locations"] } -[dev-dependencies] -rune = { version = "0.12.3", path = "../rune" } - [lib] proc-macro = true -path = "src/lib.rs" diff --git a/crates/rune-macros/src/any.rs b/crates/rune-macros/src/any.rs index 449218965..652ee15ec 100644 --- a/crates/rune-macros/src/any.rs +++ b/crates/rune-macros/src/any.rs @@ -208,7 +208,7 @@ fn expand_enum_install_with( generics: &syn::Generics, ) -> Option<()> { let Tokens { - compile_variant, + module_variant, protocol, to_value, type_of, @@ -266,7 +266,7 @@ fn expand_enum_install_with( } } - variants.push(quote!((#variant_name, #compile_variant::st([#(#field_names),*])))); + variants.push(quote!((#variant_name, #module_variant::st([#(#field_names),*])))); } syn::Fields::Unnamed(fields) => { let mut fields_len = 0usize; @@ -290,7 +290,7 @@ fn expand_enum_install_with( } } - variants.push(quote!((#variant_name, #compile_variant::tuple(#fields_len)))); + variants.push(quote!((#variant_name, #module_variant::tuple(#fields_len)))); if variant_attrs.constructor { if fields_len != fields.unnamed.len() { @@ -302,7 +302,7 @@ fn expand_enum_install_with( } } syn::Fields::Unit => { - variants.push(quote!((#variant_name, #compile_variant::unit()))); + variants.push(quote!((#variant_name, #module_variant::unit()))); if variant_attrs.constructor { constructors diff --git a/crates/rune-macros/src/context.rs b/crates/rune-macros/src/context.rs index b24e84df7..0649fb8c7 100644 --- a/crates/rune-macros/src/context.rs +++ b/crates/rune-macros/src/context.rs @@ -617,19 +617,23 @@ impl Context { }; Tokens { + any_type_info: quote!(#module::runtime::AnyTypeInfo), any: quote!(#module::Any), + compile_error: quote!(#module::compile::Error), context_error: quote!(#module::compile::ContextError), from_value: quote!(#module::runtime::FromValue), + full_type_of: quote!(#module::runtime::FullTypeOf), hash: quote!(#module::Hash), id: quote!(#module::parse::Id), - install_with: quote!(#module::compile::InstallWith), + install_with: quote!(#module::__private::InstallWith), macro_context: quote!(#module::macros::MacroContext), - module: quote!(#module::compile::Module), + maybe_type_of: quote!(#module::runtime::MaybeTypeOf), + module_variant: quote!(#module::module::Variant), + module: quote!(#module::__private::Module), named: quote!(#module::compile::Named), object: quote!(#module::runtime::Object), opaque: quote!(#module::parse::Opaque), option_spanned: quote!(#module::ast::OptionSpanned), - compile_error: quote!(#module::compile::Error), parse: quote!(#module::parse::Parse), parser: quote!(#module::parse::Parser), pointer_guard: quote!(#module::runtime::SharedPointerGuard), @@ -637,47 +641,47 @@ impl Context { raw_into_mut: quote!(#module::runtime::RawMut), raw_into_ref: quote!(#module::runtime::RawRef), raw_str: quote!(#module::runtime::RawStr), + result: quote!(::core::result::Result), shared: quote!(#module::runtime::Shared), span: quote!(#module::ast::Span), spanned: quote!(#module::ast::Spanned), to_tokens: quote!(#module::macros::ToTokens), to_value: quote!(#module::runtime::ToValue), token_stream: quote!(#module::macros::TokenStream), + try_result: quote!(#module::runtime::try_result), tuple: quote!(#module::runtime::Tuple), type_info: quote!(#module::runtime::TypeInfo), - any_type_info: quote!(#module::runtime::AnyTypeInfo), + type_name: quote!(::core::any::type_name), type_of: quote!(#module::runtime::TypeOf), - maybe_type_of: quote!(#module::runtime::MaybeTypeOf), - full_type_of: quote!(#module::runtime::FullTypeOf), unit_struct: quote!(#module::runtime::UnitStruct), unsafe_from_value: quote!(#module::runtime::UnsafeFromValue), unsafe_to_value: quote!(#module::runtime::UnsafeToValue), value: quote!(#module::runtime::Value), variant_data: quote!(#module::runtime::VariantData), - compile_variant: quote!(#module::compile::Variant), vm_error: quote!(#module::runtime::VmError), vm_result: quote!(#module::runtime::VmResult), - try_result: quote!(#module::runtime::try_result), - type_name: quote!(::core::any::type_name), - result: quote!(::core::result::Result), } } } pub(crate) struct Tokens { + pub(crate) any_type_info: TokenStream, pub(crate) any: TokenStream, + pub(crate) compile_error: TokenStream, pub(crate) context_error: TokenStream, pub(crate) from_value: TokenStream, + pub(crate) full_type_of: TokenStream, pub(crate) hash: TokenStream, pub(crate) id: TokenStream, pub(crate) install_with: TokenStream, pub(crate) macro_context: TokenStream, + pub(crate) maybe_type_of: TokenStream, + pub(crate) module_variant: TokenStream, pub(crate) module: TokenStream, pub(crate) named: TokenStream, pub(crate) object: TokenStream, pub(crate) opaque: TokenStream, pub(crate) option_spanned: TokenStream, - pub(crate) compile_error: TokenStream, pub(crate) parse: TokenStream, pub(crate) parser: TokenStream, pub(crate) pointer_guard: TokenStream, @@ -685,29 +689,25 @@ pub(crate) struct Tokens { pub(crate) raw_into_mut: TokenStream, pub(crate) raw_into_ref: TokenStream, pub(crate) raw_str: TokenStream, + pub(crate) result: TokenStream, pub(crate) shared: TokenStream, pub(crate) span: TokenStream, pub(crate) spanned: TokenStream, pub(crate) to_tokens: TokenStream, pub(crate) to_value: TokenStream, pub(crate) token_stream: TokenStream, + pub(crate) try_result: TokenStream, pub(crate) tuple: TokenStream, pub(crate) type_info: TokenStream, - pub(crate) any_type_info: TokenStream, + pub(crate) type_name: TokenStream, pub(crate) type_of: TokenStream, - pub(crate) maybe_type_of: TokenStream, - pub(crate) full_type_of: TokenStream, pub(crate) unit_struct: TokenStream, pub(crate) unsafe_from_value: TokenStream, pub(crate) unsafe_to_value: TokenStream, pub(crate) value: TokenStream, pub(crate) variant_data: TokenStream, - pub(crate) compile_variant: TokenStream, pub(crate) vm_error: TokenStream, pub(crate) vm_result: TokenStream, - pub(crate) try_result: TokenStream, - pub(crate) type_name: TokenStream, - pub(crate) result: TokenStream, } impl Tokens { diff --git a/crates/rune-macros/src/lib.rs b/crates/rune-macros/src/lib.rs index 088ef08fe..04c261974 100644 --- a/crates/rune-macros/src/lib.rs +++ b/crates/rune-macros/src/lib.rs @@ -39,28 +39,6 @@ mod spanned; mod to_tokens; mod to_value; -/// Macro helper function for quoting the token stream as macro output. -/// -/// Is capable of quoting everything in Rune, except for the following: -/// * Labels, which must be created using `Label::new`. -/// * Dynamic quoted strings and other literals, which must be created using -/// `Lit::new`. -/// -/// ``` -/// use rune::macros::quote; -/// -/// quote!(hello self); -/// ``` -/// -/// # Interpolating values -/// -/// Values are interpolated with `#value`, or `#(value + 1)` for expressions. -/// -/// # Iterators -/// -/// Anything that can be used as an iterator can be iterated over with -/// `#(iter)*`. A token can also be used to join inbetween each iteration, like -/// `#(iter),*`. #[proc_macro] pub fn quote(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = proc_macro2::TokenStream::from(input); @@ -74,111 +52,6 @@ pub fn quote(input: proc_macro::TokenStream) -> proc_macro::TokenStream { output.into() } -/// Macro used to annotate native functions which can be loaded into rune. -/// -/// This macro automatically performs the following things: -/// * Rust documentation comments are captured so that it can be used in -/// generated Rune documentation. -/// * The name of arguments is captured to improve documentation generation. -/// * If an instance function is annotated this is detected (if the function -/// receives `self`). This behavior can be forced using `#[rune(instance)]` if -/// the function doesn't take `self`. -/// -/// # Examples -/// -/// A simple free function: -/// -/// ``` -/// use rune::{Module, ContextError}; -/// -/// /// This is a pretty neat function which is called `std::str::to_uppercase("hello")`. -/// #[rune::function] -/// fn to_uppercase(string: &str) -> String { -/// string.to_uppercase() -/// } -/// -/// fn module() -> Result { -/// let mut m = Module::new(); -/// m.function_meta(to_uppercase)?; -/// Ok(m) -/// } -/// ``` -/// -/// A free instance function: -/// -/// ``` -/// use rune::{Module, ContextError}; -/// -/// /// This is a pretty neat function, which is called like `"hello".to_uppercase()`. -/// #[rune::function(instance)] -/// fn to_uppercase(string: &str) -> String { -/// string.to_uppercase() -/// } -/// -/// /// This is a pretty neat function, which is called like `string::to_uppercase2("hello")`. -/// #[rune::function(path = string)] -/// fn to_uppercase2(string: &str) -> String { -/// string.to_uppercase() -/// } -/// -/// fn module() -> Result { -/// let mut m = Module::new(); -/// m.function_meta(to_uppercase)?; -/// m.function_meta(to_uppercase2)?; -/// Ok(m) -/// } -/// ``` -/// -/// A regular instance function: -/// -/// ``` -/// use rune::{Any, Module, ContextError}; -/// -/// #[derive(Any)] -/// struct String { -/// inner: std::string::String -/// } -/// -/// impl String { -/// /// Construct a new string wrapper. -/// #[rune::function(path = Self::new)] -/// fn new(string: &str) -> Self { -/// Self { -/// inner: string.into() -/// } -/// } -/// -/// /// Construct a new string wrapper. -/// #[rune::function(path = Self::new2)] -/// fn new2(string: &str) -> Self { -/// Self { -/// inner: string.into() -/// } -/// } -/// -/// /// Uppercase the string inside of the string wrapper. -/// /// -/// /// # Examples -/// /// -/// /// ```rune -/// /// let string = String::new("hello"); -/// /// assert_eq!(string.to_uppercase(), "HELLO"); -/// /// ``` -/// #[rune::function] -/// fn to_uppercase(&self) -> std::string::String { -/// self.inner.to_uppercase() -/// } -/// } -/// -/// fn module() -> Result { -/// let mut m = Module::new(); -/// m.ty::()?; -/// m.function_meta(String::new)?; -/// m.function_meta(String::new2)?; -/// m.function_meta(String::to_uppercase)?; -/// Ok(m) -/// } -/// ``` #[proc_macro_attribute] pub fn function( attrs: proc_macro::TokenStream, @@ -211,7 +84,6 @@ pub fn macro_( output.into() } -/// Helper derive to implement `ToTokens`. #[proc_macro_derive(ToTokens, attributes(rune))] #[doc(hidden)] pub fn to_tokens(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -219,7 +91,6 @@ pub fn to_tokens(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive.expand().unwrap_or_else(to_compile_errors).into() } -/// Helper derive to implement `Parse`. #[proc_macro_derive(Parse, attributes(rune))] #[doc(hidden)] pub fn parse(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -227,7 +98,6 @@ pub fn parse(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive.expand().unwrap_or_else(to_compile_errors).into() } -/// Helper derive to implement `Spanned`. #[proc_macro_derive(Spanned, attributes(rune))] #[doc(hidden)] pub fn spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -235,7 +105,6 @@ pub fn spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive.expand().unwrap_or_else(to_compile_errors).into() } -/// Helper derive to implement `OptionSpanned`. #[proc_macro_derive(OptionSpanned, attributes(rune))] #[doc(hidden)] pub fn option_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -243,7 +112,6 @@ pub fn option_spanned(input: proc_macro::TokenStream) -> proc_macro::TokenStream derive.expand().unwrap_or_else(to_compile_errors).into() } -/// Helper derive to implement `Opaque`. #[proc_macro_derive(Opaque, attributes(rune))] #[doc(hidden)] pub fn opaque(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -251,37 +119,6 @@ pub fn opaque(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive.expand().unwrap_or_else(to_compile_errors).into() } -/// Derive macro for the `FromValue` trait for converting types from the dynamic -/// `Value` container. -/// -/// # Examples -/// -/// ``` -/// use rune::{FromValue, Vm}; -/// use std::sync::Arc; -/// -/// #[derive(FromValue)] -/// struct Foo { -/// field: u64, -/// } -/// -/// let mut sources = rune::sources! { -/// entry => { -/// pub fn main() { -/// #{field: 42} -/// } -/// } -/// }; -/// -/// let unit = rune::prepare(&mut sources).build()?; -/// -/// let mut vm = Vm::without_runtime(Arc::new(unit)); -/// let foo = vm.call(["main"], ())?; -/// let foo: Foo = rune::from_value(foo)?; -/// -/// assert_eq!(foo.field, 42); -/// # Ok::<_, rune::Error>(()) -/// ``` #[proc_macro_derive(FromValue, attributes(rune))] pub fn from_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); @@ -290,37 +127,6 @@ pub fn from_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { .into() } -/// Derive macro for the `FromValue` trait for converting types into the dynamic -/// `Value` container. -/// -/// # Examples -/// -/// ``` -/// use rune::{ToValue, Vm}; -/// use std::sync::Arc; -/// -/// #[derive(ToValue)] -/// struct Foo { -/// field: u64, -/// } -/// -/// let mut sources = rune::sources! { -/// entry => { -/// pub fn main(foo) { -/// foo.field + 1 -/// } -/// } -/// }; -/// -/// let unit = rune::prepare(&mut sources).build()?; -/// -/// let mut vm = Vm::without_runtime(Arc::new(unit)); -/// let value = vm.call(["main"], (Foo { field: 42 },))?; -/// let value: u64 = rune::from_value(value)?; -/// -/// assert_eq!(value, 43); -/// # Ok::<_, rune::Error>(()) -/// ``` #[proc_macro_derive(ToValue, attributes(rune))] pub fn to_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = syn::parse_macro_input!(input as syn::DeriveInput); @@ -329,40 +135,12 @@ pub fn to_value(input: proc_macro::TokenStream) -> proc_macro::TokenStream { .into() } -/// 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(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; -/// -/// #[derive(Any)] -/// #[rune(name = "Bar")] -/// struct Foo { -/// } -/// -/// fn install() -> Result { -/// let mut module = rune::Module::new(); -/// module.ty::()?; -/// Ok(module) -/// } -/// ``` #[proc_macro_derive(Any, attributes(rune))] pub fn any(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let derive = syn::parse_macro_input!(input as any::Derive); derive.expand().unwrap_or_else(to_compile_errors).into() } -/// Internal macro to implement external. #[proc_macro] #[doc(hidden)] pub fn __internal_impl_any(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -373,7 +151,6 @@ pub fn __internal_impl_any(input: proc_macro::TokenStream) -> proc_macro::TokenS .into() } -/// Internal macro to instrument a function which is threading AST. #[proc_macro_attribute] #[doc(hidden)] pub fn __instrument_ast( diff --git a/crates/rune/src/any.rs b/crates/rune/src/any.rs index c182b8ea9..dc92a7637 100644 --- a/crates/rune/src/any.rs +++ b/crates/rune/src/any.rs @@ -3,6 +3,33 @@ use core::any; use crate::compile::Named; use crate::hash::Hash; +/// 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(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; +/// +/// #[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; /// A trait which can be stored inside of an [AnyObj](crate::runtime::AnyObj). diff --git a/crates/rune/src/ast/spanned.rs b/crates/rune/src/ast/spanned.rs index ff077f400..c012e36c1 100644 --- a/crates/rune/src/ast/spanned.rs +++ b/crates/rune/src/ast/spanned.rs @@ -6,7 +6,11 @@ use crate::no_std::vec::Vec; use crate::ast::Span; use crate::parse::{Id, NonZeroId}; -pub use rune_macros::{OptionSpanned, Spanned}; +/// Helper derive to implement [`OptionSpanned`]. +pub use rune_macros::OptionSpanned; + +/// Helper derive to implement [`Spanned`]. +pub use rune_macros::Spanned; /// Types for which we can get a span. pub trait Spanned { diff --git a/crates/rune/src/compile.rs b/crates/rune/src/compile.rs index e4ab23a02..ad74ae26d 100644 --- a/crates/rune/src/compile.rs +++ b/crates/rune/src/compile.rs @@ -59,21 +59,6 @@ pub mod meta; pub(crate) use self::meta::{Doc, ItemMeta}; pub use self::meta::{MetaRef, SourceMeta}; -mod function_meta; -pub(crate) use self::function_meta::{AssociatedFunctionData, FunctionData, IterFunctionArgs}; -pub use self::function_meta::{ - AssociatedFunctionKind, AssociatedFunctionName, FunctionMeta, MacroMeta, ToFieldFunction, - ToInstance, -}; -#[doc(hidden)] -pub use self::function_meta::{FunctionMetaData, FunctionMetaKind, MacroMetaData, MacroMetaKind}; - -mod module; -pub use self::module::{ - AssocType, AssociatedFunction, AssociatedFunctionKey, AsyncFunction, AsyncInstFn, Function, - InstFn, InstallWith, Module, Variant, -}; - mod pool; pub(crate) use self::pool::{ItemId, ModId, ModMeta, Pool}; diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index 7e25e00ab..fac486440 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -5,13 +5,12 @@ use crate::no_std::sync::Arc; use crate::collections::{HashMap, HashSet}; use crate::compile::meta; -use crate::compile::module::{ - AssociatedFunction, Function, InternalEnum, Macro, Module, ModuleFunction, Type, - TypeSpecification, UnitType, VariantKind, -}; use crate::compile::{ - AssociatedFunctionKey, AssociatedFunctionKind, ComponentRef, ContextError, Docs, IntoComponent, - Item, ItemBuf, MetaInfo, Names, + ComponentRef, ContextError, Docs, IntoComponent, Item, ItemBuf, MetaInfo, Names, +}; +use crate::module::{ + AssociatedKey, AssociatedKind, Function, InternalEnum, Module, ModuleAssociated, + ModuleFunction, ModuleMacro, Type, TypeSpecification, UnitType, VariantKind, }; use crate::runtime::{ ConstValue, FunctionHandler, MacroHandler, Protocol, RuntimeContext, StaticType, TypeCheck, @@ -111,7 +110,7 @@ pub struct Context { functions: HashMap>, /// Information on associated types. #[cfg(feature = "doc")] - associated: HashMap>, + associated: HashMap>, /// Registered native macro handlers. macros: HashMap>, /// Registered types. @@ -252,8 +251,8 @@ impl Context { self.install_internal_enum(module, internal_enum, Docs::default())?; } - for (key, inst) in &module.associated_functions { - self.install_associated_function(module, key, inst)?; + for (key, assoc) in &module.associated { + self.install_associated(module, key, assoc)?; } Ok(()) @@ -340,7 +339,7 @@ impl Context { /// Get all associated types for the given hash. #[cfg(feature = "doc")] - pub(crate) fn associated(&self, hash: Hash) -> impl Iterator + '_ { + pub(crate) fn associated(&self, hash: Hash) -> impl Iterator + '_ { self.associated .get(&hash) .into_iter() @@ -571,7 +570,7 @@ impl Context { args: f.args, is_test: false, is_bench: false, - instance_function: f.instance_function, + instance_function: false, }, f.docs.clone(), ))?; @@ -584,7 +583,7 @@ impl Context { &mut self, module: &Module, item: &Item, - m: &Macro, + m: &ModuleMacro, ) -> Result<(), ContextError> { let item = module.item.join(item); let hash = Hash::type_hash(&item); @@ -634,11 +633,11 @@ impl Context { Ok(()) } - fn install_associated_function( + fn install_associated( &mut self, module: &Module, - key: &AssociatedFunctionKey, - assoc: &AssociatedFunction, + key: &AssociatedKey, + assoc: &ModuleAssociated, ) -> Result<(), ContextError> { let info = match self .types_rev @@ -696,7 +695,7 @@ impl Context { // // The other alternatives are protocol functions (which are not free) // and plain hashes. - if let AssociatedFunctionKind::Instance(name) = &assoc.name.kind { + if let AssociatedKind::Instance(name) = &assoc.name.kind { let item = info.item.extended(name); self.names.insert(&item); @@ -863,7 +862,7 @@ impl Context { } /// Add a piece of internal tuple meta. - fn add_internal_tuple( + fn add_internal_tuple( &mut self, module: &Module, enum_item: Option<(Hash, usize)>, @@ -873,7 +872,7 @@ impl Context { docs: Docs, ) -> Result<(), ContextError> where - C: Function, + C: Function, C::Return: TypeOf, { let type_hash = ::type_hash(); diff --git a/crates/rune/src/compile/context_error.rs b/crates/rune/src/compile/context_error.rs index a061f03e5..48bb03302 100644 --- a/crates/rune/src/compile/context_error.rs +++ b/crates/rune/src/compile/context_error.rs @@ -23,9 +23,11 @@ pub enum ContextError { signature: Box, hash: Hash, }, - #[error("Function with name `{name}` already exists")] + #[error("Function `{name}` already exists")] ConflictingFunctionName { name: ItemBuf }, - #[error("Constant with name `{name}` already exists")] + #[error("Macro `{name}` already exists")] + ConflictingMacroName { name: ItemBuf }, + #[error("Constant `{name}` already exists")] ConflictingConstantName { name: ItemBuf }, #[error("Instance function `{name}` for type `{type_info}` already exists")] ConflictingInstanceFunction { type_info: TypeInfo, name: Box }, @@ -49,10 +51,6 @@ pub enum ContextError { ConflictingType { item: ItemBuf, type_info: TypeInfo }, #[error("Type `{item}` at `{type_info}` already has a specification")] ConflictingTypeMeta { item: ItemBuf, type_info: TypeInfo }, - #[error("Type `{item}` with info `{type_info}` isn't registered")] - MissingType { item: ItemBuf, type_info: TypeInfo }, - #[error("Type `{item}` with info `{type_info}` is registered but is not an enum")] - MissingEnum { item: ItemBuf, type_info: TypeInfo }, #[error("Conflicting meta hash `{hash}` for `{existing}` when inserting item `{item}`")] ConflictingMetaHash { item: ItemBuf, @@ -63,12 +61,18 @@ pub enum ContextError { ConflictingTypeHash { hash: Hash, existing: Hash }, #[error("Variant with `{item}` already exists")] ConflictingVariant { item: ItemBuf }, - #[error("Instance `{instance_type}` does not exist in module")] - MissingInstance { instance_type: TypeInfo }, #[error("Error when converting to constant value: {error}")] ValueError { error: VmError }, - #[error("Missing variant {index} for `{type_info}`")] - MissingVariant { type_info: TypeInfo, index: usize }, #[error("Constructor for variant {index} in `{type_info}` has already been registered")] VariantConstructorConflict { type_info: TypeInfo, index: usize }, + #[error("Type `{item}` with info `{type_info}` isn't registered")] + MissingType { item: ItemBuf, type_info: TypeInfo }, + #[error("Type `{item}` with info `{type_info}` is registered but is not an enum")] + MissingEnum { item: ItemBuf, type_info: TypeInfo }, + #[error("Instance `{instance_type}` does not exist in module")] + MissingInstance { instance_type: TypeInfo }, + #[error("Missing variant {index} for `{type_info}`")] + MissingVariant { type_info: TypeInfo, index: usize }, + #[error("Expected associated function")] + ExpectedAssociated, } diff --git a/crates/rune/src/compile/meta.rs b/crates/rune/src/compile/meta.rs index db416ad15..95a6809da 100644 --- a/crates/rune/src/compile/meta.rs +++ b/crates/rune/src/compile/meta.rs @@ -9,11 +9,9 @@ use crate::no_std::sync::Arc; use crate::ast::{LitStr, Span}; use crate::collections::HashSet; use crate::compile::attrs::Attributes; -use crate::compile::{ - self, AssociatedFunctionKind, Item, ItemBuf, ItemId, Location, MetaInfo, ModId, Pool, - Visibility, -}; +use crate::compile::{self, Item, ItemBuf, ItemId, Location, MetaInfo, ModId, Pool, Visibility}; use crate::hash::Hash; +use crate::module::AssociatedKind; use crate::parse::{Id, ResolveContext}; use crate::runtime::{ConstValue, TypeInfo}; @@ -284,7 +282,7 @@ pub(crate) enum SignatureKind { /// An instance function or method Instance { /// Name of the instance function. - name: AssociatedFunctionKind, + name: AssociatedKind, /// Information on the self type. self_type_info: TypeInfo, }, diff --git a/crates/rune/src/compile/module.rs b/crates/rune/src/compile/module.rs deleted file mode 100644 index 693da76a6..000000000 --- a/crates/rune/src/compile/module.rs +++ /dev/null @@ -1,1537 +0,0 @@ -//! Crate used for definint native *modules*. -//! -//! A native module is one that provides rune with functions and types through -//! native code. - -use core::fmt; -use core::future; - -use crate::no_std::prelude::*; -use crate::no_std::sync::Arc; - -use crate::collections::{HashMap, HashSet}; -use crate::compile::{ - self, AssociatedFunctionData, AssociatedFunctionKind, AssociatedFunctionName, ContextError, - Docs, FunctionData, FunctionMeta, FunctionMetaKind, IntoComponent, ItemBuf, IterFunctionArgs, - MacroMeta, MacroMetaKind, Named, ToFieldFunction, ToInstance, -}; -use crate::macros::{MacroContext, TokenStream}; -use crate::runtime::{ - ConstValue, FromValue, FullTypeOf, FunctionHandler, Future, GeneratorState, MacroHandler, - MaybeTypeOf, Protocol, Stack, StaticType, ToValue, TypeCheck, TypeInfo, TypeOf, - UnsafeFromValue, Value, VmErrorKind, VmResult, -}; -use crate::Hash; - -/// Trait to handle the installation of auxilliary functions for a type -/// installed into a module. -pub trait InstallWith { - /// Hook to install more things into the module. - fn install_with(_: &mut Module) -> Result<(), ContextError> { - Ok(()) - } -} - -/// The static hash and diagnostical information about a type. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct AssocType { - /// Hash of the type. - pub hash: Hash, - /// Type information of the instance function. - pub type_info: TypeInfo, -} - -/// Specialized information on `Option` types. -pub(crate) struct UnitType { - /// Item of the unit type. - pub(crate) name: Box, -} - -/// Specialized information on `GeneratorState` types. -pub(crate) struct InternalEnum { - /// The name of the internal enum. - pub(crate) name: &'static str, - /// The result type. - pub(crate) base_type: ItemBuf, - /// The static type of the enum. - pub(crate) static_type: &'static StaticType, - /// Internal variants. - pub(crate) variants: Vec, -} - -impl InternalEnum { - /// Construct a new handler for an internal enum. - fn new(name: &'static str, base_type: N, static_type: &'static StaticType) -> Self - where - N: IntoIterator, - N::Item: IntoComponent, - { - InternalEnum { - name, - base_type: ItemBuf::with_item(base_type), - static_type, - variants: Vec::new(), - } - } - - /// Register a new variant. - fn variant(&mut self, name: &'static str, type_check: TypeCheck, constructor: C) - where - C: Function, - { - let constructor: Arc = - Arc::new(move |stack, args| constructor.fn_call(stack, args)); - - self.variants.push(InternalVariant { - name, - type_check, - args: C::args(), - constructor, - }); - } -} - -/// Internal variant. -pub(crate) struct InternalVariant { - /// The name of the variant. - pub(crate) name: &'static str, - /// Type check for the variant. - pub(crate) type_check: TypeCheck, - /// Arguments for the variant. - pub(crate) args: usize, - /// The constructor of the variant. - pub(crate) constructor: Arc, -} - -/// Data for an opaque type. If `spec` is set, indicates things which are known -/// about that type. -pub(crate) struct Type { - /// The name of the installed type which will be the final component in the - /// item it will constitute. - pub(crate) name: Box, - /// Type information for the installed type. - pub(crate) type_info: TypeInfo, - /// The specification for the type. - pub(crate) spec: Option, -} - -/// Metadata about a variant. -pub struct Variant { - /// Variant metadata. - pub(crate) kind: VariantKind, - /// Handler to use if this variant can be constructed through a regular function call. - pub(crate) constructor: Option>, -} - -impl fmt::Debug for Variant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Variant") - .field("kind", &self.kind) - .field("constructor", &self.constructor.is_some()) - .finish() - } -} - -/// The kind of the variant. -#[derive(Debug)] -pub(crate) enum VariantKind { - /// Variant is a Tuple variant. - Tuple(Tuple), - /// Variant is a Struct variant. - Struct(Struct), - /// Variant is a Unit variant. - Unit, -} - -impl Variant { - /// Construct metadata for a tuple variant. - #[inline] - pub fn tuple(args: usize) -> Self { - Self { - kind: VariantKind::Tuple(Tuple { args }), - constructor: None, - } - } - - /// Construct metadata for a tuple variant. - #[inline] - pub fn st(fields: [&'static str; N]) -> Self { - Self { - kind: VariantKind::Struct(Struct { - fields: fields.into_iter().map(Box::::from).collect(), - }), - constructor: None, - } - } - - /// Construct metadata for a unit variant. - #[inline] - pub fn unit() -> Self { - Self { - kind: VariantKind::Unit, - constructor: None, - } - } -} - -/// Metadata about a tuple or tuple variant. -#[derive(Debug)] -pub struct Tuple { - /// The number of fields. - pub(crate) args: usize, -} - -/// The type specification for a native struct. -#[derive(Debug)] -pub(crate) struct Struct { - /// The names of the struct fields known at compile time. - pub(crate) fields: HashSet>, -} - -/// The type specification for a native enum. -pub(crate) struct Enum { - /// The variants. - pub(crate) variants: Vec<(Box, Variant)>, -} - -/// A type specification. -pub(crate) enum TypeSpecification { - Struct(Struct), - Enum(Enum), -} - -/// The data of an associated function. -#[derive(Clone)] -#[non_exhaustive] -pub struct AssociatedFunction { - /// Handle of the associated function. - pub(crate) handler: Arc, - /// Type information of the associated function. - pub(crate) type_info: TypeInfo, - /// If the function is asynchronous. - pub(crate) is_async: bool, - /// Arguments the function receives. - pub(crate) args: Option, - /// The full name of the associated function. - pub(crate) name: AssociatedFunctionName, - /// The return type of an associated function. - pub(crate) return_type: Option, - /// Argument types passed in. - pub(crate) argument_types: Box<[Option]>, - /// The documentation of the associated function. - pub(crate) docs: Docs, -} - -/// A key that identifies an associated function. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub struct AssociatedFunctionKey { - /// The type the associated function belongs to. - pub type_hash: Hash, - /// The kind of the associated function. - pub kind: AssociatedFunctionKind, - /// The type parameters of the associated function. - pub parameters: Hash, -} - -pub(crate) struct ModuleFunction { - pub(crate) handler: Arc, - pub(crate) is_async: bool, - pub(crate) args: Option, - pub(crate) instance_function: bool, - /// The return type of a module function. - pub(crate) return_type: Option, - /// The arguments types of a module function. - pub(crate) argument_types: Box<[Option]>, - /// Documentation of the module function. - pub(crate) docs: Docs, -} - -pub(crate) struct Macro { - pub(crate) handler: Arc, - pub(crate) docs: Docs, -} - -/// 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]. -#[derive(Default)] -pub struct Module { - /// A special identifier for this module, which will cause it to not conflict if installed multiple times. - pub(crate) unique: Option<&'static str>, - /// The name of the module. - pub(crate) item: ItemBuf, - /// Functions. - pub(crate) functions: HashMap, - /// MacroHandler handlers. - pub(crate) macros: HashMap, - /// Constant values. - pub(crate) constants: HashMap, - /// Associated functions. - pub(crate) associated_functions: HashMap, - /// Registered types. - pub(crate) types: HashMap, - /// Registered unit type. - pub(crate) unit_type: Option, - /// Registered generator state type. - pub(crate) internal_enums: Vec, -} - -impl Module { - /// Create an empty module for the root path. - pub fn new() -> Self { - Self::default() - } - - /// Modify the current module to utilise a special identifier. - #[doc(hidden)] - pub fn with_unique(self, id: &'static str) -> Self { - Self { - unique: Some(id), - ..self - } - } - - /// Construct a new module for the given item. - pub fn with_item(iter: I) -> Self - where - I: IntoIterator, - I::Item: IntoComponent, - { - Self::inner_new(ItemBuf::with_item(iter)) - } - - /// Construct a new module for the given crate. - pub fn with_crate(name: &str) -> Self { - Self::inner_new(ItemBuf::with_crate(name)) - } - - /// Construct a new module for the given crate. - pub fn with_crate_item(name: &str, iter: I) -> Self - where - I: IntoIterator, - I::Item: IntoComponent, - { - Self::inner_new(ItemBuf::with_crate_item(name, iter)) - } - - fn inner_new(item: ItemBuf) -> Self { - Self { - unique: None, - item, - functions: HashMap::default(), - macros: HashMap::default(), - associated_functions: HashMap::default(), - types: HashMap::default(), - unit_type: None, - internal_enums: Vec::new(), - constants: HashMap::default(), - } - } - - /// Register a type. Registering a type is mandatory in order to register - /// instance functions using that type. - /// - /// This will allow the type to be used within scripts, using the item named - /// here. - /// - /// # Examples - /// - /// ``` - /// use rune::Any; - /// - /// #[derive(Any)] - /// struct MyBytes { - /// queue: Vec, - /// } - /// - /// impl MyBytes { - /// fn len(&self) -> usize { - /// self.queue.len() - /// } - /// } - /// - /// // Register `len` without registering a type. - /// let mut module = rune::Module::default(); - /// // Note: cannot do this until we have registered a type. - /// module.inst_fn("len", MyBytes::len)?; - /// - /// let mut context = rune::Context::new(); - /// assert!(context.install(module).is_err()); - /// - /// // Register `len` properly. - /// let mut module = rune::Module::default(); - /// - /// module.ty::()?; - /// module.inst_fn("len", MyBytes::len)?; - /// - /// let mut context = rune::Context::new(); - /// assert!(context.install(module).is_ok()); - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn ty(&mut self) -> Result<(), ContextError> - where - T: Named + TypeOf + InstallWith, - { - let type_hash = T::type_hash(); - let type_info = T::type_info(); - - let ty = Type { - name: T::full_name(), - type_info, - spec: None, - }; - - if let Some(old) = self.types.insert(type_hash, ty) { - return Err(ContextError::ConflictingType { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: old.type_info, - }); - } - - T::install_with(self)?; - Ok(()) - } - - /// 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. - pub fn struct_meta( - &mut self, - fields: [&'static str; N], - ) -> Result<(), ContextError> - where - T: Named + TypeOf, - { - let type_hash = T::type_hash(); - - let ty = match self.types.get_mut(&type_hash) { - Some(ty) => ty, - None => { - return Err(ContextError::MissingType { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: T::type_info(), - }); - } - }; - - let old = ty.spec.replace(TypeSpecification::Struct(Struct { - fields: fields.into_iter().map(Box::::from).collect(), - })); - - if old.is_some() { - return Err(ContextError::ConflictingTypeMeta { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: ty.type_info.clone(), - }); - } - - Ok(()) - } - - /// Register enum metadata for the given type `T`. This allows an enum to be - /// used in limited ways in Rune. - pub fn enum_meta( - &mut self, - variants: [(&'static str, Variant); N], - ) -> Result<(), ContextError> - where - T: Named + TypeOf, - { - let type_hash = T::type_hash(); - - let ty = match self.types.get_mut(&type_hash) { - Some(ty) => ty, - None => { - return Err(ContextError::MissingType { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: T::type_info(), - }); - } - }; - - let old = ty.spec.replace(TypeSpecification::Enum(Enum { - variants: variants - .into_iter() - .map(|(name, variant)| (Box::from(name), variant)) - .collect(), - })); - - if old.is_some() { - return Err(ContextError::ConflictingTypeMeta { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: ty.type_info.clone(), - }); - } - - Ok(()) - } - - /// Register a variant constructor for type `T`. - pub fn variant_constructor( - &mut self, - index: usize, - constructor: Func, - ) -> Result<(), ContextError> - where - T: Named + TypeOf, - Func: Function, - { - let type_hash = T::type_hash(); - - let ty = match self.types.get_mut(&type_hash) { - Some(ty) => ty, - None => { - return Err(ContextError::MissingType { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: T::type_info(), - }); - } - }; - - let en = match &mut ty.spec { - Some(TypeSpecification::Enum(en)) => en, - _ => { - return Err(ContextError::MissingEnum { - item: ItemBuf::with_item(&[T::full_name()]), - type_info: T::type_info(), - }); - } - }; - - let variant = match en.variants.get_mut(index) { - Some((_, variant)) => variant, - _ => { - return Err(ContextError::MissingVariant { - type_info: T::type_info(), - index, - }); - } - }; - - if variant.constructor.is_some() { - return Err(ContextError::VariantConstructorConflict { - type_info: T::type_info(), - index, - }); - } - - variant.constructor = Some(Arc::new(move |stack, args| { - constructor.fn_call(stack, args) - })); - - Ok(()) - } - - /// Construct type information for the `unit` type. - /// - /// Registering this allows the given type to be used in Rune scripts when - /// referring to the `unit` type. - /// - /// # Examples - /// - /// This shows how to register the unit type `()` as `nonstd::unit`. - /// - /// ``` - /// use rune::Module; - /// - /// let mut module = Module::with_item(["nonstd"]); - /// module.unit("unit")?; - /// # Ok::<_, rune::Error>(()) - pub fn unit(&mut self, name: N) -> Result<(), ContextError> - where - N: AsRef, - { - if self.unit_type.is_some() { - return Err(ContextError::UnitAlreadyPresent); - } - - self.unit_type = Some(UnitType { - name: >::from(name.as_ref()), - }); - - Ok(()) - } - - /// Construct the type information for the `GeneratorState` type. - /// - /// Registering this allows the given type to be used in Rune scripts when - /// referring to the `GeneratorState` type. - /// - /// # Examples - /// - /// This shows how to register the `GeneratorState` as - /// `nonstd::generator::GeneratorState`. - /// - /// ``` - /// use rune::Module; - /// - /// let mut module = Module::with_crate_item("nonstd", ["generator"]); - /// module.generator_state(["GeneratorState"])?; - /// # Ok::<_, rune::Error>(()) - pub fn generator_state(&mut self, name: N) -> Result<(), ContextError> - where - N: IntoIterator, - N::Item: IntoComponent, - { - let mut enum_ = - InternalEnum::new("GeneratorState", name, crate::runtime::GENERATOR_STATE_TYPE); - - // Note: these numeric variants are magic, and must simply match up with - // what's being used in the virtual machine implementation for these - // types. - enum_.variant( - "Complete", - TypeCheck::GeneratorState(0), - GeneratorState::Complete, - ); - enum_.variant( - "Yielded", - TypeCheck::GeneratorState(1), - GeneratorState::Yielded, - ); - - self.internal_enums.push(enum_); - Ok(()) - } - /// Construct type information for the `Option` type. - /// - /// Registering this allows the given type to be used in Rune scripts when - /// referring to the `Option` type. - /// - /// # Examples - /// - /// This shows how to register the `Option` as `nonstd::option::Option`. - /// - /// ``` - /// use rune::Module; - /// - /// let mut module = Module::with_crate_item("nonstd", ["option"]); - /// module.option(["Option"])?; - /// # Ok::<_, rune::Error>(()) - pub fn option(&mut self, name: N) -> Result<(), ContextError> - where - N: IntoIterator, - N::Item: IntoComponent, - { - let mut enum_ = InternalEnum::new("Option", name, crate::runtime::OPTION_TYPE); - - // Note: these numeric variants are magic, and must simply match up with - // what's being used in the virtual machine implementation for these - // types. - enum_.variant("Some", TypeCheck::Option(0), Option::::Some); - enum_.variant("None", TypeCheck::Option(1), || Option::::None); - self.internal_enums.push(enum_); - Ok(()) - } - - /// Construct type information for the internal `Result` type. - /// - /// Registering this allows the given type to be used in Rune scripts when - /// referring to the `Result` type. - /// - /// # Examples - /// - /// This shows how to register the `Result` as `nonstd::result::Result`. - /// - /// ``` - /// use rune::Module; - /// - /// let mut module = Module::with_crate_item("nonstd", ["result"]); - /// module.result(["Result"])?; - /// # Ok::<_, rune::Error>(()) - pub fn result(&mut self, name: N) -> Result<(), ContextError> - where - N: IntoIterator, - N::Item: IntoComponent, - { - let mut enum_ = InternalEnum::new("Result", name, crate::runtime::RESULT_TYPE); - - // Note: these numeric variants are magic, and must simply match up with - // what's being used in the virtual machine implementation for these - // types. - enum_.variant("Ok", TypeCheck::Result(0), Result::::Ok); - enum_.variant("Err", TypeCheck::Result(1), Result::::Err); - self.internal_enums.push(enum_); - Ok(()) - } - - /// Register a constant value, at a crate, module or associated level. - /// - /// # Examples - /// - /// ``` - /// - /// let mut module = rune::Module::default(); - /// - /// module.constant(["TEN"], 10)?; // a global TEN value - /// module.constant(["MyType", "TEN"], 10)?; // looks like an associated value - /// - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn constant(&mut self, name: N, value: V) -> Result<(), ContextError> - where - N: IntoIterator, - N::Item: IntoComponent, - V: ToValue, - { - let name = ItemBuf::with_item(name); - - if self.constants.contains_key(&name) { - return Err(ContextError::ConflictingConstantName { name }); - } - - let value = match value.to_value() { - VmResult::Ok(v) => v, - VmResult::Err(error) => return Err(ContextError::ValueError { error }), - }; - - let constant_value = match ::from_value(value) { - VmResult::Ok(v) => v, - VmResult::Err(error) => return Err(ContextError::ValueError { error }), - }; - - self.constants.insert(name, constant_value); - - Ok(()) - } - - /// Register a native macro handler through its meta. - /// - /// The metadata must be provided by annotating the function with - /// [`#[rune::macro_]`][crate::macro_]. - /// - /// This has the benefit that it captures documentation comments which can - /// be used when generating documentation or referencing the function - /// through code sense systems. - /// - /// # Examples - /// - /// ``` - /// use rune::Module; - /// use rune::ast; - /// use rune::compile; - /// use rune::macros::{quote, MacroContext, TokenStream}; - /// use rune::parse::Parser; - /// - /// /// Takes an identifier and converts it into a string. - /// /// - /// /// # Examples - /// /// - /// /// ```rune - /// /// assert_eq!(ident_to_string!(Hello), "Hello"); - /// /// ``` - /// #[rune::macro_] - /// fn ident_to_string(ctx: &mut MacroContext<'_>, stream: &TokenStream) -> compile::Result { - /// let mut p = Parser::from_token_stream(stream, ctx.stream_span()); - /// let ident = p.parse_all::()?; - /// let ident = ctx.resolve(ident)?.to_owned(); - /// let string = ctx.lit(&ident); - /// Ok(quote!(#string).into_token_stream(ctx)) - /// } - /// - /// let mut m = Module::new(); - /// m.macro_meta(ident_to_string)?; - /// Ok::<_, rune::Error>(()) - /// ``` - #[inline] - pub fn macro_meta(&mut self, meta: MacroMeta) -> Result<(), ContextError> { - let meta = meta(); - - match meta.kind { - MacroMetaKind::Function(data) => { - if self.macros.contains_key(&data.name) { - return Err(ContextError::ConflictingFunctionName { name: data.name }); - } - - let mut docs = Docs::default(); - docs.set_docs(meta.docs); - - self.macros.insert( - data.name.clone(), - Macro { - handler: data.handler, - docs, - }, - ); - } - } - - Ok(()) - } - - /// Register a native macro handler. - /// - /// If possible, [`Module::function_meta`] should be used since it includes more - /// useful information about the function. - /// - /// # Examples - /// - /// ``` - /// use rune::Module; - /// use rune::ast; - /// use rune::compile; - /// use rune::macros::{quote, MacroContext, TokenStream}; - /// use rune::parse::Parser; - /// - /// fn ident_to_string(ctx: &mut MacroContext<'_>, stream: &TokenStream) -> compile::Result { - /// let mut p = Parser::from_token_stream(stream, ctx.stream_span()); - /// let ident = p.parse_all::()?; - /// let ident = ctx.resolve(ident)?.to_owned(); - /// let string = ctx.lit(&ident); - /// Ok(quote!(#string).into_token_stream(ctx)) - /// } - /// - /// let mut m = Module::new(); - /// m.macro_(["ident_to_string"], ident_to_string)?; - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn macro_(&mut self, name: N, f: M) -> Result<(), ContextError> - where - M: 'static - + Send - + Sync - + Fn(&mut MacroContext<'_>, &TokenStream) -> compile::Result, - N: IntoIterator, - N::Item: IntoComponent, - { - let name = ItemBuf::with_item(name); - - if self.macros.contains_key(&name) { - return Err(ContextError::ConflictingFunctionName { name }); - } - - let handler: Arc = Arc::new(f); - self.macros.insert( - name, - Macro { - handler, - docs: Docs::default(), - }, - ); - Ok(()) - } - - /// Register a function handler through its meta. - /// - /// The metadata must be provided by annotating the function with - /// [`#[rune::function]`][crate::function]. - /// - /// This has the benefit that it captures documentation comments which can - /// be used when generating documentation or referencing the function - /// through code sense systems. - /// - /// # Examples - /// - /// ``` - /// use rune::{Module, ContextError}; - /// - /// /// This is a pretty neat function. - /// #[rune::function] - /// fn to_string(string: &str) -> String { - /// string.to_string() - /// } - /// - /// /// This is a pretty neat download function - /// #[rune::function] - /// async fn download(url: &str) -> rune::Result { - /// todo!() - /// } - /// - /// fn module() -> Result { - /// let mut m = Module::new(); - /// m.function_meta(to_string)?; - /// m.function_meta(download)?; - /// Ok(m) - /// } - /// ``` - /// - /// Registering instance functions: - /// - /// ``` - /// use rune::Any; - /// - /// #[derive(Any)] - /// struct MyBytes { - /// queue: Vec, - /// } - /// - /// impl MyBytes { - /// fn new() -> Self { - /// Self { - /// queue: Vec::new(), - /// } - /// } - /// - /// #[rune::function] - /// fn len(&self) -> usize { - /// self.queue.len() - /// } - /// - /// #[rune::function] - /// async fn download(&self, url: &str) -> rune::Result<()> { - /// todo!() - /// } - /// } - /// - /// let mut module = rune::Module::default(); - /// - /// module.ty::()?; - /// module.function_meta(MyBytes::len)?; - /// module.function_meta(MyBytes::download)?; - /// # Ok::<_, rune::Error>(()) - /// ``` - #[inline] - pub fn function_meta(&mut self, meta: FunctionMeta) -> Result<(), ContextError> { - let meta = meta(); - - match meta.kind { - FunctionMetaKind::Function(data) => { - let mut docs = Docs::default(); - docs.set_docs(meta.docs); - docs.set_arguments(meta.arguments); - self.function_inner(data, docs) - } - FunctionMetaKind::AssociatedFunction(data) => { - let mut docs = Docs::default(); - docs.set_docs(meta.docs); - docs.set_arguments(meta.arguments); - self.assoc_fn(data, docs) - } - } - } - - /// Register a function. - /// - /// If possible, [`Module::function_meta`] should be used since it includes more - /// useful information about the function. - /// - /// # Examples - /// - /// ``` - /// fn add_ten(value: i64) -> i64 { - /// value + 10 - /// } - /// - /// let mut module = rune::Module::default(); - /// - /// module.function(["add_ten"], add_ten)?; - /// module.function(["empty"], || Ok::<_, rune::Error>(()))?; - /// module.function(["string"], |a: String| Ok::<_, rune::Error>(()))?; - /// module.function(["optional"], |a: Option| Ok::<_, rune::Error>(()))?; - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn function(&mut self, name: N, f: Func) -> Result<(), ContextError> - where - Func: Function, - Func::Return: MaybeTypeOf, - N: IntoIterator, - N::Item: IntoComponent, - Args: IterFunctionArgs, - { - self.function_inner(FunctionData::new(name, f), Docs::default()) - } - - /// Register an asynchronous function. - /// - /// If possible, [`Module::function_meta`] should be used since it includes more - /// useful information about the function. - /// - /// # Examples - /// - /// ``` - /// let mut module = rune::Module::default(); - /// - /// async fn empty() { - /// } - /// - /// async fn empty_fallible() -> rune::Result<()> { - /// Ok(()) - /// } - /// - /// async fn string(a: String) -> rune::Result<()> { - /// Ok(()) - /// } - /// - /// async fn optional(a: Option) -> rune::Result<()> { - /// Ok(()) - /// } - /// - /// module.async_function(["empty"], empty)?; - /// module.async_function(["empty_fallible"], empty_fallible)?; - /// module.async_function(["string"], string)?; - /// module.async_function(["optional"], optional)?; - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn async_function(&mut self, name: N, f: Func) -> Result<(), ContextError> - where - Func: AsyncFunction, - Func::Output: MaybeTypeOf, - N: IntoIterator, - N::Item: IntoComponent, - Args: IterFunctionArgs, - { - self.function_inner(FunctionData::new_async(name, f), Docs::default()) - } - - /// Register an instance function. - /// - /// If possible, [`Module::function_meta`] should be used since it includes more - /// useful information about the function. - /// - /// # Examples - /// - /// ``` - /// use rune::Any; - /// - /// #[derive(Any)] - /// struct MyBytes { - /// queue: Vec, - /// } - /// - /// impl MyBytes { - /// fn new() -> Self { - /// Self { - /// queue: Vec::new(), - /// } - /// } - /// - /// fn len(&self) -> usize { - /// self.queue.len() - /// } - /// } - /// - /// let mut module = rune::Module::default(); - /// - /// module.ty::()?; - /// module.function(["MyBytes", "new"], MyBytes::new)?; - /// module.inst_fn("len", MyBytes::len)?; - /// - /// let mut context = rune::Context::new(); - /// context.install(module)?; - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn inst_fn(&mut self, name: N, f: Func) -> Result<(), ContextError> - where - N: ToInstance, - Func: InstFn, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, - { - self.assoc_fn( - AssociatedFunctionData::new(name.to_instance(), f), - Docs::default(), - ) - } - - /// Register an asynchronous instance function. - /// - /// If possible, [`Module::function_meta`] should be used since it includes more - /// useful information about the function. - /// - /// # Examples - /// - /// ``` - /// use std::sync::atomic::AtomicU32; - /// use std::sync::Arc; - /// use rune::Any; - /// - /// #[derive(Clone, Debug, Any)] - /// struct MyType { - /// value: Arc, - /// } - /// - /// impl MyType { - /// async fn test(&self) -> rune::Result<()> { - /// Ok(()) - /// } - /// } - /// - /// let mut module = rune::Module::default(); - /// - /// module.ty::()?; - /// module.async_inst_fn("test", MyType::test)?; - /// # Ok::<_, rune::Error>(()) - /// ``` - pub fn async_inst_fn(&mut self, name: N, f: Func) -> Result<(), ContextError> - where - N: ToInstance, - Func: AsyncInstFn, - Func::Output: MaybeTypeOf, - Args: IterFunctionArgs, - { - self.assoc_fn( - AssociatedFunctionData::new_async(name.to_instance(), f), - Docs::default(), - ) - } - - /// Install a protocol function that interacts with the given field. - pub fn field_fn( - &mut self, - protocol: Protocol, - name: N, - f: Func, - ) -> Result<(), ContextError> - where - N: ToFieldFunction, - Func: InstFn, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, - { - self.assoc_fn( - AssociatedFunctionData::new(name.to_field_function(protocol), f), - Docs::default(), - ) - } - - /// 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]. - pub fn index_fn( - &mut self, - protocol: Protocol, - index: usize, - f: Func, - ) -> Result<(), ContextError> - where - Func: InstFn, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, - { - let name = AssociatedFunctionName::index(protocol, index); - self.assoc_fn(AssociatedFunctionData::new(name, f), Docs::default()) - } - - /// Register a raw function which interacts directly with the virtual - /// machine. - pub fn raw_fn(&mut self, name: N, f: F) -> Result<(), ContextError> - where - F: 'static + Fn(&mut Stack, usize) -> VmResult<()> + Send + Sync, - N: IntoIterator, - N::Item: IntoComponent, - { - let name = ItemBuf::with_item(name); - - if self.functions.contains_key(&name) { - return Err(ContextError::ConflictingFunctionName { name }); - } - - self.functions.insert( - name, - ModuleFunction { - handler: Arc::new(move |stack, args| f(stack, args)), - is_async: false, - args: None, - instance_function: false, - return_type: None, - argument_types: Box::from([]), - docs: Docs::default(), - }, - ); - - Ok(()) - } - - fn function_inner(&mut self, data: FunctionData, docs: Docs) -> Result<(), ContextError> { - if self.functions.contains_key(&data.name) { - return Err(ContextError::ConflictingFunctionName { name: data.name }); - } - - self.functions.insert( - data.name, - ModuleFunction { - handler: data.handler, - is_async: data.is_async, - args: data.args, - instance_function: false, - return_type: data.return_type, - argument_types: data.argument_types, - docs, - }, - ); - - Ok(()) - } - - /// Install an associated function. - fn assoc_fn(&mut self, data: AssociatedFunctionData, docs: Docs) -> Result<(), ContextError> { - let key = data.assoc_key(); - - if self.associated_functions.contains_key(&key) { - return Err(match data.name.kind { - AssociatedFunctionKind::Protocol(protocol) => { - ContextError::ConflictingProtocolFunction { - type_info: data.ty.type_info, - name: protocol.name.into(), - } - } - AssociatedFunctionKind::FieldFn(protocol, field) => { - ContextError::ConflictingFieldFunction { - type_info: data.ty.type_info, - name: protocol.name.into(), - field, - } - } - AssociatedFunctionKind::IndexFn(protocol, index) => { - ContextError::ConflictingIndexFunction { - type_info: data.ty.type_info, - name: protocol.name.into(), - index, - } - } - AssociatedFunctionKind::Instance(name) => { - ContextError::ConflictingInstanceFunction { - type_info: data.ty.type_info, - name, - } - } - }); - } - - let assoc_fn = AssociatedFunction { - handler: data.handler, - type_info: data.ty.type_info, - is_async: data.is_async, - args: data.args, - name: data.name, - return_type: data.return_type, - argument_types: data.argument_types, - docs, - }; - - self.associated_functions.insert(key, assoc_fn); - Ok(()) - } -} - -impl AsRef for Module { - #[inline] - fn as_ref(&self) -> &Module { - self - } -} - -/// Trait used to provide the [function][Module::function] function. -pub trait Function: 'static + Send + Sync { - /// The return type of the function. - #[doc(hidden)] - type Return; - - /// Get the number of arguments. - #[doc(hidden)] - fn args() -> usize; - - /// Perform the vm call. - #[doc(hidden)] - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; -} - -/// Trait used to provide the [async_function][Module::async_function] function. -pub trait AsyncFunction: 'static + Send + Sync { - /// The return type of the function. - #[doc(hidden)] - type Return: future::Future; - - /// The output produces by the future. - #[doc(hidden)] - type Output; - - /// Get the number of arguments. - #[doc(hidden)] - fn args() -> usize; - - /// Perform the vm call. - #[doc(hidden)] - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; -} - -/// Trait used to provide the [inst_fn][Module::inst_fn] function. -pub trait InstFn: 'static + Send + Sync { - /// The type of the instance. - #[doc(hidden)] - type Instance; - - /// The return type of the function. - #[doc(hidden)] - type Return; - - /// Get the number of arguments. - #[doc(hidden)] - fn args() -> usize; - - /// Access static information on the instance type with the associated - /// function. - #[doc(hidden)] - fn ty() -> AssocType; - - /// Perform the vm call. - #[doc(hidden)] - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; -} - -/// Trait used to provide the [async_inst_fn][Module::async_inst_fn] function. -pub trait AsyncInstFn: 'static + Send + Sync { - /// The type of the instance. - #[doc(hidden)] - type Instance; - - /// The return type of the function. - #[doc(hidden)] - type Return: future::Future; - - /// The output value of the async function. - #[doc(hidden)] - type Output; - - /// Get the number of arguments. - #[doc(hidden)] - fn args() -> usize; - - /// Access static information on the instance type with the associated - /// function. - #[doc(hidden)] - fn ty() -> AssocType; - - /// Perform the vm call. - #[doc(hidden)] - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; -} - -macro_rules! impl_register { - ($count:expr $(, $ty:ident $var:ident $num:expr)*) => { - impl Function<($($ty,)*)> for Func - where - Func: 'static + Send + Sync + Fn($($ty,)*) -> Return, - Return: ToValue, - $($ty: UnsafeFromValue,)* - { - type Return = Return; - - fn args() -> usize { - $count - } - - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { - impl_register!(@check-args $count, args); - - #[allow(unused_mut)] - let mut it = vm_try!(stack.drain($count)); - $(let $var = it.next().unwrap();)* - drop(it); - - // Safety: We hold a reference to the stack, so we can - // guarantee that it won't be modified. - // - // The scope is also necessary, since we mutably access `stack` - // when we return below. - #[allow(unused)] - let ret = unsafe { - impl_register!(@unsafe-vars $count, $($ty, $var, $num,)*); - let ret = self($(<$ty>::unsafe_coerce($var.0),)*); - impl_register!(@drop-stack-guards $($var),*); - ret - }; - - let ret = vm_try!(ret.to_value()); - stack.push(ret); - VmResult::Ok(()) - } - } - - impl AsyncFunction<($($ty,)*)> for Func - where - Func: 'static + Send + Sync + Fn($($ty,)*) -> Return, - Return: 'static + future::Future, - Return::Output: ToValue, - $($ty: 'static + UnsafeFromValue,)* - { - type Return = Return; - type Output = Return::Output; - - fn args() -> usize { - $count - } - - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { - impl_register!(@check-args $count, args); - - #[allow(unused_mut)] - let mut it = vm_try!(stack.drain($count)); - $(let $var = it.next().unwrap();)* - drop(it); - - // Safety: Future is owned and will only be called within the - // context of the virtual machine, which will provide - // exclusive thread-local access to itself while the future is - // being polled. - #[allow(unused_unsafe)] - let ret = unsafe { - impl_register!(@unsafe-vars $count, $($ty, $var, $num,)*); - - let fut = self($(<$ty>::unsafe_coerce($var.0),)*); - - Future::new(async move { - let output = fut.await; - impl_register!(@drop-stack-guards $($var),*); - let value = vm_try!(output.to_value()); - VmResult::Ok(value) - }) - }; - - let ret = vm_try!(ret.to_value()); - stack.push(ret); - VmResult::Ok(()) - } - } - - impl InstFn<(Instance, $($ty,)*)> for Func - where - Func: 'static + Send + Sync + Fn(Instance $(, $ty)*) -> Return, - Return: ToValue, - Instance: UnsafeFromValue + TypeOf, - $($ty: UnsafeFromValue,)* - { - type Instance = Instance; - type Return = Return; - - fn args() -> usize { - $count + 1 - } - - fn ty() -> AssocType { - AssocType { - hash: Instance::type_hash(), - type_info: Instance::type_info(), - } - } - - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { - impl_register!(@check-args ($count + 1), args); - - #[allow(unused_mut)] - let mut it = vm_try!(stack.drain($count + 1)); - let inst = it.next().unwrap(); - $(let $var = it.next().unwrap();)* - drop(it); - - // Safety: We hold a reference to the stack, so we can - // guarantee that it won't be modified. - // - // The scope is also necessary, since we mutably access `stack` - // when we return below. - #[allow(unused)] - let ret = unsafe { - impl_register!(@unsafe-inst-vars inst, $count, $($ty, $var, $num,)*); - let ret = self(Instance::unsafe_coerce(inst.0), $(<$ty>::unsafe_coerce($var.0),)*); - impl_register!(@drop-stack-guards inst, $($var),*); - ret - }; - - let ret = vm_try!(ret.to_value()); - stack.push(ret); - VmResult::Ok(()) - } - } - - impl AsyncInstFn<(Instance, $($ty,)*)> for Func - where - Func: 'static + Send + Sync + Fn(Instance $(, $ty)*) -> Return, - Return: 'static + future::Future, - Return::Output: ToValue, - Instance: UnsafeFromValue + TypeOf, - $($ty: UnsafeFromValue,)* - { - type Instance = Instance; - type Return = Return; - type Output = Return::Output; - - fn args() -> usize { - $count + 1 - } - - fn ty() -> AssocType { - AssocType { - hash: Instance::type_hash(), - type_info: Instance::type_info(), - } - } - - fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { - impl_register!(@check-args ($count + 1), args); - - #[allow(unused_mut)] - let mut it = vm_try!(stack.drain($count + 1)); - let inst = it.next().unwrap(); - $(let $var = it.next().unwrap();)* - drop(it); - - // Safety: Future is owned and will only be called within the - // context of the virtual machine, which will provide - // exclusive thread-local access to itself while the future is - // being polled. - #[allow(unused)] - let ret = unsafe { - impl_register!(@unsafe-inst-vars inst, $count, $($ty, $var, $num,)*); - - let fut = self(Instance::unsafe_coerce(inst.0), $(<$ty>::unsafe_coerce($var.0),)*); - - Future::new(async move { - let output = fut.await; - impl_register!(@drop-stack-guards inst, $($var),*); - let value = vm_try!(output.to_value()); - VmResult::Ok(value) - }) - }; - - let ret = vm_try!(ret.to_value()); - stack.push(ret); - VmResult::Ok(()) - } - } - }; - - // Expand to function variable bindings. - (@unsafe-vars $count:expr, $($ty:ty, $var:ident, $num:expr,)*) => { - $( - let $var = vm_try!(<$ty>::from_value($var).with_error(|| VmErrorKind::BadArgument { - arg: $count - $num, - })); - )* - }; - - // Expand to instance variable bindings. - (@unsafe-inst-vars $inst:ident, $count:expr, $($ty:ty, $var:ident, $num:expr,)*) => { - let $inst = vm_try!(Instance::from_value($inst).with_error(|| VmErrorKind::BadArgument { - arg: 0, - })); - - $( - let $var = vm_try!(<$ty>::from_value($var).with_error(|| VmErrorKind::BadArgument { - arg: 1 + $count - $num, - })); - )* - }; - - // Helper variation to drop all stack guards associated with the specified variables. - (@drop-stack-guards $($var:ident),* $(,)?) => {{ - $(drop(($var.1));)* - }}; - - (@check-args $expected:expr, $actual:expr) => { - if $actual != $expected { - return VmResult::err(VmErrorKind::BadArgumentCount { - actual: $actual, - expected: $expected, - }); - } - }; -} - -repeat_macro!(impl_register); diff --git a/crates/rune/src/compile/named.rs b/crates/rune/src/compile/named.rs index 47f2a0de8..bc548c9f7 100644 --- a/crates/rune/src/compile/named.rs +++ b/crates/rune/src/compile/named.rs @@ -1,6 +1,6 @@ use crate::no_std::prelude::*; -use crate::compile::InstallWith; +use crate::module::InstallWith; use crate::runtime::{RawStr, Tuple}; /// The trait used for something that can be statically named. diff --git a/crates/rune/src/doc/context.rs b/crates/rune/src/doc/context.rs index e7262a16d..9c653b19d 100644 --- a/crates/rune/src/doc/context.rs +++ b/crates/rune/src/doc/context.rs @@ -1,9 +1,9 @@ use crate::no_std::prelude::*; use crate::compile::context::PrivMeta; -use crate::compile::{meta, AssociatedFunctionKind}; -use crate::compile::{AssociatedFunction, ComponentRef, IntoComponent, Item}; +use crate::compile::{meta, ComponentRef, IntoComponent, Item}; use crate::doc::{Visitor, VisitorData}; +use crate::module::{AssociatedKind, ModuleAssociated}; use crate::runtime::ConstValue; use crate::runtime::Protocol; use crate::Hash; @@ -137,31 +137,31 @@ impl<'a> Context<'a> { })) } - fn context_to_associated(associated: &AssociatedFunction) -> Assoc<'_> { - let kind = match associated.name.kind { - AssociatedFunctionKind::Protocol(protocol) => AssocFnKind::Protocol(protocol), - AssociatedFunctionKind::FieldFn(protocol, ref field) => { + fn context_to_associated(m: &ModuleAssociated) -> Assoc<'_> { + let kind = match m.name.kind { + AssociatedKind::Protocol(protocol) => AssocFnKind::Protocol(protocol), + AssociatedKind::FieldFn(protocol, ref field) => { AssocFnKind::FieldFn(protocol, field) } - AssociatedFunctionKind::IndexFn(protocol, index) => { + AssociatedKind::IndexFn(protocol, index) => { AssocFnKind::IndexFn(protocol, index) } - AssociatedFunctionKind::Instance(ref name) => AssocFnKind::Instance(name), + AssociatedKind::Instance(ref name) => AssocFnKind::Instance(name), }; Assoc::Fn(AssocFn { - is_async: associated.is_async, - return_type: associated.return_type.as_ref().map(|f| f.hash), - argument_types: associated + is_async: m.is_async, + return_type: m.return_type.as_ref().map(|f| f.hash), + argument_types: m .argument_types .iter() .map(|f| f.as_ref().map(|f| f.hash)) .collect(), - docs: associated.docs.lines(), - docs_args: associated.docs.args(), + docs: m.docs.lines(), + docs_args: m.docs.args(), kind, - args: associated.args, - parameter_types: &associated.name.parameter_types, + args: m.args, + parameter_types: &m.name.parameter_types, }) } @@ -170,7 +170,10 @@ impl<'a> Context<'a> { .iter() .flat_map(move |v| visitor_to_associated(hash, v).into_iter().flatten()); - let context = self.context.associated(hash).map(context_to_associated); + let context = self + .context + .associated(hash) + .map(context_to_associated); visitors.chain(context) } diff --git a/crates/rune/src/internal_macros.rs b/crates/rune/src/internal_macros.rs index 3de7806a2..41407cc1d 100644 --- a/crates/rune/src/internal_macros.rs +++ b/crates/rune/src/internal_macros.rs @@ -40,22 +40,22 @@ macro_rules! impl_static_type { macro_rules! repeat_macro { ($macro:ident) => { $macro!(0); - $macro!(1, A a 1); - $macro!(2, A a 1, B b 2); - $macro!(3, A a 1, B b 2, C c 3); - $macro!(4, A a 1, B b 2, C c 3, D d 4); - $macro!(5, A a 1, B b 2, C c 3, D d 4, E e 5); - $macro!(6, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6); - $macro!(7, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7); - $macro!(8, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8); - $macro!(9, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9); - $macro!(10, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10); - $macro!(11, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10, K k 11); - $macro!(12, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10, K k 11, L l 12); - $macro!(13, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10, K k 11, L l 12, M m 13); - $macro!(14, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10, K k 11, L l 12, M m 13, N n 14); - $macro!(15, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10, K k 11, L l 12, M m 13, N n 14, O o 15); - $macro!(16, A a 1, B b 2, C c 3, D d 4, E e 5, F f 6, G g 7, H h 8, I i 9, J j 10, K k 11, L l 12, M m 13, N n 14, O o 15, P p 16); + $macro!(1, A a 0); + $macro!(2, A a 0, B b 1); + $macro!(3, A a 0, B b 1, C c 2); + $macro!(4, A a 0, B b 1, C c 2, D d 3); + $macro!(5, A a 0, B b 1, C c 2, D d 3, E e 4); + $macro!(6, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5); + $macro!(7, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6); + $macro!(8, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7); + $macro!(9, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8); + $macro!(10, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9); + $macro!(11, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9, K k 10); + $macro!(12, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9, K k 10, L l 11); + $macro!(13, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9, K k 10, L l 11, M m 12); + $macro!(14, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9, K k 10, L l 11, M m 12, N n 13); + $macro!(15, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9, K k 10, L l 11, M m 12, N n 13, O o 14); + $macro!(16, A a 0, B b 1, C c 2, D d 3, E e 4, F f 5, G g 6, H h 7, I i 8, J j 9, K k 10, L l 11, M m 12, N n 13, O o 14, P p 15); }; } @@ -78,3 +78,23 @@ macro_rules! cfg_workspace { )* } } + +macro_rules! cfg_cli { + ($($item:item)*) => { + $( + #[cfg(feature = "cli")] + #[cfg_attr(docsrs, doc(cfg(feature = "cli")))] + $item + )* + } +} + +macro_rules! cfg_doc { + ($($item:item)*) => { + $( + #[cfg(feature = "doc")] + #[cfg_attr(docsrs, doc(cfg(feature = "doc")))] + $item + )* + } +} diff --git a/crates/rune/src/languageserver/completion.rs b/crates/rune/src/languageserver/completion.rs index 9eea29035..b213b85b9 100644 --- a/crates/rune/src/languageserver/completion.rs +++ b/crates/rune/src/languageserver/completion.rs @@ -10,7 +10,7 @@ use lsp::MarkupKind; use lsp::TextEdit; use crate::compile::meta::SignatureKind; -use crate::compile::AssociatedFunctionKind; +use crate::module::AssociatedKind; use crate::runtime::debug::DebugArgs; use crate::Context; use crate::Unit; @@ -94,10 +94,10 @@ pub(super) fn complete_native_instance_data( }; let n = match function_kind { - AssociatedFunctionKind::Protocol(_) => continue, - AssociatedFunctionKind::FieldFn(_, _) => continue, - AssociatedFunctionKind::IndexFn(_, _) => continue, - AssociatedFunctionKind::Instance(n) => n, + AssociatedKind::Protocol(_) => continue, + AssociatedKind::FieldFn(_, _) => continue, + AssociatedKind::IndexFn(_, _) => continue, + AssociatedKind::Instance(n) => n, }; if n.starts_with(symbol) { diff --git a/crates/rune/src/lib.rs b/crates/rune/src/lib.rs index 264d5a25c..c008327ff 100644 --- a/crates/rune/src/lib.rs +++ b/crates/rune/src/lib.rs @@ -219,7 +219,11 @@ pub use self::build::{prepare, Build, BuildError}; pub mod compile; #[doc(inline)] -pub use self::compile::{Context, ContextError, InstallWith, Module, Options}; +pub use self::compile::{Context, ContextError, Options}; + +pub mod module; +#[doc(inline)] +pub use self::module::module::Module; pub mod diagnostics; #[doc(inline)] @@ -263,16 +267,132 @@ cfg_workspace! { // Macros used internally and re-exported. pub(crate) use rune_macros::__internal_impl_any; -pub use rune_macros::{function, macro_}; -#[cfg(feature = "cli")] -pub mod cli; +/// Macro used to annotate native functions which can be loaded into rune. +/// +/// This macro automatically performs the following things: +/// * Rust documentation comments are captured so that it can be used in +/// generated Rune documentation. +/// * The name of arguments is captured to improve documentation generation. +/// * If an instance function is annotated this is detected (if the function +/// receives `self`). This behavior can be forced using `#[rune(instance)]` if +/// the function doesn't take `self`. +/// +/// # Examples +/// +/// A simple free function: +/// +/// ``` +/// use rune::{Module, ContextError}; +/// +/// /// This is a pretty neat function which is called `std::str::to_uppercase("hello")`. +/// #[rune::function] +/// fn to_uppercase(string: &str) -> String { +/// string.to_uppercase() +/// } +/// +/// fn module() -> Result { +/// let mut m = Module::new(); +/// m.function_meta(to_uppercase)?; +/// Ok(m) +/// } +/// ``` +/// +/// A free instance function: +/// +/// ``` +/// use rune::{Module, ContextError}; +/// +/// /// This is a pretty neat function, which is called like `"hello".to_uppercase()`. +/// #[rune::function(instance)] +/// fn to_uppercase(string: &str) -> String { +/// string.to_uppercase() +/// } +/// +/// /// This is a pretty neat function, which is called like `string::to_uppercase2("hello")`. +/// #[rune::function(path = string)] +/// fn to_uppercase2(string: &str) -> String { +/// string.to_uppercase() +/// } +/// +/// fn module() -> Result { +/// let mut m = Module::new(); +/// m.function_meta(to_uppercase)?; +/// m.function_meta(to_uppercase2)?; +/// Ok(m) +/// } +/// ``` +/// +/// A regular instance function: +/// +/// ``` +/// use rune::{Any, Module, ContextError}; +/// +/// #[derive(Any)] +/// struct String { +/// inner: std::string::String +/// } +/// +/// impl String { +/// /// Construct a new string wrapper. +/// #[rune::function(path = Self::new)] +/// fn new(string: &str) -> Self { +/// Self { +/// inner: string.into() +/// } +/// } +/// +/// /// Construct a new string wrapper. +/// #[rune::function(path = Self::new2)] +/// fn new2(string: &str) -> Self { +/// Self { +/// inner: string.into() +/// } +/// } +/// +/// /// Uppercase the string inside of the string wrapper. +/// /// +/// /// # Examples +/// /// +/// /// ```rune +/// /// let string = String::new("hello"); +/// /// assert_eq!(string.to_uppercase(), "HELLO"); +/// /// ``` +/// #[rune::function] +/// fn to_uppercase(&self) -> std::string::String { +/// self.inner.to_uppercase() +/// } +/// } +/// +/// fn module() -> Result { +/// let mut m = Module::new(); +/// m.ty::()?; +/// m.function_meta(String::new)?; +/// m.function_meta(String::new2)?; +/// m.function_meta(String::to_uppercase)?; +/// Ok(m) +/// } +/// ``` +#[doc(hidden)] +pub use rune_macros::function; + +/// 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_; + +cfg_cli! { + pub mod cli; +} #[cfg(feature = "languageserver")] pub mod languageserver; -#[cfg(feature = "doc")] -pub mod doc; +cfg_doc! { + pub mod doc; +} /// Internal collection re-export. mod collections { @@ -288,8 +408,10 @@ mod collections { /// Privately exported details. #[doc(hidden)] pub mod __private { - pub use crate::compile::{FunctionMetaData, FunctionMetaKind}; - pub use crate::compile::{MacroMetaData, MacroMetaKind}; + pub use crate::module::module::Module; + pub use crate::module::InstallWith; + pub use crate::module::{FunctionMetaData, FunctionMetaKind}; + pub use crate::module::{MacroMetaData, MacroMetaKind}; } #[cfg(test)] diff --git a/crates/rune/src/macros.rs b/crates/rune/src/macros.rs index 07859b9ae..886720581 100644 --- a/crates/rune/src/macros.rs +++ b/crates/rune/src/macros.rs @@ -88,5 +88,30 @@ pub use self::quote_fn::{quote_fn, Quote}; pub(crate) use self::storage::Storage; pub use self::storage::{SyntheticId, SyntheticKind}; pub use self::token_stream::{ToTokens, TokenStream, TokenStreamIter}; + +/// Macro helper function for quoting the token stream as macro output. +/// +/// Is capable of quoting everything in Rune, except for the following: +/// * Labels, which must be created using `Label::new`. +/// * Dynamic quoted strings and other literals, which must be created using +/// `Lit::new`. +/// +/// ``` +/// use rune::macros::quote; +/// +/// quote!(hello self); +/// ``` +/// +/// # Interpolating values +/// +/// Values are interpolated with `#value`, or `#(value + 1)` for expressions. +/// +/// # Iterators +/// +/// Anything that can be used as an iterator can be iterated over with +/// `#(iter)*`. A token can also be used to join inbetween each iteration, like +/// `#(iter),*`. pub use rune_macros::quote; + +/// Helper derive to implement [`ToTokens`]. pub use rune_macros::ToTokens; diff --git a/crates/rune/src/module.rs b/crates/rune/src/module.rs new file mode 100644 index 000000000..9ccb18ee4 --- /dev/null +++ b/crates/rune/src/module.rs @@ -0,0 +1,269 @@ +//! Types used for defining native modules. +//! +//! A native module is one that provides rune with functions and types through +//! native Rust-based code. + +mod function_meta; +mod function_traits; +pub(crate) mod module; + +use core::fmt; + +use crate::no_std::collections::HashSet; +use crate::no_std::prelude::*; +use crate::no_std::sync::Arc; + +use crate::compile::{ContextError, Docs, IntoComponent, ItemBuf}; +use crate::runtime::{FullTypeOf, FunctionHandler, MacroHandler, StaticType, TypeCheck, TypeInfo}; +use crate::Hash; + +pub(crate) use self::function_meta::{ + AssociatedFunctionName, AssociatedKind, ToFieldFunction, ToInstance, +}; + +#[doc(hidden)] +pub use self::function_meta::{FunctionMetaData, FunctionMetaKind, MacroMetaData, MacroMetaKind}; +pub use self::function_traits::{AssocType, AsyncFunction, AsyncInstFn, Function, InstFn}; +#[doc(hidden)] +pub use self::module::Module; + +/// Trait to handle the installation of auxilliary functions for a type +/// installed into a module. +pub trait InstallWith { + /// Hook to install more things into the module. + fn install_with(_: &mut Module) -> Result<(), ContextError> { + Ok(()) + } +} + +/// Specialized information on `Option` types. +pub(crate) struct UnitType { + /// Item of the unit type. + pub(crate) name: Box, +} + +/// Specialized information on `GeneratorState` types. +pub(crate) struct InternalEnum { + /// The name of the internal enum. + pub(crate) name: &'static str, + /// The result type. + pub(crate) base_type: ItemBuf, + /// The static type of the enum. + pub(crate) static_type: &'static StaticType, + /// Internal variants. + pub(crate) variants: Vec, +} + +impl InternalEnum { + /// Construct a new handler for an internal enum. + fn new(name: &'static str, base_type: N, static_type: &'static StaticType) -> Self + where + N: IntoIterator, + N::Item: IntoComponent, + { + InternalEnum { + name, + base_type: ItemBuf::with_item(base_type), + static_type, + variants: Vec::new(), + } + } + + /// Register a new variant. + fn variant(&mut self, name: &'static str, type_check: TypeCheck, constructor: C) + where + C: Function, + { + let constructor: Arc = + Arc::new(move |stack, args| constructor.fn_call(stack, args)); + + self.variants.push(InternalVariant { + name, + type_check, + args: C::args(), + constructor, + }); + } +} + +/// Internal variant. +pub(crate) struct InternalVariant { + /// The name of the variant. + pub(crate) name: &'static str, + /// Type check for the variant. + pub(crate) type_check: TypeCheck, + /// Arguments for the variant. + pub(crate) args: usize, + /// The constructor of the variant. + pub(crate) constructor: Arc, +} + +/// Data for an opaque type. If `spec` is set, indicates things which are known +/// about that type. +pub(crate) struct Type { + /// The name of the installed type which will be the final component in the + /// item it will constitute. + pub(crate) name: Box, + /// Type information for the installed type. + pub(crate) type_info: TypeInfo, + /// The specification for the type. + pub(crate) spec: Option, +} + +/// Metadata about a variant. +pub struct Variant { + /// Variant metadata. + pub(crate) kind: VariantKind, + /// Handler to use if this variant can be constructed through a regular function call. + pub(crate) constructor: Option>, +} + +impl fmt::Debug for Variant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Variant") + .field("kind", &self.kind) + .field("constructor", &self.constructor.is_some()) + .finish() + } +} + +/// The kind of the variant. +#[derive(Debug)] +pub(crate) enum VariantKind { + /// Variant is a Tuple variant. + Tuple(Tuple), + /// Variant is a Struct variant. + Struct(Struct), + /// Variant is a Unit variant. + Unit, +} + +impl Variant { + /// Construct metadata for a tuple variant. + #[inline] + pub fn tuple(args: usize) -> Self { + Self { + kind: VariantKind::Tuple(Tuple { args }), + constructor: None, + } + } + + /// Construct metadata for a tuple variant. + #[inline] + pub fn st(fields: [&'static str; N]) -> Self { + Self { + kind: VariantKind::Struct(Struct { + fields: fields.into_iter().map(Box::::from).collect(), + }), + constructor: None, + } + } + + /// Construct metadata for a unit variant. + #[inline] + pub fn unit() -> Self { + Self { + kind: VariantKind::Unit, + constructor: None, + } + } +} + +/// Metadata about a tuple or tuple variant. +#[derive(Debug)] +pub struct Tuple { + /// The number of fields. + pub(crate) args: usize, +} + +/// The type specification for a native struct. +#[derive(Debug)] +pub(crate) struct Struct { + /// The names of the struct fields known at compile time. + pub(crate) fields: HashSet>, +} + +/// The type specification for a native enum. +pub(crate) struct Enum { + /// The variants. + pub(crate) variants: Vec<(Box, Variant)>, +} + +/// A type specification. +pub(crate) enum TypeSpecification { + Struct(Struct), + Enum(Enum), +} + +/// A key that identifies an associated function. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub(crate) struct AssociatedKey { + /// The type the associated function belongs to. + pub(crate) type_hash: Hash, + /// The kind of the associated function. + pub(crate) kind: AssociatedKind, + /// The type parameters of the associated function. + pub(crate) parameters: Hash, +} + +#[derive(Clone)] +pub(crate) struct ModuleFunction { + pub(crate) handler: Arc, + pub(crate) is_async: bool, + pub(crate) args: Option, + pub(crate) return_type: Option, + pub(crate) argument_types: Box<[Option]>, + pub(crate) docs: Docs, +} + +#[derive(Clone)] +pub(crate) struct ModuleAssociated { + pub(crate) name: AssociatedFunctionName, + pub(crate) type_info: TypeInfo, + pub(crate) handler: Arc, + pub(crate) is_async: bool, + pub(crate) args: Option, + pub(crate) return_type: Option, + pub(crate) argument_types: Box<[Option]>, + pub(crate) docs: Docs, +} + +/// Handle to a macro inserted into a module. +pub(crate) struct ModuleMacro { + pub(crate) handler: Arc, + pub(crate) docs: Docs, +} + +/// Handle to a an item inserted into a module which allows for mutation of item +/// metadata. +/// +/// This is returned by methods which insert meta items, such as: +/// * [`Module::raw_fn`]. +/// * [`Module::function`]. +/// * [`Module::async_function`]. +/// * [`Module::inst_fn`]. +/// * [`Module::async_inst_fn`]. +/// +/// While this is also returned by `*_meta` inserting functions, it is instead +/// recommended that you make use of the appropriate macro to capture doc +/// comments instead: +/// * [`Module::macro_meta`]. +/// * [`Module::function_meta`]. +pub struct ItemMut<'a> { + docs: &'a mut Docs, +} + +impl ItemMut<'_> { + /// Set documentation for an inserted item. + /// + /// This completely replaces any existing documentation. + pub fn docs(self, docs: I) -> Self + where + I: IntoIterator, + I::Item: AsRef, + { + self.docs.set_docs(docs); + self + } +} diff --git a/crates/rune/src/compile/function_meta.rs b/crates/rune/src/module/function_meta.rs similarity index 73% rename from crates/rune/src/compile/function_meta.rs rename to crates/rune/src/module/function_meta.rs index 40939952b..d8226869c 100644 --- a/crates/rune/src/compile/function_meta.rs +++ b/crates/rune/src/module/function_meta.rs @@ -4,12 +4,10 @@ use core::future::Future; use crate::no_std::prelude::*; use crate::no_std::sync::Arc; -use crate::compile::module::{ - AssocType, AssociatedFunctionKey, AsyncFunction, AsyncInstFn, Function, InstFn, -}; use crate::compile::{self, IntoComponent, ItemBuf, Named}; use crate::hash::Hash; use crate::macros::{MacroContext, TokenStream}; +use crate::module::{AssocType, AssociatedKey, AsyncFunction, AsyncInstFn, Function, InstFn}; use crate::runtime::{FullTypeOf, FunctionHandler, MacroHandler, MaybeTypeOf, Protocol}; mod sealed { @@ -27,8 +25,8 @@ mod sealed { /// `#[rune::function]` macro. /// /// This is the argument type for -/// [`Module::function_meta`][crate::compile::Module::function_meta], and is from a -/// public API perspective completely opaque and might change for any release. +/// [`Module::function_meta`][crate::module::Module::function_meta], and is from +/// a public API perspective completely opaque and might change for any release. /// /// Calling and making use of `FunctionMeta` manually despite this warning might /// lead to future breakage. @@ -38,7 +36,7 @@ pub type FunctionMeta = fn() -> FunctionMetaData; /// `#[rune::macro_]` macro. /// /// This is the argument type for -/// [`Module::macro_meta`][crate::compile::Module::macro_meta], and is from a +/// [`Module::macro_meta`][crate::module::Module::macro_meta], and is from a /// public API perspective completely opaque and might change for any release. /// /// Calling and making use of `MacroMeta` manually despite this warning might @@ -58,45 +56,45 @@ pub struct FunctionData { impl FunctionData { #[inline] - pub(crate) fn new(name: N, f: Func) -> Self + pub(crate) fn new(name: N, f: F) -> Self where - Func: Function, - Func::Return: MaybeTypeOf, + F: Function, + F::Return: MaybeTypeOf, N: IntoIterator, N::Item: IntoComponent, - Args: IterFunctionArgs, + A: IterFunctionArgs, { - let mut argument_types = Vec::with_capacity(Args::len()); - Args::iter_args(|ty| argument_types.push(ty)); + let mut argument_types = Vec::with_capacity(A::len()); + A::iter_args(|ty| argument_types.push(ty)); Self { is_async: false, name: ItemBuf::with_item(name), handler: Arc::new(move |stack, args| f.fn_call(stack, args)), - args: Some(Func::args()), - return_type: Func::Return::maybe_type_of(), + args: Some(F::args()), + return_type: F::Return::maybe_type_of(), argument_types: argument_types.into(), } } #[inline] - pub(crate) fn new_async(name: N, f: Func) -> Self + pub(crate) fn new_async(name: N, f: F) -> Self where - Func: AsyncFunction, - Func::Output: MaybeTypeOf, + F: AsyncFunction, + F::Output: MaybeTypeOf, N: IntoIterator, N::Item: IntoComponent, - Args: IterFunctionArgs, + A: IterFunctionArgs, { - let mut argument_types = Vec::with_capacity(Args::len()); - Args::iter_args(|ty| argument_types.push(ty)); + let mut argument_types = Vec::with_capacity(A::len()); + A::iter_args(|ty| argument_types.push(ty)); Self { is_async: true, name: ItemBuf::with_item(name), handler: Arc::new(move |stack, args| f.fn_call(stack, args)), - args: Some(Func::args()), - return_type: Func::Output::maybe_type_of(), + args: Some(F::args()), + return_type: F::Output::maybe_type_of(), argument_types: argument_types.into(), } } @@ -111,9 +109,9 @@ pub struct FunctionMacroData { impl FunctionMacroData { #[inline] - pub(crate) fn new(name: N, f: Func) -> Self + pub(crate) fn new(name: N, f: F) -> Self where - Func: 'static + F: 'static + Send + Sync + Fn(&mut MacroContext<'_>, &TokenStream) -> compile::Result, @@ -130,7 +128,7 @@ impl FunctionMacroData { /// An instance function name. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] -pub enum AssociatedFunctionKind { +pub enum AssociatedKind { /// A protocol function implemented on the type itself. Protocol(Protocol), /// A field function with the given protocol. @@ -141,7 +139,7 @@ pub enum AssociatedFunctionKind { Instance(Box), } -impl AssociatedFunctionKind { +impl AssociatedKind { /// Convert the kind into a hash function. pub(crate) fn hash(&self, instance_type: Hash) -> Hash { match self { @@ -157,17 +155,17 @@ impl AssociatedFunctionKind { } } -impl fmt::Display for AssociatedFunctionKind { +impl fmt::Display for AssociatedKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - AssociatedFunctionKind::Protocol(protocol) => write!(f, "<{}>", protocol.name), - AssociatedFunctionKind::FieldFn(protocol, field) => { + AssociatedKind::Protocol(protocol) => write!(f, "<{}>", protocol.name), + AssociatedKind::FieldFn(protocol, field) => { write!(f, ".{field}<{}>", protocol.name) } - AssociatedFunctionKind::IndexFn(protocol, index) => { + AssociatedKind::IndexFn(protocol, index) => { write!(f, ".{index}<{}>", protocol.name) } - AssociatedFunctionKind::Instance(name) => write!(f, "{}", name), + AssociatedKind::Instance(name) => write!(f, "{}", name), } } } @@ -189,7 +187,7 @@ impl ToInstance for &str { #[inline] fn to_instance(self) -> AssociatedFunctionName { AssociatedFunctionName { - kind: AssociatedFunctionKind::Instance(self.into()), + kind: AssociatedKind::Instance(self.into()), parameters: Hash::EMPTY, #[cfg(feature = "doc")] parameter_types: vec![], @@ -201,7 +199,7 @@ impl ToFieldFunction for &str { #[inline] fn to_field_function(self, protocol: Protocol) -> AssociatedFunctionName { AssociatedFunctionName { - kind: AssociatedFunctionKind::FieldFn(protocol, self.into()), + kind: AssociatedKind::FieldFn(protocol, self.into()), parameters: Hash::EMPTY, #[cfg(feature = "doc")] parameter_types: vec![], @@ -215,7 +213,7 @@ impl ToFieldFunction for &str { #[doc(hidden)] pub struct AssociatedFunctionName { /// The name of the instance function. - pub kind: AssociatedFunctionKind, + pub kind: AssociatedKind, /// Parameters hash. pub parameters: Hash, #[cfg(feature = "doc")] @@ -225,7 +223,7 @@ pub struct AssociatedFunctionName { impl AssociatedFunctionName { pub(crate) fn index(protocol: Protocol, index: usize) -> Self { Self { - kind: AssociatedFunctionKind::IndexFn(protocol, index), + kind: AssociatedKind::IndexFn(protocol, index), parameters: Hash::EMPTY, #[cfg(feature = "doc")] parameter_types: vec![], @@ -247,50 +245,50 @@ pub struct AssociatedFunctionData { impl AssociatedFunctionData { #[inline] - pub(crate) fn new(name: AssociatedFunctionName, f: Func) -> Self + pub(crate) fn new(name: AssociatedFunctionName, f: F) -> Self where - Func: InstFn, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, + F: InstFn, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, { - let mut argument_types = Vec::with_capacity(Args::len()); - Args::iter_args(|ty| argument_types.push(ty)); + let mut argument_types = Vec::with_capacity(A::len()); + A::iter_args(|ty| argument_types.push(ty)); Self { name, handler: Arc::new(move |stack, args| f.fn_call(stack, args)), - ty: Func::ty(), + ty: F::ty(), is_async: false, - args: Some(Func::args()), - return_type: Func::Return::maybe_type_of(), + args: Some(F::args()), + return_type: F::Return::maybe_type_of(), argument_types: argument_types.into(), } } #[inline] - pub(crate) fn new_async(name: AssociatedFunctionName, f: Func) -> Self + pub(crate) fn new_async(name: AssociatedFunctionName, f: F) -> Self where - Func: AsyncInstFn, - Func::Output: MaybeTypeOf, - Args: IterFunctionArgs, + F: AsyncInstFn, + F::Output: MaybeTypeOf, + A: IterFunctionArgs, { - let mut argument_types = Vec::with_capacity(Args::len()); - Args::iter_args(|ty| argument_types.push(ty)); + let mut argument_types = Vec::with_capacity(A::len()); + A::iter_args(|ty| argument_types.push(ty)); Self { name, handler: Arc::new(move |stack, args| f.fn_call(stack, args)), - ty: Func::ty(), + ty: F::ty(), is_async: true, - args: Some(Func::args()), - return_type: ::Output::maybe_type_of(), + args: Some(F::args()), + return_type: ::Output::maybe_type_of(), argument_types: argument_types.into(), } } /// Get associated key. - pub(crate) fn assoc_key(&self) -> AssociatedFunctionKey { - AssociatedFunctionKey { + pub(crate) fn assoc_key(&self) -> AssociatedKey { + AssociatedKey { type_hash: self.ty.hash, kind: self.name.kind.clone(), parameters: self.name.parameters, @@ -314,27 +312,27 @@ pub enum FunctionMetaKind { impl FunctionMetaKind { #[doc(hidden)] #[inline] - pub fn function(name: N, f: Func) -> Self + pub fn function(name: N, f: F) -> Self where N: IntoIterator, N::Item: IntoComponent, - Func: Function, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, + F: Function, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, { Self::Function(FunctionData::new(name, f)) } #[doc(hidden)] #[inline] - pub fn function_with(name: N, f: Func) -> Self + pub fn function_with(name: N, f: F) -> Self where T: Named, N: IntoIterator, N::Item: IntoComponent, - Func: Function, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, + F: Function, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, { let name = [IntoComponent::into_component(T::BASE_NAME)] .into_iter() @@ -344,27 +342,27 @@ impl FunctionMetaKind { #[doc(hidden)] #[inline] - pub fn async_function(name: N, f: Func) -> Self + pub fn async_function(name: N, f: F) -> Self where N: IntoIterator, N::Item: IntoComponent, - Func: AsyncFunction, - Func::Output: MaybeTypeOf, - Args: IterFunctionArgs, + F: AsyncFunction, + F::Output: MaybeTypeOf, + A: IterFunctionArgs, { Self::Function(FunctionData::new_async(name, f)) } #[doc(hidden)] #[inline] - pub fn async_function_with(name: N, f: Func) -> Self + pub fn async_function_with(name: N, f: F) -> Self where T: Named, N: IntoIterator, N::Item: IntoComponent, - Func: AsyncFunction, - Func::Output: MaybeTypeOf, - Args: IterFunctionArgs, + F: AsyncFunction, + F::Output: MaybeTypeOf, + A: IterFunctionArgs, { let name = [IntoComponent::into_component(T::BASE_NAME)] .into_iter() @@ -374,24 +372,24 @@ impl FunctionMetaKind { #[doc(hidden)] #[inline] - pub fn instance(name: N, f: Func) -> Self + pub fn instance(name: N, f: F) -> Self where N: ToInstance, - Func: InstFn, - Func::Return: MaybeTypeOf, - Args: IterFunctionArgs, + F: InstFn, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, { Self::AssociatedFunction(AssociatedFunctionData::new(name.to_instance(), f)) } #[doc(hidden)] #[inline] - pub fn async_instance(name: N, f: Func) -> Self + pub fn async_instance(name: N, f: F) -> Self where N: ToInstance, - Func: AsyncInstFn, - Func::Output: MaybeTypeOf, - Args: IterFunctionArgs, + F: AsyncInstFn, + F::Output: MaybeTypeOf, + A: IterFunctionArgs, { Self::AssociatedFunction(AssociatedFunctionData::new_async(name.to_instance(), f)) } @@ -411,9 +409,9 @@ pub enum MacroMetaKind { impl MacroMetaKind { #[doc(hidden)] #[inline] - pub fn function(name: N, f: Func) -> Self + pub fn function(name: N, f: F) -> Self where - Func: 'static + F: 'static + Send + Sync + Fn(&mut MacroContext<'_>, &TokenStream) -> compile::Result, diff --git a/crates/rune/src/module/function_traits.rs b/crates/rune/src/module/function_traits.rs new file mode 100644 index 000000000..b45b72a75 --- /dev/null +++ b/crates/rune/src/module/function_traits.rs @@ -0,0 +1,327 @@ +use core::future::Future; + +use crate::runtime::{ + self, Stack, ToValue, TypeInfo, TypeOf, UnsafeFromValue, VmErrorKind, VmResult, +}; +use crate::Hash; + +macro_rules! check_args { + ($expected:expr, $actual:expr) => { + if $actual != $expected { + return VmResult::err(VmErrorKind::BadArgumentCount { + actual: $actual, + expected: $expected, + }); + } + }; +} + +// Expand to function variable bindings. +macro_rules! unsafe_vars { + ($count:expr, $($ty:ty, $var:ident, $num:expr,)*) => { + $( + let $var = vm_try!(<$ty>::from_value($var).with_error(|| VmErrorKind::BadArgument { + arg: $num, + })); + )* + }; +} + +// Helper variation to drop all stack guards associated with the specified variables. +macro_rules! drop_stack_guards { + ($($var:ident),* $(,)?) => {{ + $(drop(($var.1));)* + }}; +} + +// Expand to instance variable bindings. +macro_rules! unsafe_inst_vars { + ($inst:ident, $count:expr, $($ty:ty, $var:ident, $num:expr,)*) => { + let $inst = vm_try!(Inst::from_value($inst).with_error(|| VmErrorKind::BadArgument { + arg: 0, + })); + + $( + let $var = vm_try!(<$ty>::from_value($var).with_error(|| VmErrorKind::BadArgument { + arg: 1 + $num, + })); + )* + }; +} + +/// The static hash and diagnostical information about a type. +#[derive(Debug, Clone)] +#[non_exhaustive] +#[doc(hidden)] +pub struct AssocType { + /// Hash of the type. + pub hash: Hash, + /// Type information of the instance function. + pub type_info: TypeInfo, +} + +/// Trait used to provide the [function][crate::module::Module::function] +/// function. +pub trait Function: 'static + Send + Sync { + /// The return type of the function. + #[doc(hidden)] + type Return; + + /// Get the number of arguments. + #[doc(hidden)] + fn args() -> usize; + + /// Perform the vm call. + #[doc(hidden)] + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; +} + +/// Trait used to provide the +/// [async_function][crate::module::Module::async_function] function. +pub trait AsyncFunction: 'static + Send + Sync { + /// The return type of the function. + #[doc(hidden)] + type Return: Future; + + /// The output produces by the future. + #[doc(hidden)] + type Output; + + /// Get the number of arguments. + #[doc(hidden)] + fn args() -> usize; + + /// Perform the vm call. + #[doc(hidden)] + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; +} + +/// Trait used to provide the [inst_fn][crate::module::Module::inst_fn] +/// function. +pub trait InstFn: 'static + Send + Sync { + /// The type of the instance. + #[doc(hidden)] + type Inst; + + /// The return type of the function. + #[doc(hidden)] + type Return; + + /// Get the number of arguments. + #[doc(hidden)] + fn args() -> usize; + + /// Access static information on the instance type with the associated + /// function. + #[doc(hidden)] + fn ty() -> AssocType; + + /// Perform the vm call. + #[doc(hidden)] + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; +} + +/// Trait used to provide the +/// [async_inst_fn][crate::module::Module::async_inst_fn] function. +pub trait AsyncInstFn: 'static + Send + Sync { + /// The type of the instance. + #[doc(hidden)] + type Inst; + + /// The return type of the function. + #[doc(hidden)] + type Return: Future; + + /// The output value of the async function. + #[doc(hidden)] + type Output; + + /// Get the number of arguments. + #[doc(hidden)] + fn args() -> usize; + + /// Access static information on the instance type with the associated + /// function. + #[doc(hidden)] + fn ty() -> AssocType; + + /// Perform the vm call. + #[doc(hidden)] + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()>; +} + +macro_rules! impl_register { + ($count:expr $(, $ty:ident $var:ident $num:expr)*) => { + impl Function<($($ty,)*)> for T + where + T: 'static + Send + Sync + Fn($($ty,)*) -> U, + U: ToValue, + $($ty: UnsafeFromValue,)* + { + type Return = U; + + fn args() -> usize { + $count + } + + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { + check_args!($count, args); + let [$($var,)*] = vm_try!(stack.drain_vec($count)); + + // Safety: We hold a reference to the stack, so we can + // guarantee that it won't be modified. + // + // The scope is also necessary, since we mutably access `stack` + // when we return below. + #[allow(unused)] + let ret = unsafe { + unsafe_vars!($count, $($ty, $var, $num,)*); + let ret = self($(<$ty>::unsafe_coerce($var.0),)*); + drop_stack_guards!($($var),*); + ret + }; + + let ret = vm_try!(ret.to_value()); + stack.push(ret); + VmResult::Ok(()) + } + } + + impl AsyncFunction<($($ty,)*)> for T + where + T: 'static + Send + Sync + Fn($($ty,)*) -> U, + U: 'static + Future, + U::Output: ToValue, + $($ty: 'static + UnsafeFromValue,)* + { + type Return = U; + type Output = U::Output; + + fn args() -> usize { + $count + } + + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { + check_args!($count, args); + let [$($var,)*] = vm_try!(stack.drain_vec($count)); + + // Safety: Future is owned and will only be called within the + // context of the virtual machine, which will provide + // exclusive thread-local access to itself while the future is + // being polled. + #[allow(unused_unsafe)] + let ret = unsafe { + unsafe_vars!($count, $($ty, $var, $num,)*); + let fut = self($(<$ty>::unsafe_coerce($var.0),)*); + + runtime::Future::new(async move { + let output = fut.await; + drop_stack_guards!($($var),*); + let value = vm_try!(output.to_value()); + VmResult::Ok(value) + }) + }; + + let ret = vm_try!(ret.to_value()); + stack.push(ret); + VmResult::Ok(()) + } + } + + impl InstFn<(Inst, $($ty,)*)> for T + where + T: 'static + Send + Sync + Fn(Inst $(, $ty)*) -> U, + U: ToValue, + Inst: UnsafeFromValue + TypeOf, + $($ty: UnsafeFromValue,)* + { + type Inst = Inst; + type Return = U; + + fn args() -> usize { + $count + 1 + } + + fn ty() -> AssocType { + AssocType { + hash: Inst::type_hash(), + type_info: Inst::type_info(), + } + } + + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { + check_args!(($count + 1), args); + let [inst $(, $var)*] = vm_try!(stack.drain_vec($count + 1)); + + // Safety: We hold a reference to the stack, so we can + // guarantee that it won't be modified. + // + // The scope is also necessary, since we mutably access `stack` + // when we return below. + #[allow(unused)] + let ret = unsafe { + unsafe_inst_vars!(inst, $count, $($ty, $var, $num,)*); + let ret = self(Inst::unsafe_coerce(inst.0), $(<$ty>::unsafe_coerce($var.0),)*); + drop_stack_guards!(inst, $($var),*); + ret + }; + + let ret = vm_try!(ret.to_value()); + stack.push(ret); + VmResult::Ok(()) + } + } + + impl AsyncInstFn<(Inst, $($ty,)*)> for T + where + T: 'static + Send + Sync + Fn(Inst $(, $ty)*) -> U, + U: 'static + Future, + U::Output: ToValue, + Inst: UnsafeFromValue + TypeOf, + $($ty: UnsafeFromValue,)* + { + type Inst = Inst; + type Return = U; + type Output = U::Output; + + fn args() -> usize { + $count + 1 + } + + fn ty() -> AssocType { + AssocType { + hash: Inst::type_hash(), + type_info: Inst::type_info(), + } + } + + fn fn_call(&self, stack: &mut Stack, args: usize) -> VmResult<()> { + check_args!(($count + 1), args); + let [inst $(, $var)*] = vm_try!(stack.drain_vec($count + 1)); + + // Safety: Future is owned and will only be called within the + // context of the virtual machine, which will provide + // exclusive thread-local access to itself while the future is + // being polled. + #[allow(unused)] + let ret = unsafe { + unsafe_inst_vars!(inst, $count, $($ty, $var, $num,)*); + let fut = self(Inst::unsafe_coerce(inst.0), $(<$ty>::unsafe_coerce($var.0),)*); + + runtime::Future::new(async move { + let output = fut.await; + drop_stack_guards!(inst, $($var),*); + let value = vm_try!(output.to_value()); + VmResult::Ok(value) + }) + }; + + let ret = vm_try!(ret.to_value()); + stack.push(ret); + VmResult::Ok(()) + } + } + }; +} + +repeat_macro!(impl_register); diff --git a/crates/rune/src/module/module.rs b/crates/rune/src/module/module.rs new file mode 100644 index 000000000..cd1a28a82 --- /dev/null +++ b/crates/rune/src/module/module.rs @@ -0,0 +1,1031 @@ +use crate::no_std::collections::{hash_map, HashMap}; +use crate::no_std::prelude::*; +use crate::no_std::sync::Arc; + +use crate::compile::{self, ContextError, Docs, IntoComponent, ItemBuf, Named}; +use crate::macros::{MacroContext, TokenStream}; +use crate::module::function_meta::{ + AssociatedFunctionData, AssociatedFunctionName, AssociatedKind, FunctionData, FunctionMeta, + FunctionMetaKind, IterFunctionArgs, MacroMeta, MacroMetaKind, ToFieldFunction, ToInstance, +}; +use crate::module::{ + AssociatedKey, AsyncFunction, AsyncInstFn, Enum, Function, InstFn, InstallWith, InternalEnum, + ItemMut, ModuleAssociated, ModuleFunction, ModuleMacro, Struct, Type, TypeSpecification, + UnitType, Variant, +}; +use crate::runtime::{ + ConstValue, FromValue, GeneratorState, MacroHandler, MaybeTypeOf, Protocol, Stack, ToValue, + TypeCheck, TypeOf, Value, VmResult, +}; +use crate::Hash; + +/// 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]. +#[derive(Default)] +pub struct Module { + /// A special identifier for this module, which will cause it to not conflict if installed multiple times. + pub(crate) unique: Option<&'static str>, + /// The name of the module. + pub(crate) item: ItemBuf, + /// Functions. + pub(crate) functions: HashMap, + /// MacroHandler handlers. + pub(crate) macros: HashMap, + /// Constant values. + pub(crate) constants: HashMap, + /// Associated items. + pub(crate) associated: HashMap, + /// Registered types. + pub(crate) types: HashMap, + /// Registered unit type. + pub(crate) unit_type: Option, + /// Registered generator state type. + pub(crate) internal_enums: Vec, +} + +impl Module { + /// Create an empty module for the root path. + pub fn new() -> Self { + Self::default() + } + + /// Modify the current module to utilise a special identifier. + #[doc(hidden)] + pub fn with_unique(self, id: &'static str) -> Self { + Self { + unique: Some(id), + ..self + } + } + + /// Construct a new module for the given item. + pub fn with_item(iter: I) -> Self + where + I: IntoIterator, + I::Item: IntoComponent, + { + Self::inner_new(ItemBuf::with_item(iter)) + } + + /// Construct a new module for the given crate. + pub fn with_crate(name: &str) -> Self { + Self::inner_new(ItemBuf::with_crate(name)) + } + + /// Construct a new module for the given crate. + pub fn with_crate_item(name: &str, iter: I) -> Self + where + I: IntoIterator, + I::Item: IntoComponent, + { + Self::inner_new(ItemBuf::with_crate_item(name, iter)) + } + + fn inner_new(item: ItemBuf) -> Self { + Self { + unique: None, + item, + functions: HashMap::default(), + macros: HashMap::default(), + associated: HashMap::default(), + types: HashMap::default(), + unit_type: None, + internal_enums: Vec::new(), + constants: HashMap::default(), + } + } + + /// Register a type. Registering a type is mandatory in order to register + /// instance functions using that type. + /// + /// This will allow the type to be used within scripts, using the item named + /// here. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Context, Module}; + /// + /// #[derive(Any)] + /// struct MyBytes { + /// queue: Vec, + /// } + /// + /// impl MyBytes { + /// fn len(&self) -> usize { + /// self.queue.len() + /// } + /// } + /// + /// // Register `len` without registering a type. + /// let mut module = Module::default(); + /// // Note: cannot do this until we have registered a type. + /// module.inst_fn("len", MyBytes::len)?; + /// + /// let mut context = rune::Context::new(); + /// assert!(context.install(module).is_err()); + /// + /// // Register `len` properly. + /// let mut module = Module::default(); + /// + /// module.ty::()?; + /// module.inst_fn("len", MyBytes::len)?; + /// + /// let mut context = Context::new(); + /// assert!(context.install(module).is_ok()); + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn ty(&mut self) -> Result<(), ContextError> + where + T: Named + TypeOf + InstallWith, + { + let type_hash = T::type_hash(); + let type_info = T::type_info(); + + let ty = Type { + name: T::full_name(), + type_info, + spec: None, + }; + + if let Some(old) = self.types.insert(type_hash, ty) { + return Err(ContextError::ConflictingType { + item: ItemBuf::with_item(&[T::full_name()]), + type_info: old.type_info, + }); + } + + T::install_with(self)?; + Ok(()) + } + + /// 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. + pub fn struct_meta( + &mut self, + fields: [&'static str; N], + ) -> Result<(), ContextError> + where + T: Named + TypeOf, + { + let type_hash = T::type_hash(); + + let ty = match self.types.get_mut(&type_hash) { + Some(ty) => ty, + None => { + return Err(ContextError::MissingType { + item: ItemBuf::with_item(&[T::full_name()]), + type_info: T::type_info(), + }); + } + }; + + let old = ty.spec.replace(TypeSpecification::Struct(Struct { + fields: fields.into_iter().map(Box::::from).collect(), + })); + + if old.is_some() { + return Err(ContextError::ConflictingTypeMeta { + item: ItemBuf::with_item(&[T::full_name()]), + type_info: ty.type_info.clone(), + }); + } + + Ok(()) + } + + /// Register enum metadata for the given type `T`. This allows an enum to be + /// used in limited ways in Rune. + pub fn enum_meta( + &mut self, + variants: [(&'static str, Variant); N], + ) -> Result<(), ContextError> + where + T: Named + TypeOf, + { + let type_hash = T::type_hash(); + + let ty = match self.types.get_mut(&type_hash) { + Some(ty) => ty, + None => { + return Err(ContextError::MissingType { + item: ItemBuf::with_item(&[T::full_name()]), + type_info: T::type_info(), + }); + } + }; + + let old = ty.spec.replace(TypeSpecification::Enum(Enum { + variants: variants + .into_iter() + .map(|(name, variant)| (Box::from(name), variant)) + .collect(), + })); + + if old.is_some() { + return Err(ContextError::ConflictingTypeMeta { + item: ItemBuf::with_item(&[T::full_name()]), + type_info: ty.type_info.clone(), + }); + } + + Ok(()) + } + + /// Register a variant constructor for type `T`. + pub fn variant_constructor( + &mut self, + index: usize, + constructor: F, + ) -> Result<(), ContextError> + where + F: Function, + F::Return: Named + TypeOf, + { + let type_hash = F::Return::type_hash(); + + let ty = match self.types.get_mut(&type_hash) { + Some(ty) => ty, + None => { + return Err(ContextError::MissingType { + item: ItemBuf::with_item(&[F::Return::full_name()]), + type_info: F::Return::type_info(), + }); + } + }; + + let en = match &mut ty.spec { + Some(TypeSpecification::Enum(en)) => en, + _ => { + return Err(ContextError::MissingEnum { + item: ItemBuf::with_item(&[F::Return::full_name()]), + type_info: F::Return::type_info(), + }); + } + }; + + let variant = match en.variants.get_mut(index) { + Some((_, variant)) => variant, + _ => { + return Err(ContextError::MissingVariant { + type_info: F::Return::type_info(), + index, + }); + } + }; + + if variant.constructor.is_some() { + return Err(ContextError::VariantConstructorConflict { + type_info: F::Return::type_info(), + index, + }); + } + + variant.constructor = Some(Arc::new(move |stack, args| { + constructor.fn_call(stack, args) + })); + + Ok(()) + } + + /// Construct type information for the `unit` type. + /// + /// Registering this allows the given type to be used in Rune scripts when + /// referring to the `unit` type. + /// + /// # Examples + /// + /// This shows how to register the unit type `()` as `nonstd::unit`. + /// + /// ``` + /// use rune::Module; + /// + /// let mut module = Module::with_item(["nonstd"]); + /// module.unit("unit")?; + /// # Ok::<_, rune::Error>(()) + pub fn unit(&mut self, name: N) -> Result<(), ContextError> + where + N: AsRef, + { + if self.unit_type.is_some() { + return Err(ContextError::UnitAlreadyPresent); + } + + self.unit_type = Some(UnitType { + name: >::from(name.as_ref()), + }); + + Ok(()) + } + + /// Construct the type information for the `GeneratorState` type. + /// + /// Registering this allows the given type to be used in Rune scripts when + /// referring to the `GeneratorState` type. + /// + /// # Examples + /// + /// This shows how to register the `GeneratorState` as + /// `nonstd::generator::GeneratorState`. + /// + /// ``` + /// use rune::Module; + /// + /// let mut module = Module::with_crate_item("nonstd", ["generator"]); + /// module.generator_state(["GeneratorState"])?; + /// # Ok::<_, rune::Error>(()) + pub fn generator_state(&mut self, name: N) -> Result<(), ContextError> + where + N: IntoIterator, + N::Item: IntoComponent, + { + let mut enum_ = + InternalEnum::new("GeneratorState", name, crate::runtime::GENERATOR_STATE_TYPE); + + // Note: these numeric variants are magic, and must simply match up with + // what's being used in the virtual machine implementation for these + // types. + enum_.variant( + "Complete", + TypeCheck::GeneratorState(0), + GeneratorState::Complete, + ); + enum_.variant( + "Yielded", + TypeCheck::GeneratorState(1), + GeneratorState::Yielded, + ); + + self.internal_enums.push(enum_); + Ok(()) + } + /// Construct type information for the `Option` type. + /// + /// Registering this allows the given type to be used in Rune scripts when + /// referring to the `Option` type. + /// + /// # Examples + /// + /// This shows how to register the `Option` as `nonstd::option::Option`. + /// + /// ``` + /// use rune::Module; + /// + /// let mut module = Module::with_crate_item("nonstd", ["option"]); + /// module.option(["Option"])?; + /// # Ok::<_, rune::Error>(()) + pub fn option(&mut self, name: N) -> Result<(), ContextError> + where + N: IntoIterator, + N::Item: IntoComponent, + { + let mut enum_ = InternalEnum::new("Option", name, crate::runtime::OPTION_TYPE); + + // Note: these numeric variants are magic, and must simply match up with + // what's being used in the virtual machine implementation for these + // types. + enum_.variant("Some", TypeCheck::Option(0), Option::::Some); + enum_.variant("None", TypeCheck::Option(1), || Option::::None); + self.internal_enums.push(enum_); + Ok(()) + } + + /// Construct type information for the internal `Result` type. + /// + /// Registering this allows the given type to be used in Rune scripts when + /// referring to the `Result` type. + /// + /// # Examples + /// + /// This shows how to register the `Result` as `nonstd::result::Result`. + /// + /// ``` + /// use rune::Module; + /// + /// let mut module = Module::with_crate_item("nonstd", ["result"]); + /// module.result(["Result"])?; + /// # Ok::<_, rune::Error>(()) + pub fn result(&mut self, name: N) -> Result<(), ContextError> + where + N: IntoIterator, + N::Item: IntoComponent, + { + let mut enum_ = InternalEnum::new("Result", name, crate::runtime::RESULT_TYPE); + + // Note: these numeric variants are magic, and must simply match up with + // what's being used in the virtual machine implementation for these + // types. + enum_.variant("Ok", TypeCheck::Result(0), Result::::Ok); + enum_.variant("Err", TypeCheck::Result(1), Result::::Err); + self.internal_enums.push(enum_); + Ok(()) + } + + /// Register a constant value, at a crate, module or associated level. + /// + /// # Examples + /// + /// ``` + /// use rune::Module; + /// + /// let mut module = Module::default(); + /// + /// module.constant(["TEN"], 10)?; // a global TEN value + /// module.constant(["MyType", "TEN"], 10)?; // looks like an associated value + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn constant(&mut self, name: N, value: V) -> Result<(), ContextError> + where + N: IntoIterator, + N::Item: IntoComponent, + V: ToValue, + { + let name = ItemBuf::with_item(name); + + if self.constants.contains_key(&name) { + return Err(ContextError::ConflictingConstantName { name }); + } + + let value = match value.to_value() { + VmResult::Ok(v) => v, + VmResult::Err(error) => return Err(ContextError::ValueError { error }), + }; + + let constant_value = match ::from_value(value) { + VmResult::Ok(v) => v, + VmResult::Err(error) => return Err(ContextError::ValueError { error }), + }; + + self.constants.insert(name, constant_value); + Ok(()) + } + + /// Register a native macro handler through its meta. + /// + /// The metadata must be provided by annotating the function with + /// [`#[rune::macro_]`][crate::macro_]. + /// + /// This has the benefit that it captures documentation comments which can + /// be used when generating documentation or referencing the function + /// through code sense systems. + /// + /// # Examples + /// + /// ``` + /// use rune::Module; + /// use rune::ast; + /// use rune::compile; + /// use rune::macros::{quote, MacroContext, TokenStream}; + /// use rune::parse::Parser; + /// + /// /// Takes an identifier and converts it into a string. + /// /// + /// /// # Examples + /// /// + /// /// ```rune + /// /// assert_eq!(ident_to_string!(Hello), "Hello"); + /// /// ``` + /// #[rune::macro_] + /// fn ident_to_string(ctx: &mut MacroContext<'_>, stream: &TokenStream) -> compile::Result { + /// let mut p = Parser::from_token_stream(stream, ctx.stream_span()); + /// let ident = p.parse_all::()?; + /// let ident = ctx.resolve(ident)?.to_owned(); + /// let string = ctx.lit(&ident); + /// Ok(quote!(#string).into_token_stream(ctx)) + /// } + /// + /// let mut m = Module::new(); + /// m.macro_meta(ident_to_string)?; + /// Ok::<_, rune::Error>(()) + /// ``` + #[inline] + pub fn macro_meta(&mut self, meta: MacroMeta) -> Result, ContextError> { + let meta = meta(); + + match meta.kind { + MacroMetaKind::Function(data) => match self.macros.entry(data.name.clone()) { + hash_map::Entry::Occupied(..) => { + Err(ContextError::ConflictingMacroName { name: data.name }) + } + hash_map::Entry::Vacant(e) => { + let mut docs = Docs::default(); + docs.set_docs(meta.docs); + + let e = e.insert(ModuleMacro { + handler: data.handler, + docs, + }); + + Ok(ItemMut { docs: &mut e.docs }) + } + }, + } + } + + /// Register a native macro handler. + /// + /// If possible, [`Module::function_meta`] should be used since it includes more + /// useful information about the function. + /// + /// # Examples + /// + /// ``` + /// use rune::Module; + /// use rune::ast; + /// use rune::compile; + /// use rune::macros::{quote, MacroContext, TokenStream}; + /// use rune::parse::Parser; + /// + /// fn ident_to_string(ctx: &mut MacroContext<'_>, stream: &TokenStream) -> compile::Result { + /// let mut p = Parser::from_token_stream(stream, ctx.stream_span()); + /// let ident = p.parse_all::()?; + /// let ident = ctx.resolve(ident)?.to_owned(); + /// let string = ctx.lit(&ident); + /// Ok(quote!(#string).into_token_stream(ctx)) + /// } + /// + /// let mut m = Module::new(); + /// m.macro_(["ident_to_string"], ident_to_string)?; + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn macro_(&mut self, name: N, f: M) -> Result, ContextError> + where + M: 'static + + Send + + Sync + + Fn(&mut MacroContext<'_>, &TokenStream) -> compile::Result, + N: IntoIterator, + N::Item: IntoComponent, + { + let name = ItemBuf::with_item(name); + + match self.macros.entry(name.clone()) { + hash_map::Entry::Occupied(..) => Err(ContextError::ConflictingMacroName { name }), + hash_map::Entry::Vacant(e) => { + let handler: Arc = Arc::new(f); + + let e = e.insert(ModuleMacro { + handler, + docs: Docs::default(), + }); + + Ok(ItemMut { docs: &mut e.docs }) + } + } + } + + /// Register a function handler through its meta. + /// + /// The metadata must be provided by annotating the function with + /// [`#[rune::function]`][crate::function]. + /// + /// This has the benefit that it captures documentation comments which can + /// be used when generating documentation or referencing the function + /// through code sense systems. + /// + /// # Examples + /// + /// ``` + /// use rune::{Module, ContextError}; + /// + /// /// This is a pretty neat function. + /// #[rune::function] + /// fn to_string(string: &str) -> String { + /// string.to_string() + /// } + /// + /// /// This is a pretty neat download function + /// #[rune::function] + /// async fn download(url: &str) -> rune::Result { + /// todo!() + /// } + /// + /// fn module() -> Result { + /// let mut m = Module::new(); + /// m.function_meta(to_string)?; + /// m.function_meta(download)?; + /// Ok(m) + /// } + /// ``` + /// + /// Registering instance functions: + /// + /// ``` + /// use rune::{Any, Module}; + /// + /// #[derive(Any)] + /// struct MyBytes { + /// queue: Vec, + /// } + /// + /// impl MyBytes { + /// fn new() -> Self { + /// Self { + /// queue: Vec::new(), + /// } + /// } + /// + /// #[rune::function] + /// fn len(&self) -> usize { + /// self.queue.len() + /// } + /// + /// #[rune::function] + /// async fn download(&self, url: &str) -> rune::Result<()> { + /// todo!() + /// } + /// } + /// + /// let mut module = Module::default(); + /// + /// module.ty::()?; + /// module.function_meta(MyBytes::len)?; + /// module.function_meta(MyBytes::download)?; + /// # Ok::<_, rune::Error>(()) + /// ``` + #[inline] + pub fn function_meta(&mut self, meta: FunctionMeta) -> Result, ContextError> { + let meta = meta(); + + match meta.kind { + FunctionMetaKind::Function(data) => { + let mut docs = Docs::default(); + docs.set_docs(meta.docs); + docs.set_arguments(meta.arguments); + self.function_inner(data, docs) + } + FunctionMetaKind::AssociatedFunction(data) => { + let mut docs = Docs::default(); + docs.set_docs(meta.docs); + docs.set_arguments(meta.arguments); + self.assoc_fn(data, docs) + } + } + } + + /// Register a function. + /// + /// If possible, [`Module::function_meta`] should be used since it includes more + /// useful information about the function. + /// + /// # Examples + /// + /// ``` + /// use rune::Module; + /// + /// fn add_ten(value: i64) -> i64 { + /// value + 10 + /// } + /// + /// let mut module = Module::default(); + /// + /// module.function(["add_ten"], add_ten)?.docs(["Adds 10 to any integer passed in."]); + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn function(&mut self, name: N, f: F) -> Result, ContextError> + where + F: Function, + F::Return: MaybeTypeOf, + N: IntoIterator, + N::Item: IntoComponent, + A: IterFunctionArgs, + { + self.function_inner(FunctionData::new(name, f), Docs::default()) + } + + /// Register an asynchronous function. + /// + /// If possible, [`Module::function_meta`] should be used since it includes + /// more useful information about the function. + /// + /// This returns a [`ItemMut`], which is a handle that can be used to associate more metadata + /// with the inserted item. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Module}; + /// # async fn download(url: &str) -> Result { Ok(String::new()) } + /// + /// #[derive(Any)] + /// struct DownloadError { + /// /* .. */ + /// } + /// + /// async fn download_quote() -> Result { + /// download("https://api.quotable.io/random").await + /// } + /// + /// let mut module = Module::default(); + /// + /// module.async_function(["download_quote"], download_quote)? + /// .docs(["Download a random quote from the internet."]); + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn async_function(&mut self, name: N, f: F) -> Result, ContextError> + where + F: AsyncFunction, + F::Output: MaybeTypeOf, + N: IntoIterator, + N::Item: IntoComponent, + A: IterFunctionArgs, + { + self.function_inner(FunctionData::new_async(name, f), Docs::default()) + } + + /// Register an instance function. + /// + /// If possible, [`Module::function_meta`] should be used since it includes + /// more useful information about the function. + /// + /// This returns a [`ItemMut`], which is a handle that can be used to associate more metadata + /// with the inserted item. + /// + /// # Examples + /// + /// ``` + /// use rune::{Any, Module}; + /// + /// #[derive(Any)] + /// struct MyBytes { + /// queue: Vec, + /// } + /// + /// impl MyBytes { + /// fn new() -> Self { + /// Self { + /// queue: Vec::new(), + /// } + /// } + /// + /// fn len(&self) -> usize { + /// self.queue.len() + /// } + /// } + /// + /// let mut module = Module::default(); + /// + /// module.ty::()?; + /// + /// module.function(["MyBytes", "new"], MyBytes::new)? + /// .docs(["Construct a new empty bytes container."]); + /// + /// module.inst_fn("len", MyBytes::len)? + /// .docs(["Get the number of bytes."]); + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn inst_fn(&mut self, name: N, f: F) -> Result, ContextError> + where + N: ToInstance, + F: InstFn, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, + { + self.assoc_fn( + AssociatedFunctionData::new(name.to_instance(), f), + Docs::default(), + ) + } + + /// Register an asynchronous instance function. + /// + /// If possible, [`Module::function_meta`] should be used since it includes + /// more useful information about the function. + /// + /// This returns a [`ItemMut`], which is a handle that can be used to associate more metadata + /// with the inserted item. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicU32; + /// use std::sync::Arc; + /// + /// use rune::{Any, Module}; + /// + /// #[derive(Clone, Debug, Any)] + /// struct Client { + /// value: Arc, + /// } + /// + /// #[derive(Any)] + /// struct DownloadError { + /// /* .. */ + /// } + /// + /// impl Client { + /// async fn download(&self) -> Result<(), DownloadError> { + /// /* .. */ + /// # Ok(()) + /// } + /// } + /// + /// let mut module = Module::default(); + /// + /// module.ty::()?; + /// module.async_inst_fn("download", Client::download)? + /// .docs(["Download a thing."]); + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn async_inst_fn(&mut self, name: N, f: F) -> Result, ContextError> + where + N: ToInstance, + F: AsyncInstFn, + F::Output: MaybeTypeOf, + A: IterFunctionArgs, + { + self.assoc_fn( + AssociatedFunctionData::new_async(name.to_instance(), f), + Docs::default(), + ) + } + + /// Install a protocol function that interacts with the given field. + /// + /// This returns a [`ItemMut`], which is a handle that can be used to + /// associate more metadata with the inserted item. + pub fn field_fn( + &mut self, + protocol: Protocol, + name: N, + f: F, + ) -> Result, ContextError> + where + N: ToFieldFunction, + F: InstFn, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, + { + self.assoc_fn( + AssociatedFunctionData::new(name.to_field_function(protocol), f), + Docs::default(), + ) + } + + /// 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]. + pub fn index_fn( + &mut self, + protocol: Protocol, + index: usize, + f: F, + ) -> Result, ContextError> + where + F: InstFn, + F::Return: MaybeTypeOf, + A: IterFunctionArgs, + { + let name = AssociatedFunctionName::index(protocol, index); + self.assoc_fn(AssociatedFunctionData::new(name, f), Docs::default()) + } + + /// Register a raw function which interacts directly with the virtual + /// machine. + /// + /// This returns a [`ItemMut`], which is a handle that can be used to + /// associate more metadata with the inserted item. + /// + /// # Examples + /// + /// ``` + /// use rune::Module; + /// use rune::runtime::{Stack, VmResult}; + /// use rune::vm_try; + /// + /// fn sum(stack: &mut Stack, args: usize) -> VmResult<()> { + /// let mut number = 0; + /// + /// for _ in 0..args { + /// number += vm_try!(vm_try!(stack.pop()).into_integer()); + /// } + /// + /// stack.push(number); + /// VmResult::Ok(()) + /// } + /// + /// let mut module = Module::default(); + /// + /// let sum = module.raw_fn(["sum"], sum)?; + /// sum.docs([ + /// "Sum all numbers provided to the function." + /// ]); + /// # Ok::<_, rune::Error>(()) + /// ``` + pub fn raw_fn(&mut self, name: N, f: F) -> Result, ContextError> + where + F: 'static + Fn(&mut Stack, usize) -> VmResult<()> + Send + Sync, + N: IntoIterator, + N::Item: IntoComponent, + { + let name = ItemBuf::with_item(name); + + if self.functions.contains_key(&name) {} + + match self.functions.entry(name) { + hash_map::Entry::Occupied(e) => Err(ContextError::ConflictingFunctionName { + name: e.key().clone(), + }), + hash_map::Entry::Vacant(e) => { + let e = e.insert(ModuleFunction { + handler: Arc::new(move |stack, args| f(stack, args)), + is_async: false, + args: None, + return_type: None, + argument_types: Box::from([]), + docs: Docs::default(), + }); + + Ok(ItemMut { docs: &mut e.docs }) + } + } + } + + fn function_inner( + &mut self, + data: FunctionData, + docs: Docs, + ) -> Result, ContextError> { + match self.functions.entry(data.name.clone()) { + hash_map::Entry::Occupied(e) => Err(ContextError::ConflictingFunctionName { + name: e.key().clone(), + }), + hash_map::Entry::Vacant(e) => { + let e = e.insert(ModuleFunction { + handler: data.handler, + is_async: data.is_async, + args: data.args, + return_type: data.return_type, + argument_types: data.argument_types, + docs, + }); + + Ok(ItemMut { docs: &mut e.docs }) + } + } + } + + /// Install an associated function. + fn assoc_fn( + &mut self, + data: AssociatedFunctionData, + docs: Docs, + ) -> Result, ContextError> { + let key = data.assoc_key(); + + match self.associated.entry(key) { + hash_map::Entry::Occupied(..) => Err(match data.name.kind { + AssociatedKind::Protocol(protocol) => ContextError::ConflictingProtocolFunction { + type_info: data.ty.type_info, + name: protocol.name.into(), + }, + AssociatedKind::FieldFn(protocol, field) => { + ContextError::ConflictingFieldFunction { + type_info: data.ty.type_info, + name: protocol.name.into(), + field, + } + } + AssociatedKind::IndexFn(protocol, index) => { + ContextError::ConflictingIndexFunction { + type_info: data.ty.type_info, + name: protocol.name.into(), + index, + } + } + AssociatedKind::Instance(name) => ContextError::ConflictingInstanceFunction { + type_info: data.ty.type_info, + name, + }, + }), + hash_map::Entry::Vacant(e) => { + let e = e.insert(ModuleAssociated { + name: data.name, + handler: data.handler, + is_async: data.is_async, + args: data.args, + return_type: data.return_type, + argument_types: data.argument_types, + docs, + type_info: data.ty.type_info, + }); + + Ok(ItemMut { docs: &mut e.docs }) + } + } + } +} + +impl AsRef for Module { + #[inline] + fn as_ref(&self) -> &Module { + self + } +} diff --git a/crates/rune/src/modules/io.rs b/crates/rune/src/modules/io.rs index 6761a08eb..396ecc7ad 100644 --- a/crates/rune/src/modules/io.rs +++ b/crates/rune/src/modules/io.rs @@ -22,7 +22,26 @@ pub fn module(stdio: bool) -> Result { if stdio { module.function_meta(print_impl)?; module.function_meta(println_impl)?; - module.raw_fn(["dbg"], dbg_impl)?; + + module.raw_fn(["dbg"], dbg_impl)?.docs([ + "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 diff --git a/crates/rune/src/params.rs b/crates/rune/src/params.rs index df42386bc..b3cf61c51 100644 --- a/crates/rune/src/params.rs +++ b/crates/rune/src/params.rs @@ -1,5 +1,5 @@ -use crate::compile::{AssociatedFunctionName, ToFieldFunction, ToInstance}; use crate::hash::{Hash, IntoHash}; +use crate::module::{AssociatedFunctionName, ToFieldFunction, ToInstance}; use crate::runtime::{FullTypeOf, Protocol}; /// Helper to register a parameterized function. diff --git a/crates/rune/src/parse/opaque.rs b/crates/rune/src/parse/opaque.rs index aaa1198b1..6102b09e7 100644 --- a/crates/rune/src/parse/opaque.rs +++ b/crates/rune/src/parse/opaque.rs @@ -1,5 +1,7 @@ use crate::ast::Spanned; use crate::parse::{Id, NonZeroId}; + +/// Helper derive to implement [`Opaque`]. pub(crate) use rune_macros::Opaque; pub(crate) trait Opaque { @@ -8,12 +10,14 @@ pub(crate) trait Opaque { } impl Opaque for Id { + #[inline] fn id(&self) -> Id { *self } } impl Opaque for NonZeroId { + #[inline] fn id(&self) -> Id { Id::new(*self) } @@ -23,6 +27,7 @@ impl Opaque for &T where T: Opaque, { + #[inline] fn id(&self) -> Id { (*self).id() } @@ -33,6 +38,7 @@ where S: Spanned, O: Opaque, { + #[inline] fn id(&self) -> Id { self.1.id() } diff --git a/crates/rune/src/parse/parse.rs b/crates/rune/src/parse/parse.rs index edb27ef2e..020c7b265 100644 --- a/crates/rune/src/parse/parse.rs +++ b/crates/rune/src/parse/parse.rs @@ -2,6 +2,8 @@ use crate::no_std::prelude::*; use crate::compile; use crate::parse::{Parser, Peek}; + +/// Helper derive to implement [`Parse`]. pub use rune_macros::Parse; /// The parse trait, implemented by items that can be parsed. @@ -18,6 +20,7 @@ where A: Parse + Peek, B: Parse, { + #[inline] fn parse(parser: &mut Parser) -> compile::Result { Ok((parser.parse()?, parser.parse()?)) } @@ -28,6 +31,7 @@ impl Parse for Option where T: Parse + Peek, { + #[inline] fn parse(parser: &mut Parser) -> compile::Result { Ok(if parser.peek::()? { Some(parser.parse()?) @@ -53,6 +57,7 @@ impl Parse for Vec where T: Parse + Peek, { + #[inline] fn parse(parser: &mut Parser) -> compile::Result { let mut output = Vec::new(); diff --git a/crates/rune/src/parse/peek.rs b/crates/rune/src/parse/peek.rs index 0ed73f507..13a35b7a6 100644 --- a/crates/rune/src/parse/peek.rs +++ b/crates/rune/src/parse/peek.rs @@ -13,6 +13,7 @@ impl Peek for Box where T: Peek, { + #[inline] fn peek(p: &mut Peeker<'_>) -> bool { T::peek(p) } @@ -23,6 +24,7 @@ where A: Parse + Peek, B: Parse, { + #[inline] fn peek(p: &mut Peeker<'_>) -> bool { A::peek(p) } diff --git a/crates/rune/src/runtime/bytes.rs b/crates/rune/src/runtime/bytes.rs index f1387225f..b010c17ac 100644 --- a/crates/rune/src/runtime/bytes.rs +++ b/crates/rune/src/runtime/bytes.rs @@ -10,7 +10,8 @@ use crate::no_std::prelude::*; use serde::{Deserialize, Serialize}; -use crate::compile::{InstallWith, Named}; +use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Mut, RawMut, RawRef, RawStr, Ref, UnsafeFromValue, Value, VmResult, }; diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index b2114d61e..fa1381786 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -12,8 +12,8 @@ use crate::no_std::prelude::*; use serde::{Deserialize, Serialize}; use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{FromValue, ProtocolCaller, RawStr, Value, VmErrorKind, VmResult}; -use crate::InstallWith; /// Error raised when trying to parse a type string and it fails. #[derive(Debug, Clone, Copy)] diff --git a/crates/rune/src/runtime/from_value.rs b/crates/rune/src/runtime/from_value.rs index e78409dc7..de83d27d9 100644 --- a/crates/rune/src/runtime/from_value.rs +++ b/crates/rune/src/runtime/from_value.rs @@ -10,7 +10,37 @@ use crate::runtime::{ }; use crate::Any; -#[doc(inline)] +/// Derive macro for the [`FromValue`] trait for converting types from the +/// dynamic `Value` container. +/// +/// # Examples +/// +/// ``` +/// use rune::{FromValue, Vm}; +/// use std::sync::Arc; +/// +/// #[derive(FromValue)] +/// struct Foo { +/// field: u64, +/// } +/// +/// let mut sources = rune::sources! { +/// entry => { +/// pub fn main() { +/// #{field: 42} +/// } +/// } +/// }; +/// +/// let unit = rune::prepare(&mut sources).build()?; +/// +/// let mut vm = Vm::without_runtime(Arc::new(unit)); +/// let foo = vm.call(["main"], ())?; +/// let foo: Foo = rune::from_value(foo)?; +/// +/// assert_eq!(foo.field, 42); +/// # Ok::<_, rune::Error>(()) +/// ``` pub use rune_macros::FromValue; /// Convert something into the dynamic [`Value`]. diff --git a/crates/rune/src/runtime/function.rs b/crates/rune/src/runtime/function.rs index d31bc0cb3..a9ae618c0 100644 --- a/crates/rune/src/runtime/function.rs +++ b/crates/rune/src/runtime/function.rs @@ -4,6 +4,7 @@ use core::future::Future; use crate::no_std::prelude::*; use crate::no_std::sync::Arc; +use crate::module; use crate::runtime::{ Args, Call, ConstValue, FromValue, FunctionHandler, RawRef, Ref, Rtti, RuntimeContext, Shared, Stack, Tuple, Unit, UnsafeFromValue, Value, VariantRtti, Vm, VmCall, VmErrorKind, VmHalt, @@ -48,7 +49,7 @@ impl Function { /// ``` pub fn function(f: Func) -> Self where - Func: crate::compile::Function, + Func: module::Function, { Self(FunctionImpl { inner: Inner::FnHandler(FnHandler { @@ -90,7 +91,7 @@ impl Function { /// ``` pub fn async_function(f: Func) -> Self where - Func: crate::compile::AsyncFunction, + Func: module::AsyncFunction, { Self(FunctionImpl { inner: Inner::FnHandler(FnHandler { diff --git a/crates/rune/src/runtime/future.rs b/crates/rune/src/runtime/future.rs index 88065e986..9371d4342 100644 --- a/crates/rune/src/runtime/future.rs +++ b/crates/rune/src/runtime/future.rs @@ -5,7 +5,8 @@ use core::task::{Context, Poll}; use crate::no_std::prelude::*; -use crate::compile::{InstallWith, Named}; +use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Mut, RawMut, RawRef, RawStr, Ref, Shared, ToValue, UnsafeFromValue, Value, VmErrorKind, VmResult, diff --git a/crates/rune/src/runtime/generator.rs b/crates/rune/src/runtime/generator.rs index 79a4ae272..4e0f4f5b6 100644 --- a/crates/rune/src/runtime/generator.rs +++ b/crates/rune/src/runtime/generator.rs @@ -2,11 +2,11 @@ use core::fmt; use core::iter; use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, GeneratorState, Iterator, Mut, RawMut, RawRef, RawStr, Ref, Shared, UnsafeFromValue, Value, Vm, VmErrorKind, VmExecution, VmResult, }; -use crate::InstallWith; /// A generator with a stored virtual machine. pub struct Generator diff --git a/crates/rune/src/runtime/generator_state.rs b/crates/rune/src/runtime/generator_state.rs index c0ea41ddb..d4e2de5bc 100644 --- a/crates/rune/src/runtime/generator_state.rs +++ b/crates/rune/src/runtime/generator_state.rs @@ -1,7 +1,8 @@ +use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Mut, RawMut, RawRef, RawStr, Ref, Shared, UnsafeFromValue, Value, VmResult, }; -use crate::{compile::Named, InstallWith}; /// The state of a generator. /// diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index 9dda0d38b..cd49915f6 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -7,8 +7,10 @@ use crate::Hash; /// Pre-canned panic reasons. /// -/// To formulate a custom reason, use [crate::runtime::Panic::custom]. +/// To formulate a custom reason, use +/// [`VmError::panic`][crate::runtime::VmError::panic]. #[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[non_exhaustive] pub enum PanicReason { /// Not implemented. NotImplemented, diff --git a/crates/rune/src/runtime/iterator.rs b/crates/rune/src/runtime/iterator.rs index 3b405db5f..ab8b6e807 100644 --- a/crates/rune/src/runtime/iterator.rs +++ b/crates/rune/src/runtime/iterator.rs @@ -7,11 +7,11 @@ use crate::no_std::prelude::*; use crate::no_std::vec; use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Function, Mut, Panic, RawMut, RawRef, RawStr, Ref, ToValue, UnsafeFromValue, Value, VmErrorKind, VmResult, }; -use crate::InstallWith; // Note: A fair amount of code in this module is duplicated from the Rust // project under the MIT license. diff --git a/crates/rune/src/runtime/object.rs b/crates/rune/src/runtime/object.rs index f1435286c..55f3217b0 100644 --- a/crates/rune/src/runtime/object.rs +++ b/crates/rune/src/runtime/object.rs @@ -8,11 +8,11 @@ use crate::no_std::prelude::*; use crate::collections::{btree_map, BTreeMap}; use crate::compile::{ItemBuf, Named}; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Iterator, Mut, RawMut, RawRef, RawStr, Ref, ToValue, UnsafeFromValue, Value, Vm, VmResult, }; -use crate::InstallWith; /// An owning iterator over the entries of a `Object`. /// diff --git a/crates/rune/src/runtime/protocol.rs b/crates/rune/src/runtime/protocol.rs index a74fe0498..2dd32c4eb 100644 --- a/crates/rune/src/runtime/protocol.rs +++ b/crates/rune/src/runtime/protocol.rs @@ -3,8 +3,9 @@ use core::fmt; use core::hash::{self, Hash as _}; use core::ops; -use crate::compile::{AssociatedFunctionKind, AssociatedFunctionName, ItemBuf, ToInstance}; +use crate::compile::ItemBuf; use crate::hash::IntoHash; +use crate::module::{AssociatedFunctionName, AssociatedKind, ToInstance}; use crate::{Hash, ToTypeHash}; /// A built in instance function. @@ -37,7 +38,7 @@ impl ToInstance for Protocol { #[inline] fn to_instance(self) -> AssociatedFunctionName { AssociatedFunctionName { - kind: AssociatedFunctionKind::Protocol(self), + kind: AssociatedKind::Protocol(self), parameters: Hash::EMPTY, #[cfg(feature = "doc")] parameter_types: vec![], diff --git a/crates/rune/src/runtime/range.rs b/crates/rune/src/runtime/range.rs index b5b172013..b7a14bea2 100644 --- a/crates/rune/src/runtime/range.rs +++ b/crates/rune/src/runtime/range.rs @@ -1,7 +1,8 @@ use core::fmt; use core::ops; -use crate::compile::{InstallWith, Named}; +use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Iterator, Mut, Panic, RawMut, RawRef, RawStr, Ref, ToValue, UnsafeFromValue, Value, Vm, VmErrorKind, VmResult, diff --git a/crates/rune/src/runtime/stack.rs b/crates/rune/src/runtime/stack.rs index 506685506..f9595b559 100644 --- a/crates/rune/src/runtime/stack.rs +++ b/crates/rune/src/runtime/stack.rs @@ -1,3 +1,4 @@ +use core::array; use core::fmt; use core::iter; use core::mem; @@ -192,6 +193,15 @@ impl Stack { } } + /// Drain the top of the stack into a vector. + pub(crate) fn drain_vec( + &mut self, + count: usize, + ) -> Result<[Value; N], StackError> { + let mut it = self.drain(count)?; + Ok(array::from_fn(move |_| it.next().unwrap())) + } + /// Extend the current stack with an iterator. /// /// ``` diff --git a/crates/rune/src/runtime/stream.rs b/crates/rune/src/runtime/stream.rs index f4606301a..89630df07 100644 --- a/crates/rune/src/runtime/stream.rs +++ b/crates/rune/src/runtime/stream.rs @@ -1,6 +1,7 @@ use core::fmt; -use crate::compile::{InstallWith, Named}; +use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, GeneratorState, Mut, RawMut, RawRef, RawStr, Ref, Shared, UnsafeFromValue, Value, Vm, VmErrorKind, VmExecution, VmResult, diff --git a/crates/rune/src/runtime/to_value.rs b/crates/rune/src/runtime/to_value.rs index 761456a2f..2d18961fb 100644 --- a/crates/rune/src/runtime/to_value.rs +++ b/crates/rune/src/runtime/to_value.rs @@ -8,7 +8,37 @@ use crate::runtime::{ }; use crate::Any; -#[doc(inline)] +/// Derive macro for the [`ToValue`] trait for converting types into the dynamic +/// `Value` container. +/// +/// # Examples +/// +/// ``` +/// use rune::{ToValue, Vm}; +/// use std::sync::Arc; +/// +/// #[derive(ToValue)] +/// struct Foo { +/// field: u64, +/// } +/// +/// let mut sources = rune::sources! { +/// entry => { +/// pub fn main(foo) { +/// foo.field + 1 +/// } +/// } +/// }; +/// +/// let unit = rune::prepare(&mut sources).build()?; +/// +/// let mut vm = Vm::without_runtime(Arc::new(unit)); +/// let value = vm.call(["main"], (Foo { field: 42 },))?; +/// let value: u64 = rune::from_value(value)?; +/// +/// assert_eq!(value, 43); +/// # Ok::<_, rune::Error>(()) +/// ``` pub use rune_macros::ToValue; /// Convert something into the dynamic [`Value`]. diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index f24e0eae7..6fc1f6e46 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -668,22 +668,31 @@ impl Value { /// Try to coerce value into a boolean. #[inline] - pub fn into_bool(self) -> VmResult { + pub fn as_bool(&self) -> VmResult { match self { - Self::Bool(b) => VmResult::Ok(b), + Self::Bool(b) => VmResult::Ok(*b), actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), } } /// Try to coerce value into a boolean. #[inline] - pub fn as_bool(&self) -> VmResult { + pub fn into_bool(self) -> VmResult { match self { - Self::Bool(b) => VmResult::Ok(*b), + Self::Bool(b) => VmResult::Ok(b), actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), } } + /// Try to coerce value into a byte. + #[inline] + pub fn as_byte(&self) -> VmResult { + match self { + Self::Byte(b) => VmResult::Ok(*b), + actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + } + } + /// Try to coerce value into a byte. #[inline] pub fn into_byte(self) -> VmResult { @@ -693,6 +702,15 @@ impl Value { } } + /// Try to coerce value into a character. + #[inline] + pub fn as_char(&self) -> VmResult { + match self { + Self::Char(c) => VmResult::Ok(*c), + actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + } + } + /// Try to coerce value into a character. #[inline] pub fn into_char(self) -> VmResult { @@ -702,6 +720,15 @@ impl Value { } } + /// Try to coerce value into an integer. + #[inline] + pub fn as_integer(&self) -> VmResult { + match self { + Self::Integer(integer) => VmResult::Ok(*integer), + actual => err(VmErrorKind::expected::(vm_try!(actual.type_info()))), + } + } + /// Try to coerce value into an integer. #[inline] pub fn into_integer(self) -> VmResult { diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs index 8667526cc..b09f3ff37 100644 --- a/crates/rune/src/runtime/vec.rs +++ b/crates/rune/src/runtime/vec.rs @@ -6,7 +6,8 @@ use core::slice; use crate::no_std::prelude::*; use crate::no_std::vec; -use crate::compile::{InstallWith, Named}; +use crate::compile::Named; +use crate::module::InstallWith; use crate::runtime::{ FromValue, Iterator, Mut, RawMut, RawRef, RawStr, Ref, Shared, ToValue, UnsafeFromValue, Value, Vm, VmErrorKind, VmResult, diff --git a/crates/rune/src/runtime/vm_execution.rs b/crates/rune/src/runtime/vm_execution.rs index 0404b4a08..8f20439ee 100644 --- a/crates/rune/src/runtime/vm_execution.rs +++ b/crates/rune/src/runtime/vm_execution.rs @@ -273,8 +273,7 @@ where /// If the function being executed is a generator or stream this will resume /// it while returning a unit from the current `yield`. /// - /// If any async instructions are encountered, this will error with - /// [VmErrorKind::Halted]. + /// If any async instructions are encountered, this will error. pub fn resume(&mut self) -> VmResult { if matches!(self.state, ExecutionState::Resumed) { vm_mut!(self).stack_mut().push(Value::Unit); diff --git a/crates/rune/src/spanned.rs b/crates/rune/src/spanned.rs deleted file mode 100644 index 5cdf28f9b..000000000 --- a/crates/rune/src/spanned.rs +++ /dev/null @@ -1,130 +0,0 @@ -use crate::{Id, Span}; -pub use rune_macros::{OptionSpanned, Spanned}; - -/// Types for which we can get a span. -pub trait Spanned { - /// Get the span of the type. - fn span(&self) -> Span; -} - -impl Spanned for (A, B) -where - A: Spanned, - B: Spanned, -{ - fn span(&self) -> Span { - self.0.span().join(self.1.span()) - } -} - -impl Spanned for Span { - fn span(&self) -> Span { - *self - } -} - -impl Spanned for Box -where - T: Spanned, -{ - fn span(&self) -> Span { - Spanned::span(&**self) - } -} - -impl Spanned for &T -where - T: Spanned, -{ - fn span(&self) -> Span { - Spanned::span(*self) - } -} - -impl Spanned for &mut T -where - T: Spanned, -{ - fn span(&self) -> Span { - Spanned::span(*self) - } -} - -impl Spanned for (S, Id) -where - S: Spanned, -{ - fn span(&self) -> Span { - self.0.span() - } -} - -impl Spanned for (S, Option) -where - S: Spanned, -{ - fn span(&self) -> Span { - self.0.span() - } -} - -/// Types for which we can optionally get a span. -pub trait OptionSpanned { - /// Get the optional span of the type. - fn option_span(&self) -> Option; -} - -impl OptionSpanned for std::slice::Iter<'_, S> -where - S: Spanned, -{ - fn option_span(&self) -> Option { - OptionSpanned::option_span(self.as_slice()) - } -} - -impl OptionSpanned for Box -where - T: OptionSpanned, -{ - fn option_span(&self) -> Option { - OptionSpanned::option_span(&**self) - } -} - -/// Take the span of a vector of spanned. -/// Provides the span between the first and the last element. -impl OptionSpanned for Vec -where - T: Spanned, -{ - fn option_span(&self) -> Option { - OptionSpanned::option_span(&**self) - } -} - -/// Take the span of a vector of spanned. -/// Provides the span between the first and the last element. -impl OptionSpanned for [T] -where - T: Spanned, -{ - fn option_span(&self) -> Option { - let span = self.first()?.span(); - - if let Some(last) = self.last() { - Some(span.join(last.span())) - } else { - Some(span) - } - } -} - -impl OptionSpanned for Option -where - T: Spanned, -{ - fn option_span(&self) -> Option { - Some(self.as_ref()?.span()) - } -} diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index 4604d566e..9caddaf70 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -12,6 +12,7 @@ pub(crate) mod prelude { }; pub(crate) use crate::diagnostics; pub(crate) use crate::macros; + pub(crate) use crate::module::InstallWith; pub(crate) use crate::parse; pub(crate) use crate::runtime::{ self, AnyObj, AnyTypeInfo, Bytes, FullTypeOf, Function, MaybeTypeOf, Object, Protocol, @@ -21,7 +22,7 @@ pub(crate) mod prelude { pub(crate) use crate::tests::run; pub(crate) use crate::{ from_value, prepare, sources, span, vm_try, Any, Context, ContextError, Diagnostics, - FromValue, Hash, InstallWith, Module, Result, Source, Sources, ToValue, Value, Vm, + FromValue, Hash, Module, Result, Source, Sources, ToValue, Value, Vm, }; pub(crate) use futures_executor::block_on; } diff --git a/crates/rune/src/workspace/spanned_value.rs b/crates/rune/src/workspace/spanned_value.rs index 60c2005d3..a7da1ef44 100644 --- a/crates/rune/src/workspace/spanned_value.rs +++ b/crates/rune/src/workspace/spanned_value.rs @@ -1,6 +1,6 @@ //! Definition of a TOML spanned value //! -//! Copied from https://github.com/est31/toml-spanned-value/tree/e925c52d22dc92c7147cf13ddbd43f78e02b8c32 +//! Copied from . #![allow(unused)] diff --git a/crates/rune-macros/tests/test_macro.rs b/crates/rune/tests/test_macro.rs similarity index 100% rename from crates/rune-macros/tests/test_macro.rs rename to crates/rune/tests/test_macro.rs diff --git a/crates/rune-macros/tests/test_rename.rs b/crates/rune/tests/test_rename.rs similarity index 100% rename from crates/rune-macros/tests/test_rename.rs rename to crates/rune/tests/test_rename.rs diff --git a/tools/site/src/main.rs b/tools/site/src/main.rs index 7b1add034..68b78a0f6 100644 --- a/tools/site/src/main.rs +++ b/tools/site/src/main.rs @@ -1,4 +1,4 @@ -//! A small utility to build the guts of https://rune-rs.github.io +//! A small utility to build the guts of . use anyhow::{bail, Result}; use flate2::read::GzDecoder;