rhai_codegen-2.0.0/.cargo_vcs_info.json0000644000000001450000000000100134420ustar { "git": { "sha1": "bb6c700006ed75340b1faa040282bc9c711d5aa6" }, "path_in_vcs": "codegen" }rhai_codegen-2.0.0/Cargo.toml0000644000000026600000000000100114440ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "rhai_codegen" version = "2.0.0" authors = [ "jhwgh1968", "Stephen Chung", ] description = "Procedural macros support package for Rhai, a scripting language and engine for Rust" homepage = "https://rhai.rs/book/plugins/index.html" readme = "README.md" keywords = [ "scripting", "scripting-engine", "scripting-language", "embedded", "plugin", ] categories = [ "no-std", "embedded", "wasm", "parser-implementations", ] license = "MIT OR Apache-2.0" repository = "https://github.com/rhaiscript/rhai" resolver = "2" [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0.0" [dependencies.quote] version = "1.0.0" [dependencies.syn] version = "2.0.0" features = [ "full", "parsing", "printing", "proc-macro", "extra-traits", ] [dev-dependencies.rhai] version = "1.17.0" features = ["metadata"] [dev-dependencies.trybuild] version = "1.0.0" [features] default = [] metadata = [] rhai_codegen-2.0.0/Cargo.toml.orig000064400000000000000000000015470072674642500151600ustar 00000000000000[package] name = "rhai_codegen" version = "2.0.0" edition = "2018" resolver = "2" authors = ["jhwgh1968", "Stephen Chung"] description = "Procedural macros support package for Rhai, a scripting language and engine for Rust" keywords = ["scripting", "scripting-engine", "scripting-language", "embedded", "plugin"] categories = ["no-std", "embedded", "wasm", "parser-implementations"] homepage = "https://rhai.rs/book/plugins/index.html" repository = "https://github.com/rhaiscript/rhai" license = "MIT OR Apache-2.0" [lib] proc-macro = true [features] default = [] metadata = [] [dependencies] proc-macro2 = "1.0.0" syn = { version = "2.0.0", features = ["full", "parsing", "printing", "proc-macro", "extra-traits"] } quote = "1.0.0" [dev-dependencies] rhai = { path = "..", version = "1.17.0", features = ["metadata"] } trybuild = "1.0.0" rhai_codegen-2.0.0/README.md000064400000000000000000000006450072674642500135460ustar 00000000000000Procedural Macros for Plugins ============================= ![Rhai logo](https://rhai.rs/book/images/logo/rhai-banner-transparent-colour.svg) This crate holds procedural macros for code generation, supporting the plugins system for [Rhai](https://github.com/rhaiscript/rhai). This crate is automatically referenced by the [Rhai crate](https://crates.io/crates/rhai). Normally it should not be used directly. rhai_codegen-2.0.0/src/attrs.rs000064400000000000000000000127440072674642500145640ustar 00000000000000use proc_macro2::{Ident, Span, TokenStream}; use syn::{ parse::{ParseStream, Parser}, spanned::Spanned, }; #[derive(Debug, Clone, Eq, PartialEq, Default, Hash)] pub enum ExportScope { #[default] PubOnly, Prefix(String), All, } pub trait ExportedParams: Sized { fn parse_stream(args: ParseStream) -> syn::Result; fn no_attrs() -> Self; fn from_info(info: ExportInfo) -> syn::Result; } #[derive(Debug, Clone)] pub struct AttrItem { pub key: Ident, pub value: Option, pub span: Span, } #[derive(Debug, Clone)] pub struct ExportInfo { pub item_span: Span, pub items: Vec, } pub fn parse_attr_items(args: ParseStream) -> syn::Result { if args.is_empty() { return Ok(ExportInfo { item_span: args.span(), items: Vec::new(), }); } let arg_list = args.call(syn::punctuated::Punctuated::parse_separated_nonempty)?; parse_punctuated_items(arg_list) } pub fn parse_punctuated_items( arg_list: syn::punctuated::Punctuated, ) -> syn::Result { let list_span = arg_list.span(); let mut attrs = Vec::new(); for arg in arg_list { let arg_span = arg.span(); let (key, value) = match arg { syn::Expr::Assign(syn::ExprAssign { ref left, ref right, .. }) => { let attr_name = match left.as_ref() { syn::Expr::Path(syn::ExprPath { path: attr_path, .. }) => attr_path.get_ident().cloned().ok_or_else(|| { syn::Error::new(attr_path.span(), "expecting attribute name") })?, x => return Err(syn::Error::new(x.span(), "expecting attribute name")), }; let attr_value = match right.as_ref() { syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(string), .. }) => string.clone(), x => return Err(syn::Error::new(x.span(), "expecting string literal")), }; (attr_name, Some(attr_value)) } syn::Expr::Path(syn::ExprPath { path, .. }) => path .get_ident() .cloned() .map(|a| (a, None)) .ok_or_else(|| syn::Error::new(path.span(), "expecting attribute name"))?, x => return Err(syn::Error::new(x.span(), "expecting identifier")), }; attrs.push(AttrItem { key, value, span: arg_span, }); } Ok(ExportInfo { item_span: list_span, items: attrs, }) } pub fn outer_item_attributes( args: TokenStream, _attr_name: &str, ) -> syn::Result { if args.is_empty() { return Ok(T::no_attrs()); } let arg_list = syn::punctuated::Punctuated::parse_separated_nonempty.parse2(args)?; T::from_info(parse_punctuated_items(arg_list)?) } pub fn inner_item_attributes( attrs: &mut Vec, attr_name: &str, ) -> syn::Result { // Find the #[rhai_fn] attribute which will turn be read for function parameters. if let Some(index) = attrs.iter().position(|a| a.path().is_ident(attr_name)) { let rhai_fn_attr = attrs.remove(index); // Cannot have more than one #[rhai_fn] if let Some(duplicate) = attrs.iter().find(|&a| a.path().is_ident(attr_name)) { return Err(syn::Error::new( duplicate.span(), format!("duplicated attribute '{attr_name}'"), )); } rhai_fn_attr.parse_args_with(T::parse_stream) } else { Ok(T::no_attrs()) } } #[cfg(feature = "metadata")] pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result> { // Find the #[doc] attribute which will turn be read for function documentation. let mut comments = Vec::new(); let mut buf = String::new(); for attr in attrs { if !attr.path().is_ident("doc") { continue; } if let syn::Meta::NameValue(syn::MetaNameValue { value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(ref s), .. }), .. }) = attr.meta { let mut line = s.value(); if line.contains('\n') { // Must be a block comment `/** ... */` if !buf.is_empty() { comments.push(buf.clone()); buf.clear(); } line.insert_str(0, "/**"); line += "*/"; comments.push(line); } else { // Single line - assume it is `///` if !buf.is_empty() { buf += "\n"; } buf += "///"; buf += &line; } } } if !buf.is_empty() { comments.push(buf); } Ok(comments) } pub fn collect_cfg_attr(attrs: &[syn::Attribute]) -> Vec { attrs .iter() .filter(|&a| a.path().is_ident("cfg")) .cloned() .collect() } rhai_codegen-2.0.0/src/custom_type.rs000064400000000000000000000263240072674642500160010ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use syn::{ punctuated::Punctuated, spanned::Spanned, Data, DataStruct, DeriveInput, Expr, Field, Fields, MetaNameValue, Path, Token, }; const ATTR: &str = "rhai_type"; const OPTION_NAME: &str = "name"; const OPTION_SKIP: &str = "skip"; const OPTION_GET: &str = "get"; const OPTION_GET_MUT: &str = "get_mut"; const OPTION_SET: &str = "set"; const OPTION_READONLY: &str = "readonly"; const OPTION_EXTRA: &str = "extra"; /// Derive the `CustomType` trait for a struct. pub fn derive_custom_type_impl(input: DeriveInput) -> TokenStream { let type_name = input.ident; let mut display_name = quote! { stringify!(#type_name) }; let mut field_accessors = Vec::new(); let mut extras = Vec::new(); let mut errors = Vec::new(); for attr in input.attrs.iter().filter(|a| a.path().is_ident(ATTR)) { let config_list: Result, _> = attr.parse_args_with(Punctuated::parse_terminated); match config_list { Ok(list) => { for expr in list { match expr { // Key-value Expr::Assign(..) => { let MetaNameValue { path, value, .. } = syn::parse2::(expr.to_token_stream()).unwrap(); if path.is_ident(OPTION_NAME) { // Type name display_name = value.to_token_stream(); } else if path.is_ident(OPTION_EXTRA) { match syn::parse2::(value.to_token_stream()) { Ok(path) => extras.push(path.to_token_stream()), Err(err) => errors.push(err.into_compile_error()), } } else { let key = path.get_ident().unwrap().to_string(); let msg = format!("invalid option: '{}'", key); errors.push(syn::Error::new(path.span(), msg).into_compile_error()); } } // skip Expr::Path(path) if path.path.is_ident(OPTION_SKIP) => { println!("SKIPPED"); } // any other identifier Expr::Path(path) if path.path.get_ident().is_some() => { let key = path.path.get_ident().unwrap().to_string(); let msg = format!("invalid option: '{}'", key); errors.push(syn::Error::new(path.span(), msg).into_compile_error()); } // Error _ => errors.push( syn::Error::new(expr.span(), "expecting identifier") .into_compile_error(), ), } } } Err(err) => errors.push(err.into_compile_error()), } } match input.data { // struct Foo { ... } Data::Struct(DataStruct { fields: Fields::Named(ref f), .. }) => scan_fields( &f.named.iter().collect::>(), &mut field_accessors, &mut errors, ), // struct Foo(...); Data::Struct(DataStruct { fields: Fields::Unnamed(ref f), .. }) => scan_fields( &f.unnamed.iter().collect::>(), &mut field_accessors, &mut errors, ), // struct Foo; Data::Struct(DataStruct { fields: Fields::Unit, .. }) => (), // enum ... Data::Enum(_) => { return syn::Error::new(Span::call_site(), "enums are not yet implemented") .into_compile_error() } // union ... Data::Union(_) => { return syn::Error::new(Span::call_site(), "unions are not yet supported") .into_compile_error() } }; quote! { impl CustomType for #type_name { fn build(mut builder: TypeBuilder) { #(#errors)* builder.with_name(#display_name); #(#field_accessors)* #(#extras(&mut builder);)* } } } } fn scan_fields(fields: &[&Field], accessors: &mut Vec, errors: &mut Vec) { for (i, &field) in fields.iter().enumerate() { let mut map_name = None; let mut get_fn = None; let mut get_mut_fn = None; let mut set_fn = None; let mut readonly = false; let mut skip = false; for attr in field.attrs.iter().filter(|a| a.path().is_ident(ATTR)) { let options_list: Result, _> = attr.parse_args_with(Punctuated::parse_terminated); let options = match options_list { Ok(list) => list, Err(err) => { errors.push(err.into_compile_error()); continue; } }; for expr in options { let ident = match expr { // skip Expr::Path(path) if path.path.is_ident(OPTION_SKIP) => { skip = true; // `skip` cannot be used with any other attributes. if get_fn.is_some() || get_mut_fn.is_some() || set_fn.is_some() || map_name.is_some() || readonly { let msg = format!("cannot use '{OPTION_SKIP}' with other attributes"); errors.push(syn::Error::new(path.span(), msg).into_compile_error()); } continue; } // readonly Expr::Path(path) if path.path.is_ident(OPTION_READONLY) => { readonly = true; if set_fn.is_some() { let msg = format!("cannot use '{OPTION_READONLY}' with '{OPTION_SET}'"); errors .push(syn::Error::new(path.path.span(), msg).into_compile_error()); } path.path.get_ident().unwrap().clone() } // Key-value Expr::Assign(..) => { let MetaNameValue { path, value, .. } = syn::parse2::(expr.to_token_stream()).unwrap(); if path.is_ident(OPTION_NAME) { // Type name map_name = Some(value.to_token_stream()); } else if path.is_ident(OPTION_GET) { match syn::parse2::(value.to_token_stream()) { Ok(path) => get_fn = Some(path.to_token_stream()), Err(err) => errors.push(err.into_compile_error()), } } else if path.is_ident(OPTION_GET_MUT) { match syn::parse2::(value.to_token_stream()) { Ok(path) => get_mut_fn = Some(path.to_token_stream()), Err(err) => errors.push(err.into_compile_error()), } } else if path.is_ident(OPTION_SET) { match syn::parse2::(value.to_token_stream()) { Ok(path) => set_fn = Some(path.to_token_stream()), Err(err) => errors.push(err.into_compile_error()), } } else if path.is_ident(OPTION_SKIP) || path.is_ident(OPTION_READONLY) { let key = path.get_ident().unwrap().to_string(); let msg = format!("'{key}' cannot have value"); errors.push(syn::Error::new(path.span(), msg).into_compile_error()); continue; } else { let key = path.get_ident().unwrap().to_string(); let msg = format!("invalid option: '{key}'"); errors.push(syn::Error::new(path.span(), msg).into_compile_error()); continue; } path.get_ident().unwrap().clone() } // any other identifier Expr::Path(path) if path.path.get_ident().is_some() => { let key = path.path.get_ident().unwrap().to_string(); let msg = format!("invalid option: '{key}'"); errors.push(syn::Error::new(path.span(), msg).into_compile_error()); continue; } // Error _ => { errors.push( syn::Error::new(expr.span(), "expecting identifier") .into_compile_error(), ); continue; } }; if skip { let msg = format!("cannot use '{ident}' with '{OPTION_SKIP}'"); errors.push(syn::Error::new(attr.path().span(), msg).into_compile_error()); } } } // If skipped don't do anything. if skip { continue; } // No field name - use field0, field1... let field_name = if let Some(ref field_name) = field.ident { quote! { #field_name } } else { if map_name.is_none() { let name = format!("field{i}"); map_name = Some(quote! { #name }); } let index = proc_macro2::Literal::usize_unsuffixed(i); quote! { #index } }; // Override functions let get = match (get_mut_fn, get_fn) { (Some(func), _) => func, (None, Some(func)) => quote! { |obj: &mut Self| #func(&*obj) }, (None, None) => quote! { |obj: &mut Self| obj.#field_name.clone() }, }; let set = set_fn.unwrap_or_else(|| quote! { |obj: &mut Self, val| obj.#field_name = val }); let name = map_name.unwrap_or_else(|| quote! { stringify!(#field_name) }); accessors.push(if readonly { quote! { builder.with_get(#name, #get); } } else { quote! { builder.with_get_set(#name, #get, #set); } }); } } rhai_codegen-2.0.0/src/function.rs000064400000000000000000000777440072674642500152670ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use syn::{ parse::{Parse, ParseStream}, spanned::Spanned, }; #[cfg(no_std)] use alloc::format; #[cfg(not(no_std))] use std::format; use std::borrow::Cow; use crate::attrs::{ExportInfo, ExportScope, ExportedParams}; #[derive(Clone, Debug, Eq, PartialEq, Copy, Default, Hash)] pub enum FnNamespaceAccess { #[default] Unset, Global, Internal, } #[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)] pub enum Index { Get, Set, } #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum Property { Get(syn::Ident), Set(syn::Ident), } #[derive(Clone, Debug, Eq, PartialEq, Default, Hash)] pub enum FnSpecialAccess { #[default] None, Index(Index), Property(Property), } impl FnSpecialAccess { pub fn get_fn_name(&self) -> Option<(String, String, Span)> { match self { FnSpecialAccess::None => None, FnSpecialAccess::Property(Property::Get(ref g)) => { Some((format!("{FN_GET}{g}"), g.to_string(), g.span())) } FnSpecialAccess::Property(Property::Set(ref s)) => { Some((format!("{FN_SET}{s}"), s.to_string(), s.span())) } FnSpecialAccess::Index(Index::Get) => Some(( FN_IDX_GET.to_string(), "index_get".to_string(), Span::call_site(), )), FnSpecialAccess::Index(Index::Set) => Some(( FN_IDX_SET.to_string(), "index_set".to_string(), Span::call_site(), )), } } } pub fn flatten_type_groups(ty: &syn::Type) -> &syn::Type { match ty { syn::Type::Group(syn::TypeGroup { ref elem, .. }) | syn::Type::Paren(syn::TypeParen { ref elem, .. }) => flatten_type_groups(elem.as_ref()), _ => ty, } } pub fn print_type(ty: &syn::Type) -> String { ty.to_token_stream() .to_string() .replace(" , ", ", ") .replace("& ", "&") .replace(" :: ", "::") .replace(" ( ", "(") .replace(" ) ", ")") .replace(" < ", "<") .replace(" > ", ">") } #[derive(Debug, Default)] pub struct ExportedFnParams { pub name: Vec, pub return_raw: Option, pub pure: Option, pub volatile: Option, pub skip: bool, pub special: FnSpecialAccess, pub namespace: FnNamespaceAccess, pub span: Option, } pub const FN_GET: &str = "get$"; pub const FN_SET: &str = "set$"; pub const FN_IDX_GET: &str = "index$get$"; pub const FN_IDX_SET: &str = "index$set$"; impl Parse for ExportedFnParams { fn parse(args: ParseStream) -> syn::Result { if args.is_empty() { return Ok(<_>::default()); } let info = crate::attrs::parse_attr_items(args)?; Self::from_info(info) } } impl ExportedParams for ExportedFnParams { fn parse_stream(args: ParseStream) -> syn::Result { Self::parse(args) } fn no_attrs() -> Self { Self::default() } fn from_info(info: crate::attrs::ExportInfo) -> syn::Result { let ExportInfo { item_span: span, items: attrs, } = info; let mut name = Vec::new(); let mut return_raw = None; let mut pure = None; let mut volatile = None; let mut skip = false; let mut namespace = FnNamespaceAccess::Unset; let mut special = FnSpecialAccess::None; for attr in attrs { let crate::attrs::AttrItem { key, value, span: item_span, } = attr; match (key.to_string().as_ref(), value) { ("get", None) | ("set", None) | ("name", None) => { return Err(syn::Error::new(key.span(), "requires value")) } ("name", Some(s)) if s.value() == FN_IDX_GET => { return Err(syn::Error::new( item_span, "use attribute 'index_get' instead", )) } ("name", Some(s)) if s.value() == FN_IDX_SET => { return Err(syn::Error::new( item_span, "use attribute 'index_set' instead", )) } ("name", Some(s)) if s.value().starts_with(FN_GET) => { return Err(syn::Error::new( item_span, format!( "use attribute 'getter = \"{}\"' instead", &s.value()[FN_GET.len()..] ), )) } ("name", Some(s)) if s.value().starts_with(FN_SET) => { return Err(syn::Error::new( item_span, format!( "use attribute 'setter = \"{}\"' instead", &s.value()[FN_SET.len()..] ), )) } ("name", Some(s)) => name.push(s.value()), ("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) | ("pure", Some(s)) | ("skip", Some(s)) | ("global", Some(s)) | ("internal", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) } ("pure", None) => pure = Some(item_span), ("volatile", None) => volatile = Some(item_span), ("return_raw", None) => return_raw = Some(item_span), ("skip", None) => skip = true, ("global", None) => match namespace { FnNamespaceAccess::Unset => namespace = FnNamespaceAccess::Global, FnNamespaceAccess::Global => (), FnNamespaceAccess::Internal => { return Err(syn::Error::new( key.span(), "namespace is already set to 'internal'", )) } }, ("internal", None) => match namespace { FnNamespaceAccess::Unset => namespace = FnNamespaceAccess::Internal, FnNamespaceAccess::Internal => (), FnNamespaceAccess::Global => { return Err(syn::Error::new( key.span(), "namespace is already set to 'global'", )) } }, ("get", Some(s)) => { special = match special { FnSpecialAccess::None => FnSpecialAccess::Property(Property::Get( syn::Ident::new(&s.value(), s.span()), )), _ => return Err(syn::Error::new(item_span.span(), "conflicting getter")), } } ("set", Some(s)) => { special = match special { FnSpecialAccess::None => FnSpecialAccess::Property(Property::Set( syn::Ident::new(&s.value(), s.span()), )), _ => return Err(syn::Error::new(item_span.span(), "conflicting setter")), } } ("index_get", None) => { special = match special { FnSpecialAccess::None => FnSpecialAccess::Index(Index::Get), _ => { return Err(syn::Error::new(item_span.span(), "conflicting index_get")) } } } ("index_set", None) => { special = match special { FnSpecialAccess::None => FnSpecialAccess::Index(Index::Set), _ => { return Err(syn::Error::new(item_span.span(), "conflicting index_set")) } } } (attr, ..) => { return Err(syn::Error::new( key.span(), format!("unknown attribute '{attr}'"), )) } } } Ok(ExportedFnParams { name, return_raw, pure, volatile, skip, special, namespace, span: Some(span), }) } } #[derive(Debug)] pub struct ExportedFn { entire_span: Span, signature: syn::Signature, visibility: syn::Visibility, pass_context: bool, mut_receiver: bool, params: ExportedFnParams, cfg_attrs: Vec, #[cfg(feature = "metadata")] comments: Vec, } impl Parse for ExportedFn { fn parse(input: ParseStream) -> syn::Result { let fn_all: syn::ItemFn = input.parse()?; let entire_span = fn_all.span(); let str_type_path = syn::parse2::(quote! { str }).unwrap(); let context_type_path1 = syn::parse2::(quote! { NativeCallContext }).unwrap(); let context_type_path2 = syn::parse2::(quote! { rhai::NativeCallContext }).unwrap(); let mut pass_context = false; let cfg_attrs = crate::attrs::collect_cfg_attr(&fn_all.attrs); let visibility = fn_all.vis; // Determine if the function requires a call context if let Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) = fn_all.sig.inputs.first() { match flatten_type_groups(ty.as_ref()) { syn::Type::Path(p) if p.path == context_type_path1 || p.path == context_type_path2 => { pass_context = true; } _ => (), } } let skip_slots = usize::from(pass_context); // Determine whether function generates a special calling convention for a mutable receiver. let mut_receiver = match fn_all.sig.inputs.iter().nth(skip_slots) { Some(syn::FnArg::Receiver(syn::Receiver { reference: Some(_), .. })) => true, Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) => { match flatten_type_groups(ty.as_ref()) { syn::Type::Reference(syn::TypeReference { mutability: Some(_), .. }) => true, syn::Type::Reference(syn::TypeReference { mutability: None, ref elem, .. }) => match flatten_type_groups(elem.as_ref()) { syn::Type::Path(ref p) if p.path == str_type_path => false, _ => { return Err(syn::Error::new( ty.span(), "references from Rhai in this position must be mutable", )) } }, _ => false, } } _ => false, }; // All arguments after the first must be moved except for &str. for arg in fn_all.sig.inputs.iter().skip(skip_slots + 1) { let ty = match arg { syn::FnArg::Typed(syn::PatType { ref ty, .. }) => ty, _ => unreachable!("receiver argument outside of first position!?"), }; let is_ok = match flatten_type_groups(ty.as_ref()) { syn::Type::Reference(syn::TypeReference { mutability: Some(_), .. }) => false, syn::Type::Reference(syn::TypeReference { mutability: None, ref elem, .. }) => { matches!(flatten_type_groups(elem.as_ref()), syn::Type::Path(ref p) if p.path == str_type_path) } syn::Type::Verbatim(..) => false, _ => true, }; if !is_ok { return Err(syn::Error::new( ty.span(), "function parameters other than the first one cannot be passed by reference", )); } } // Check return type. if let syn::ReturnType::Type(.., ref ret_type) = fn_all.sig.output { match flatten_type_groups(ret_type.as_ref()) { syn::Type::Ptr(..) => { return Err(syn::Error::new( fn_all.sig.output.span(), "Rhai functions cannot return pointers", )) } syn::Type::Reference(..) => { return Err(syn::Error::new( fn_all.sig.output.span(), "Rhai functions cannot return references", )) } _ => (), } } Ok(ExportedFn { entire_span, signature: fn_all.sig, visibility, pass_context, mut_receiver, params: <_>::default(), cfg_attrs, #[cfg(feature = "metadata")] comments: Vec::new(), }) } } impl ExportedFn { #![allow(unused)] pub fn params(&self) -> &ExportedFnParams { &self.params } pub fn cfg_attrs(&self) -> &[syn::Attribute] { &self.cfg_attrs } pub fn update_scope(&mut self, parent_scope: &ExportScope) { let keep = match (self.params.skip, parent_scope) { (true, ..) => false, (.., ExportScope::PubOnly) => self.is_public(), (.., ExportScope::Prefix(s)) => self.name().to_string().starts_with(s), (.., ExportScope::All) => true, }; self.params.skip = !keep; } pub fn skipped(&self) -> bool { self.params.skip } pub fn pass_context(&self) -> bool { self.pass_context } pub fn signature(&self) -> &syn::Signature { &self.signature } pub fn mutable_receiver(&self) -> bool { self.mut_receiver } pub fn is_public(&self) -> bool { !matches!(self.visibility, syn::Visibility::Inherited) } pub fn span(&self) -> &Span { &self.entire_span } pub fn name(&self) -> &syn::Ident { &self.signature.ident } pub fn exported_names(&self) -> Vec { let mut literals: Vec<_> = self .params .name .iter() .map(|s| syn::LitStr::new(s, Span::call_site())) .collect(); if let Some((s, _, span)) = self.params.special.get_fn_name() { literals.push(syn::LitStr::new(&s, span)); } if literals.is_empty() { literals.push(syn::LitStr::new( &self.signature.ident.to_string(), self.signature.ident.span(), )); } literals } pub fn exported_name(&self) -> Cow { self.params .name .last() .map_or_else(|| self.signature.ident.to_string().into(), |s| s.into()) } pub fn arg_list(&self) -> impl Iterator { let skip = usize::from(self.pass_context); self.signature.inputs.iter().skip(skip) } pub fn arg_count(&self) -> usize { let skip = usize::from(self.pass_context); self.signature.inputs.len() - skip } pub fn return_type(&self) -> Option<&syn::Type> { match self.signature.output { syn::ReturnType::Type(.., ref ret_type) => Some(flatten_type_groups(ret_type)), _ => None, } } #[cfg(feature = "metadata")] pub fn comments(&self) -> &[String] { &self.comments } #[cfg(feature = "metadata")] pub fn set_comments(&mut self, comments: Vec) { self.comments = comments } pub fn set_cfg_attrs(&mut self, cfg_attrs: Vec) { self.cfg_attrs = cfg_attrs } pub fn set_params(&mut self, mut params: ExportedFnParams) -> syn::Result<()> { // Several issues are checked here to avoid issues with diagnostics caused by raising them later. // // 1a. Do not allow non-returning raw functions. // if params.return_raw.is_some() && self.return_type().is_none() { return Err(syn::Error::new( params.return_raw.unwrap(), "functions marked with 'return_raw' must return Result>", )); } // 1b. Do not allow non-method pure functions. // if params.pure.is_some() && !self.mutable_receiver() { return Err(syn::Error::new( params.pure.unwrap(), "'pure' is not necessary on functions without a &mut first parameter", )); } match params.special { // 2a. Property getters must take only the subject as an argument. FnSpecialAccess::Property(Property::Get(..)) if self.arg_count() != 1 => { return Err(syn::Error::new( self.signature.inputs.span(), "property getter requires exactly 1 parameter", )) } // 2b. Property getters must return a value. FnSpecialAccess::Property(Property::Get(..)) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), "property getter must return a value", )) } // 3a. Property setters must take the subject and a new value as arguments. FnSpecialAccess::Property(Property::Set(..)) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.inputs.span(), "property setter requires exactly 2 parameters", )) } // 3b. Non-raw property setters must return nothing. FnSpecialAccess::Property(Property::Set(..)) if params.return_raw.is_none() && self.return_type().is_some() => { return Err(syn::Error::new( self.signature.output.span(), "property setter cannot return any value", )) } // 4a. Index getters must take the subject and the accessed "index" as arguments. FnSpecialAccess::Index(Index::Get) if self.arg_count() != 2 => { return Err(syn::Error::new( self.signature.inputs.span(), "index getter requires exactly 2 parameters", )) } // 4b. Index getters must return a value. FnSpecialAccess::Index(Index::Get) if self.return_type().is_none() => { return Err(syn::Error::new( self.signature.span(), "index getter must return a value", )) } // 5a. Index setters must take the subject, "index", and new value as arguments. FnSpecialAccess::Index(Index::Set) if self.arg_count() != 3 => { return Err(syn::Error::new( self.signature.inputs.span(), "index setter requires exactly 3 parameters", )) } // 5b. Non-raw index setters must return nothing. FnSpecialAccess::Index(Index::Set) if params.return_raw.is_none() && self.return_type().is_some() => { return Err(syn::Error::new( self.signature.output.span(), "index setter cannot return any value", )) } _ => (), } self.params = params; Ok(()) } pub fn generate(self) -> TokenStream { let name: syn::Ident = syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span()); let impl_block = self.generate_impl("Token"); let dyn_result_fn_block = self.generate_dynamic_fn(); let vis = self.visibility; quote! { #[automatically_derived] #vis mod #name { use super::*; #[doc(hidden)] pub struct Token(); #impl_block #dyn_result_fn_block } } } pub fn generate_dynamic_fn(&self) -> TokenStream { let name = self.name().clone(); let mut dynamic_signature = self.signature.clone(); dynamic_signature.ident = syn::Ident::new("dynamic_result_fn", Span::call_site()); dynamic_signature.output = syn::parse2::(quote! { -> RhaiResult }) .unwrap(); let arguments: Vec<_> = dynamic_signature .inputs .iter() .filter_map(|fn_arg| match fn_arg { syn::FnArg::Typed(syn::PatType { ref pat, .. }) => match pat.as_ref() { syn::Pat::Ident(ref ident) => Some(ident.ident.clone()), _ => None, }, _ => None, }) .collect(); let return_span = self .return_type() .map(|r| r.span()) .unwrap_or_else(Span::call_site) .resolved_at(Span::call_site()); if self.params.return_raw.is_some() { quote_spanned! { return_span => #[allow(unused)] #[doc(hidden)] #[inline(always)] pub #dynamic_signature { #name(#(#arguments),*).map(Dynamic::from) } } } else { quote_spanned! { return_span => #[allow(unused)] #[doc(hidden)] #[inline(always)] pub #dynamic_signature { Ok(Dynamic::from(#name(#(#arguments),*))) } } } } pub fn generate_impl(&self, on_type_name: &str) -> TokenStream { let sig_name = self.name().clone(); let arg_count = self.arg_count(); let is_method_call = self.mutable_receiver(); let is_pure = !self.mutable_receiver() || self.params().pure.is_some(); let is_volatile = self.params().volatile.is_some(); let pass_context = self.pass_context; let mut unpack_statements = Vec::new(); let mut unpack_exprs = Vec::new(); #[cfg(feature = "metadata")] let mut input_type_names = Vec::new(); let mut input_type_exprs = Vec::new(); let return_type = self .return_type() .map(print_type) .unwrap_or_else(|| "()".to_string()); let skip_first_arg; if self.pass_context { unpack_exprs.push(syn::parse2::(quote! { context.unwrap() }).unwrap()); } // Handle the first argument separately if the function has a "method like" receiver if is_method_call { skip_first_arg = true; let first_arg = self.arg_list().next().unwrap(); let var = syn::Ident::new("arg0", Span::call_site()); match first_arg { syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => { #[cfg(feature = "metadata")] let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty)); let arg_type = match flatten_type_groups(ty.as_ref()) { syn::Type::Reference(syn::TypeReference { ref elem, .. }) => elem.as_ref(), p => p, }; let downcast_span = quote_spanned!(arg_type.span() => &mut args[0usize].write_lock::<#arg_type>().unwrap() ); unpack_statements.push( syn::parse2::(quote! { let #var = #downcast_span; }) .unwrap(), ); #[cfg(feature = "metadata")] input_type_names.push(arg_name); input_type_exprs.push( syn::parse2::(quote_spanned!(arg_type.span() => TypeId::of::<#arg_type>() )) .unwrap(), ); } syn::FnArg::Receiver(..) => todo!("true self parameters not implemented yet"), } unpack_exprs.push(syn::parse2::(quote! { #var }).unwrap()); } else { skip_first_arg = false; } // Handle the rest of the arguments, which all are passed by value. // // The only exception is strings, which need to be downcast to ImmutableString to enable a // zero-copy conversion to &str by reference, or a cloned String. let str_type_path = syn::parse2::(quote! { str }).unwrap(); let string_type_path = syn::parse2::(quote! { String }).unwrap(); for (i, arg) in self.arg_list().enumerate().skip(skip_first_arg as usize) { let var = syn::Ident::new(&format!("arg{i}"), Span::call_site()); let is_string; let is_ref; match arg { syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => { #[cfg(feature = "metadata")] let arg_name = format!("{}: {}", pat.to_token_stream(), print_type(ty)); let arg_type = ty.as_ref(); let downcast_span = match flatten_type_groups(arg_type) { syn::Type::Reference(syn::TypeReference { mutability: None, ref elem, .. }) => match flatten_type_groups(elem.as_ref()) { syn::Type::Path(ref p) if p.path == str_type_path => { is_string = true; is_ref = true; quote_spanned!(arg_type.span().resolved_at(Span::call_site()) => mem::take(args[#i]).into_immutable_string().unwrap() ) } _ => unreachable!("why wasn't this found earlier!?"), }, syn::Type::Path(ref p) if p.path == string_type_path => { is_string = true; is_ref = false; quote_spanned!(arg_type.span().resolved_at(Span::call_site()) => mem::take(args[#i]).into_string().unwrap() ) } _ => { is_string = false; is_ref = false; quote_spanned!(arg_type.span().resolved_at(Span::call_site()) => mem::take(args[#i]).cast::<#arg_type>() ) } }; unpack_statements.push( syn::parse2::(quote! { let #var = #downcast_span; }) .unwrap(), ); #[cfg(feature = "metadata")] input_type_names.push(arg_name); if !is_string { input_type_exprs.push( syn::parse2::(quote_spanned!(arg_type.span() => TypeId::of::<#arg_type>() )) .unwrap(), ); } else { input_type_exprs.push( syn::parse2::(quote_spanned!(arg_type.span() => TypeId::of::() )) .unwrap(), ); } } syn::FnArg::Receiver(..) => unreachable!("how did this happen!?"), } if !is_ref { unpack_exprs.push(syn::parse2::(quote! { #var }).unwrap()); } else { unpack_exprs.push(syn::parse2::(quote! { &#var }).unwrap()); } } // In method calls, the first argument will need to be mutably borrowed. Because Rust marks // that as needing to borrow the entire array, all of the previous argument unpacking via // clone needs to happen first. if is_method_call { let arg0 = unpack_statements.remove(0); unpack_statements.push(arg0); } // Handle "raw returns", aka cases where the result is a dynamic or an error. // // This allows skipping the Dynamic::from wrap. let return_span = self .return_type() .map(|r| r.span()) .unwrap_or_else(Span::call_site) .resolved_at(Span::call_site()); let return_expr = if self.params.return_raw.is_none() { quote_spanned! { return_span => Ok(Dynamic::from(#sig_name(#(#unpack_exprs),*))) } } else { quote_spanned! { return_span => #sig_name(#(#unpack_exprs),*).map(Dynamic::from) } }; let type_name = syn::Ident::new(on_type_name, Span::call_site()); #[cfg(feature = "metadata")] let param_names = quote! { pub const PARAM_NAMES: &'static [&'static str] = &[#(#input_type_names,)* #return_type]; }; #[cfg(not(feature = "metadata"))] let param_names = quote! {}; let cfg_attrs: Vec<_> = self .cfg_attrs() .iter() .map(syn::Attribute::to_token_stream) .collect(); quote! { #(#cfg_attrs)* #[doc(hidden)] impl #type_name { #param_names #[inline(always)] pub fn param_types() -> [TypeId; #arg_count] { [#(#input_type_exprs),*] } } #(#cfg_attrs)* impl PluginFunc for #type_name { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { #(#unpack_statements)* #return_expr } #[inline(always)] fn is_method_call(&self) -> bool { #is_method_call } #[inline(always)] fn is_pure(&self) -> bool { #is_pure } #[inline(always)] fn is_volatile(&self) -> bool { #is_volatile } #[inline(always)] fn has_context(&self) -> bool { #pass_context } } } } } rhai_codegen-2.0.0/src/lib.rs000064400000000000000000000241360072674642500141730ustar 00000000000000//! This crate contains procedural macros to make creating Rhai plugin modules much easier. //! //! # Export an Entire Rust Module to a Rhai `Module` //! //! ``` //! use rhai::{EvalAltResult, FLOAT}; //! use rhai::plugin::*; //! use rhai::module_resolvers::*; //! //! #[export_module] //! mod advanced_math { //! pub const MYSTIC_NUMBER: FLOAT = 42.0; //! //! pub fn euclidean_distance(x1: FLOAT, y1: FLOAT, x2: FLOAT, y2: FLOAT) -> FLOAT { //! ((y2 - y1).abs().powf(2.0) + (x2 -x1).abs().powf(2.0)).sqrt() //! } //! } //! //! # fn main() -> Result<(), Box> { //! let mut engine = Engine::new(); //! let m = exported_module!(advanced_math); //! let mut r = StaticModuleResolver::new(); //! r.insert("Math::Advanced", m); //! engine.set_module_resolver(r); //! //! assert_eq!(engine.eval::( //! r#" //! import "Math::Advanced" as math; //! math::euclidean_distance(0.0, 1.0, 0.0, math::MYSTIC_NUMBER) //! "#)?, 41.0); //! # Ok(()) //! # } //! ``` use quote::quote; use syn::{parse_macro_input, spanned::Spanned, DeriveInput}; mod attrs; mod custom_type; mod function; mod module; mod register; mod rhai_module; #[cfg(test)] mod test; /// Attribute, when put on a Rust module, turns it into a _plugin module_. /// /// # Usage /// /// ``` /// # use rhai::{Engine, Module, EvalAltResult}; /// use rhai::plugin::*; /// /// #[export_module] /// mod my_plugin_module { /// pub fn foo(x: i64) -> i64 { x * 2 } /// pub fn bar() -> i64 { 21 } /// } /// /// # fn main() -> Result<(), Box> { /// let mut engine = Engine::new(); /// /// let module = exported_module!(my_plugin_module); /// /// engine.register_global_module(module.into()); /// /// assert_eq!(engine.eval::("foo(bar())")?, 42); /// # Ok(()) /// # } /// ``` #[proc_macro_attribute] pub fn export_module( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let parsed_params = match crate::attrs::outer_item_attributes(args.into(), "export_module") { Ok(args) => args, Err(err) => return err.to_compile_error().into(), }; let mut module_def = parse_macro_input!(input as module::Module); if let Err(e) = module_def.set_params(parsed_params) { return e.to_compile_error().into(); } let tokens = module_def.generate(); proc_macro::TokenStream::from(tokens) } /// Macro to generate a Rhai `Module` from a _plugin module_ defined via [`#[export_module]`][macro@export_module]. /// /// # Usage /// /// ``` /// # use rhai::{Engine, Module, EvalAltResult}; /// use rhai::plugin::*; /// /// #[export_module] /// mod my_plugin_module { /// pub fn foo(x: i64) -> i64 { x * 2 } /// pub fn bar() -> i64 { 21 } /// } /// /// # fn main() -> Result<(), Box> { /// let mut engine = Engine::new(); /// /// let module = exported_module!(my_plugin_module); /// /// engine.register_global_module(module.into()); /// /// assert_eq!(engine.eval::("foo(bar())")?, 42); /// # Ok(()) /// # } /// ``` #[proc_macro] pub fn exported_module(module_path: proc_macro::TokenStream) -> proc_macro::TokenStream { let module_path = parse_macro_input!(module_path as syn::Path); proc_macro::TokenStream::from(quote::quote! { #module_path::rhai_module_generate() }) } /// Macro to combine a _plugin module_ into an existing module. /// /// Functions and variables in the plugin module overrides any existing similarly-named /// functions and variables in the target module. /// /// This call is intended to be used within the [`def_package!`][crate::def_package] macro to define /// a custom package based on a plugin module. /// /// All sub-modules, if any, in the plugin module are _flattened_ and their functions/variables /// registered at the top level because packages require so. /// /// The text string name in the second parameter can be anything and is reserved for future use; /// it is recommended to be an ID string that uniquely identifies the plugin module. /// /// # Usage /// /// ``` /// # use rhai::{Engine, Module, EvalAltResult}; /// use rhai::plugin::*; /// /// #[export_module] /// mod my_plugin_module { /// pub fn foo(x: i64) -> i64 { x * 2 } /// pub fn bar() -> i64 { 21 } /// } /// /// # fn main() -> Result<(), Box> { /// let mut engine = Engine::new(); /// /// let mut module = Module::new(); /// combine_with_exported_module!(&mut module, "my_plugin_module_ID", my_plugin_module); /// /// engine.register_global_module(module.into()); /// /// assert_eq!(engine.eval::("foo(bar())")?, 42); /// # Ok(()) /// # } /// ``` #[proc_macro] pub fn combine_with_exported_module(args: proc_macro::TokenStream) -> proc_macro::TokenStream { match crate::register::parse_register_macro(args) { Ok((module_expr, _export_name, module_path)) => proc_macro::TokenStream::from(quote! { #module_path::rhai_generate_into_module(#module_expr, true) }), Err(e) => e.to_compile_error().into(), } } /// Attribute, when put on a Rust function, turns it into a _plugin function_. /// /// # Deprecated /// /// This macro is deprecated as it performs no additional value. /// /// This method will be removed in the next major version. #[deprecated(since = "1.18.0")] #[proc_macro_attribute] pub fn export_fn( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let mut output = quote! { #[allow(clippy::needless_pass_by_value)] }; output.extend(proc_macro2::TokenStream::from(input.clone())); let parsed_params = match crate::attrs::outer_item_attributes(args.into(), "export_fn") { Ok(args) => args, Err(err) => return err.to_compile_error().into(), }; let mut function_def = parse_macro_input!(input as function::ExportedFn); if !function_def.cfg_attrs().is_empty() { return syn::Error::new( function_def.cfg_attrs()[0].span(), "`cfg` attributes are not allowed for `export_fn`", ) .to_compile_error() .into(); } if let Err(e) = function_def.set_params(parsed_params) { return e.to_compile_error().into(); } output.extend(function_def.generate()); proc_macro::TokenStream::from(output) } /// Macro to register a _plugin function_ (defined via [`#[export_fn]`][macro@export_fn]) into an `Engine`. /// /// # Deprecated /// /// This macro is deprecated as it performs no additional value. /// /// This method will be removed in the next major version. #[deprecated(since = "1.18.0")] #[proc_macro] pub fn register_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { match crate::register::parse_register_macro(args) { Ok((engine_expr, export_name, rust_mod_path)) => { let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); proc_macro::TokenStream::from(quote! { #engine_expr.register_fn(#export_name, #gen_mod_path::dynamic_result_fn) }) } Err(e) => e.to_compile_error().into(), } } /// Macro to register a _plugin function_ into a Rhai `Module`. /// /// # Deprecated /// /// This macro is deprecated as it performs no additional value. /// /// This method will be removed in the next major version. #[deprecated(since = "1.18.0")] #[proc_macro] pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { match crate::register::parse_register_macro(args) { Ok((module_expr, export_name, rust_mod_path)) => { let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); let mut tokens = quote! { let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Internal) }; #[cfg(feature = "metadata")] tokens.extend(quote! { .with_params_info(#gen_mod_path::Token::PARAM_NAMES) }); tokens.extend(quote! { ; #module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into()); }); tokens.into() } Err(e) => e.to_compile_error().into(), } } /// Macro to register a _plugin function_ into a Rhai `Module` and expose it globally. /// /// # Deprecated /// /// This macro is deprecated as it performs no additional value. /// /// This method will be removed in the next major version. #[deprecated(since = "1.18.0")] #[proc_macro] pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream { match crate::register::parse_register_macro(args) { Ok((module_expr, export_name, rust_mod_path)) => { let gen_mod_path = crate::register::generated_module_path(&rust_mod_path); let mut tokens = quote! { let fx = FuncRegistration::new(#export_name).with_namespace(FnNamespace::Global) }; #[cfg(feature = "metadata")] tokens.extend(quote! { .with_params_info(#gen_mod_path::Token::PARAM_NAMES) }); tokens.extend(quote! { ; #module_expr.set_fn_raw_with_options(fx, &#gen_mod_path::Token::param_types(), #gen_mod_path::Token().into()); }); tokens.into() } Err(e) => e.to_compile_error().into(), } } /// Macro to implement the [`CustomType`][rhai::CustomType] trait. /// /// # Usage /// /// ``` /// use rhai::{CustomType, TypeBuilder}; /// /// #[derive(Clone, CustomType)] /// struct MyType { /// foo: i64, /// bar: bool, /// baz: String /// } /// ``` #[proc_macro_derive(CustomType, attributes(rhai_type,))] pub fn derive_custom_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); let expanded = custom_type::derive_custom_type_impl(input); expanded.into() } rhai_codegen-2.0.0/src/module.rs000064400000000000000000000273230072674642500147130ustar 00000000000000use quote::{quote, ToTokens}; use syn::{parse::Parse, parse::ParseStream}; #[cfg(no_std)] use core::mem; #[cfg(not(no_std))] use std::mem; use std::borrow::Cow; use crate::attrs::{AttrItem, ExportInfo, ExportScope, ExportedParams}; use crate::function::ExportedFn; use crate::rhai_module::{ExportedConst, ExportedType}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] pub struct ExportedModParams { pub name: String, skip: bool, pub scope: ExportScope, } impl Parse for ExportedModParams { fn parse(args: ParseStream) -> syn::Result { if args.is_empty() { return Ok(<_>::default()); } Self::from_info(crate::attrs::parse_attr_items(args)?) } } impl ExportedParams for ExportedModParams { fn parse_stream(args: ParseStream) -> syn::Result { Self::parse(args) } fn no_attrs() -> Self { Self::default() } fn from_info(info: ExportInfo) -> syn::Result { let ExportInfo { items: attrs, .. } = info; let mut name = String::new(); let mut skip = false; let mut scope = None; for attr in attrs { let AttrItem { key, value, .. } = attr; match (key.to_string().as_ref(), value) { ("name", Some(s)) => { let new_name = s.value(); if name == new_name { return Err(syn::Error::new(key.span(), "conflicting name")); } name = new_name; } ("name", None) => return Err(syn::Error::new(key.span(), "requires value")), ("skip", None) => skip = true, ("skip", Some(s)) => return Err(syn::Error::new(s.span(), "extraneous value")), ("export_prefix", Some(_)) | ("export_all", None) if scope.is_some() => { return Err(syn::Error::new(key.span(), "duplicate export scope")); } ("export_prefix", Some(s)) => scope = Some(ExportScope::Prefix(s.value())), ("export_prefix", None) => { return Err(syn::Error::new(key.span(), "requires value")) } ("export_all", None) => scope = Some(ExportScope::All), ("export_all", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) } (attr, ..) => { return Err(syn::Error::new( key.span(), format!("unknown attribute '{attr}'"), )) } } } let scope = scope.unwrap_or_default(); Ok(ExportedModParams { name, skip, scope }) } } #[derive(Debug)] pub struct Module { mod_all: syn::ItemMod, consts: Vec, custom_types: Vec, fns: Vec, sub_modules: Vec, params: ExportedModParams, } impl Module { pub fn set_params(&mut self, params: ExportedModParams) -> syn::Result<()> { self.params = params; Ok(()) } } impl Parse for Module { fn parse(input: ParseStream) -> syn::Result { let mut mod_all: syn::ItemMod = input.parse()?; let fns: Vec<_>; let mut consts = Vec::new(); let mut custom_types = Vec::new(); let mut sub_modules = Vec::new(); if let Some((.., ref mut content)) = mod_all.content { // Gather and parse functions. fns = content .iter_mut() .filter_map(|item| match item { syn::Item::Fn(f) => Some(f), _ => None, }) .try_fold(Vec::new(), |mut vec, item_fn| -> syn::Result<_> { let params = crate::attrs::inner_item_attributes(&mut item_fn.attrs, "rhai_fn")?; let f = syn::parse2(item_fn.to_token_stream()).and_then(|mut f: ExportedFn| { f.set_params(params)?; f.set_cfg_attrs(crate::attrs::collect_cfg_attr(&item_fn.attrs)); #[cfg(feature = "metadata")] f.set_comments(crate::attrs::doc_attributes(&item_fn.attrs)?); Ok(f) })?; vec.push(f); Ok(vec) })?; // Gather and parse constants definitions. for item in &*content { if let syn::Item::Const(syn::ItemConst { vis: syn::Visibility::Public(..), ref expr, ident, attrs, ty, .. }) = item { consts.push(ExportedConst { name: ident.to_string(), typ: ty.clone(), expr: expr.as_ref().clone(), cfg_attrs: crate::attrs::collect_cfg_attr(attrs), }) } } // Gather and parse type definitions. for item in &*content { if let syn::Item::Type(syn::ItemType { vis: syn::Visibility::Public(..), ident, attrs, ty, .. }) = item { custom_types.push(ExportedType { name: ident.to_string(), typ: ty.clone(), cfg_attrs: crate::attrs::collect_cfg_attr(attrs), #[cfg(feature = "metadata")] comments: crate::attrs::doc_attributes(attrs)?, }) } } // Gather and parse sub-module definitions. // // They are actually removed from the module's body, because they will need // re-generating later when generated code is added. sub_modules.reserve(content.len() - fns.len() - consts.len()); let mut i = 0; while i < content.len() { match content[i] { syn::Item::Mod(..) => { let mut item_mod = match content.remove(i) { syn::Item::Mod(m) => m, _ => unreachable!(), }; let params: ExportedModParams = crate::attrs::inner_item_attributes(&mut item_mod.attrs, "rhai_mod")?; let module = syn::parse2::(item_mod.to_token_stream()).and_then( |mut m| { m.set_params(params)?; Ok(m) }, )?; sub_modules.push(module); } _ => i += 1, } } } else { fns = Vec::new(); } Ok(Module { mod_all, fns, consts, custom_types, sub_modules, params: <_>::default(), }) } } impl Module { pub fn attrs(&self) -> &[syn::Attribute] { &self.mod_all.attrs } pub fn module_name(&self) -> &syn::Ident { &self.mod_all.ident } pub fn exported_name(&self) -> Cow { if !self.params.name.is_empty() { (&self.params.name).into() } else { self.module_name().to_string().into() } } pub fn update_scope(&mut self, parent_scope: &ExportScope) { let keep = match (self.params.skip, parent_scope) { (true, ..) => false, (.., ExportScope::PubOnly) => matches!(self.mod_all.vis, syn::Visibility::Public(..)), (.., ExportScope::Prefix(s)) => self.mod_all.ident.to_string().starts_with(s), (.., ExportScope::All) => true, }; self.params.skip = !keep; } pub fn skipped(&self) -> bool { self.params.skip } pub fn generate(self) -> proc_macro2::TokenStream { match self.generate_inner() { Ok(tokens) => tokens, Err(e) => e.to_compile_error(), } } fn generate_inner(self) -> Result { // Check for collisions if the "name" attribute was used on inner functions. crate::rhai_module::check_rename_collisions(&self.fns)?; // Extract the current structure of the module. let Module { mut mod_all, mut fns, consts, custom_types, mut sub_modules, params, .. } = self; let mod_vis = mod_all.vis; let mod_name = mod_all.ident.clone(); let (.., orig_content) = mod_all.content.take().unwrap(); let mod_attrs = mem::take(&mut mod_all.attrs); #[cfg(feature = "metadata")] let mod_doc = crate::attrs::doc_attributes(&mod_attrs)?.join("\n"); #[cfg(not(feature = "metadata"))] let mod_doc = String::new(); if !params.skip { // Generate new module items. // // This is done before inner module recursive generation, because that is destructive. let mod_gen = crate::rhai_module::generate_body( &mod_doc, &mut fns, &consts, &custom_types, &mut sub_modules, ¶ms.scope, ); // NB: sub-modules must have their new items for exporting generated in depth-first order // to avoid issues caused by re-parsing them let inner_modules = sub_modules .into_iter() .try_fold::<_, _, Result<_, syn::Error>>(Vec::new(), |mut acc, m| { acc.push(m.generate_inner()?); Ok(acc) })?; // Regenerate the module with the new content added. Ok(quote! { #(#mod_attrs)* #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] #mod_vis mod #mod_name { #(#orig_content)* #(#inner_modules)* #mod_gen } }) } else { // Regenerate the original module as-is. Ok(quote! { #(#mod_attrs)* #mod_vis mod #mod_name { #(#orig_content)* } }) } } #[allow(dead_code)] pub fn name(&self) -> &syn::Ident { &self.mod_all.ident } #[allow(dead_code)] pub fn consts(&self) -> &[ExportedConst] { &self.consts } #[allow(dead_code)] pub fn custom_types(&self) -> &[ExportedType] { &self.custom_types } #[allow(dead_code)] pub fn fns(&self) -> &[ExportedFn] { &self.fns } #[allow(dead_code)] pub fn sub_modules(&self) -> &[Module] { &self.sub_modules } #[allow(dead_code)] pub fn content(&self) -> Option<&[syn::Item]> { match self.mod_all { syn::ItemMod { content: Some((.., ref vec)), .. } => Some(vec), _ => None, } } } rhai_codegen-2.0.0/src/register.rs000064400000000000000000000031440072674642500152450ustar 00000000000000use quote::{quote, quote_spanned}; use syn::{parse::Parser, spanned::Spanned}; pub fn generated_module_path( fn_path: &syn::Path, ) -> syn::punctuated::Punctuated { let mut g = fn_path.clone().segments; g.pop(); let ident = syn::Ident::new( &format!("rhai_fn_{}", fn_path.segments.last().unwrap().ident), fn_path.span(), ); g.push_value(syn::PathSegment { ident, arguments: syn::PathArguments::None, }); g } type RegisterMacroInput = (syn::Expr, proc_macro2::TokenStream, syn::Path); pub fn parse_register_macro( args: proc_macro::TokenStream, ) -> Result { let args = syn::punctuated::Punctuated::<_, syn::Token![,]>::parse_separated_nonempty .parse(args) .unwrap(); let arg_span = args.span(); let mut items: Vec<_> = args.into_iter().collect(); if items.len() != 3 { return Err(syn::Error::new( arg_span, "this macro requires three arguments", )); } let export_name = match &items[1] { syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => #lit_str), expr => quote! { #expr }, }; let rust_mod_path = match &items[2] { syn::Expr::Path(ref path) => path.path.clone(), _ => { return Err(syn::Error::new( items[2].span(), "third argument must be a function name", )) } }; let module = items.remove(0); Ok((module, export_name, rust_mod_path)) } rhai_codegen-2.0.0/src/rhai_module.rs000064400000000000000000000251040072674642500157110ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use std::collections::BTreeMap; use crate::attrs::ExportScope; use crate::function::{ print_type, ExportedFn, FnNamespaceAccess, FnSpecialAccess, FN_GET, FN_IDX_GET, FN_IDX_SET, FN_SET, }; use crate::module::Module; #[derive(Debug)] pub struct ExportedConst { pub name: String, pub typ: Box, pub expr: syn::Expr, pub cfg_attrs: Vec, } #[derive(Debug)] pub struct ExportedType { pub name: String, pub typ: Box, pub cfg_attrs: Vec, #[cfg(feature = "metadata")] pub comments: Vec, } pub fn generate_body( doc: &str, fns: &mut [ExportedFn], consts: &[ExportedConst], custom_types: &[ExportedType], sub_modules: &mut [Module], parent_scope: &ExportScope, ) -> TokenStream { let mut set_fn_statements = Vec::new(); let mut set_const_statements = Vec::new(); let mut add_mod_blocks = Vec::new(); let mut set_flattened_mod_blocks = Vec::new(); for ExportedConst { name: const_name, cfg_attrs, .. } in consts { let const_literal = syn::LitStr::new(const_name, Span::call_site()); let const_ref = syn::Ident::new(const_name, Span::call_site()); let cfg_attrs: Vec<_> = cfg_attrs .iter() .map(syn::Attribute::to_token_stream) .collect(); set_const_statements.push(quote! { #(#cfg_attrs)* _m.set_var(#const_literal, #const_ref); }); } for ExportedType { name, typ, cfg_attrs, #[cfg(feature = "metadata")] comments, .. } in custom_types { let const_literal = syn::LitStr::new(name, Span::call_site()); let cfg_attrs: Vec<_> = cfg_attrs .iter() .map(syn::Attribute::to_token_stream) .collect(); #[cfg(feature = "metadata")] let comments = comments .iter() .map(|s| syn::LitStr::new(s, Span::call_site())) .collect::>(); #[cfg(not(feature = "metadata"))] let comments = Vec::::new(); set_const_statements.push(if comments.is_empty() { quote! { #(#cfg_attrs)* _m.set_custom_type::<#typ>(#const_literal); } } else { quote! { #(#cfg_attrs)* _m.set_custom_type_with_comments::<#typ>(#const_literal, &[#(#comments),*]); } }); } for item_mod in sub_modules { item_mod.update_scope(parent_scope); if item_mod.skipped() { continue; } let module_name = item_mod.module_name(); let exported_name = syn::LitStr::new(item_mod.exported_name().as_ref(), Span::call_site()); let cfg_attrs = crate::attrs::collect_cfg_attr(item_mod.attrs()); add_mod_blocks.push(quote! { #(#cfg_attrs)* _m.set_sub_module(#exported_name, self::#module_name::rhai_module_generate()); }); set_flattened_mod_blocks.push(quote! { #(#cfg_attrs)* self::#module_name::rhai_generate_into_module(_m, _flatten); }); } // NB: these are token streams, because re-parsing messes up "> >" vs ">>" let mut gen_fn_tokens = Vec::new(); for function in fns { function.update_scope(parent_scope); if function.skipped() { continue; } let fn_token_name = syn::Ident::new( &format!("{}_token", function.name()), function.name().span(), ); let reg_names = function.exported_names(); let cfg_attrs: Vec<_> = function .cfg_attrs() .iter() .map(syn::Attribute::to_token_stream) .collect(); for fn_literal in reg_names { let mut namespace = FnNamespaceAccess::Internal; match function.params().special { FnSpecialAccess::None => (), FnSpecialAccess::Index(..) | FnSpecialAccess::Property(..) => { let reg_name = fn_literal.value(); if reg_name.starts_with(FN_GET) || reg_name.starts_with(FN_SET) || reg_name == FN_IDX_GET || reg_name == FN_IDX_SET { namespace = FnNamespaceAccess::Global; } } } match function.params().namespace { FnNamespaceAccess::Unset => (), ns => namespace = ns, } let mut tokens = quote! { #(#cfg_attrs)* FuncRegistration::new(#fn_literal) }; match namespace { FnNamespaceAccess::Unset => unreachable!("`namespace` should be set"), FnNamespaceAccess::Global => { tokens.extend(quote! { .with_namespace(FnNamespace::Global) }) } FnNamespaceAccess::Internal => (), } #[cfg(feature = "metadata")] { tokens.extend(quote! { .with_params_info(#fn_token_name::PARAM_NAMES) }); let comments = function .comments() .iter() .map(|s| syn::LitStr::new(s, Span::call_site())) .collect::>(); if !comments.is_empty() { tokens.extend(quote! { .with_comments(&[#(#comments),*]) }); } } tokens.extend(quote! { .set_into_module_raw(_m, &#fn_token_name::param_types(), #fn_token_name().into()); }); set_fn_statements.push(syn::parse2::(tokens).unwrap()); } gen_fn_tokens.push(quote! { #(#cfg_attrs)* #[allow(non_camel_case_types)] #[doc(hidden)] pub struct #fn_token_name(); }); gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string())); } let module_docs = if doc.is_empty() { quote! {} } else { quote! { m.set_doc(#doc); } }; let flatten = if set_flattened_mod_blocks.is_empty() && add_mod_blocks.is_empty() { quote! {} } else { quote! { if _flatten { #(#set_flattened_mod_blocks)* } else { #(#add_mod_blocks)* } } }; let mut generate_fn_call = syn::parse2::(quote! { pub mod generate_info { #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); #module_docs rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { #(#set_fn_statements)* #(#set_const_statements)* #flatten } } }) .unwrap(); let (.., generate_call_content) = generate_fn_call.content.take().unwrap(); quote! { #(#generate_call_content)* #(#gen_fn_tokens)* } } pub fn check_rename_collisions(fns: &[ExportedFn]) -> Result<(), syn::Error> { fn make_key(name: impl ToString, item_fn: &ExportedFn) -> String { item_fn .arg_list() .fold(name.to_string(), |mut arg_str, fn_arg| { let type_string: String = match fn_arg { syn::FnArg::Receiver(..) => unimplemented!("receiver rhai_fns not implemented"), syn::FnArg::Typed(syn::PatType { ref ty, .. }) => print_type(ty), }; arg_str += "."; arg_str += &type_string; arg_str }) } let mut renames = BTreeMap::new(); let mut fn_defs = BTreeMap::new(); for item_fn in fns { if !item_fn.params().name.is_empty() || item_fn.params().special != FnSpecialAccess::None { let mut names: Vec<_> = item_fn .params() .name .iter() .map(|n| (n.clone(), n.clone())) .collect(); if let Some((s, n, ..)) = item_fn.params().special.get_fn_name() { names.push((s, n)); } for (name, fn_name) in names { let current_span = item_fn.params().span.unwrap(); let key = make_key(name, item_fn); if let Some(other_span) = renames.insert(key, current_span) { let mut err = syn::Error::new( current_span, format!("duplicate Rhai signature for '{fn_name}'"), ); err.combine(syn::Error::new( other_span, format!("duplicated function renamed '{fn_name}'"), )); return Err(err); } } } else { let ident = item_fn.name(); if let Some(other_span) = fn_defs.insert(ident.to_string(), ident.span()) { let mut err = syn::Error::new(ident.span(), format!("duplicate function '{ident}'")); err.combine(syn::Error::new( other_span, format!("duplicated function '{ident}'"), )); return Err(err); } let key = make_key(ident, item_fn); if let Some(fn_span) = renames.get(&key) { let mut err = syn::Error::new( ident.span(), format!("duplicate Rhai signature for '{ident}'"), ); err.combine(syn::Error::new( *fn_span, format!("duplicated function '{ident}'"), )); return Err(err); } } } Ok(()) } rhai_codegen-2.0.0/src/test/custom_type.rs000064400000000000000000000056770072674642500167700ustar 00000000000000#[cfg(test)] mod custom_type_tests { use crate::test::assert_streams_eq; use quote::quote; #[test] fn test_custom_type_tuple_struct() { let input = quote! { #[derive(Clone, CustomType)] pub struct Bar( #[rhai_type(skip)] #[cfg(not(feature = "no_float"))] rhai::FLOAT, INT, #[rhai_type(name = "boo", readonly)] String, Vec ); }; let result = crate::custom_type::derive_custom_type_impl( syn::parse2::(input).unwrap(), ); let expected = quote! { impl CustomType for Bar { fn build(mut builder: TypeBuilder) { builder.with_name(stringify!(Bar)); builder.with_get_set("field1", |obj: &mut Self| obj.1.clone(), |obj: &mut Self, val| obj.1 = val ); builder.with_get("boo", |obj: &mut Self| obj.2.clone()); builder.with_get_set("field3", |obj: &mut Self| obj.3.clone(), |obj: &mut Self, val| obj.3 = val ); } } }; assert_streams_eq(result, expected); } #[test] fn test_custom_type_struct() { let input = quote! { #[derive(CustomType)] #[rhai_type(skip, name = "MyFoo", extra = Self::build_extra)] pub struct Foo { #[cfg(not(feature = "no_float"))] #[rhai_type(skip)] _dummy: rhai::FLOAT, #[rhai_type(get = get_bar)] pub bar: INT, #[rhai_type(name = "boo", readonly)] pub(crate) baz: String, #[rhai_type(set = Self::set_qux)] pub qux: Vec } }; let result = crate::custom_type::derive_custom_type_impl( syn::parse2::(input).unwrap(), ); let expected = quote! { impl CustomType for Foo { fn build(mut builder: TypeBuilder) { builder.with_name("MyFoo"); builder.with_get_set(stringify!(bar), |obj: &mut Self| get_bar(&*obj), |obj: &mut Self, val| obj.bar = val ); builder.with_get("boo", |obj: &mut Self| obj.baz.clone()); builder.with_get_set(stringify!(qux), |obj: &mut Self| obj.qux.clone(), Self::set_qux ); Self::build_extra(&mut builder); } } }; assert_streams_eq(result, expected); } } rhai_codegen-2.0.0/src/test/function.rs000064400000000000000000000543360072674642500162360ustar 00000000000000#[cfg(test)] mod function_tests { use crate::function::ExportedFn; use proc_macro2::TokenStream; use quote::quote; #[test] fn minimal_fn() { let input_tokens: TokenStream = quote! { pub fn do_nothing() { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "do_nothing"); assert!(!item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!(item_fn.arg_list().count(), 0); } #[test] fn one_arg_fn() { let input_tokens: TokenStream = quote! { pub fn do_something(x: usize) { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "do_something"); assert_eq!(item_fn.arg_list().count(), 1); assert!(!item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!( item_fn.arg_list().next().unwrap(), &syn::parse2::(quote! { x: usize }).unwrap() ); } #[test] fn two_arg_fn() { let input_tokens: TokenStream = quote! { pub fn do_something(x: usize, y: f32) { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "do_something"); assert_eq!(item_fn.arg_list().count(), 2); assert!(!item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!( item_fn.arg_list().next().unwrap(), &syn::parse2::(quote! { x: usize }).unwrap() ); assert_eq!( item_fn.arg_list().nth(1).unwrap(), &syn::parse2::(quote! { y: f32 }).unwrap() ); } #[test] fn usize_returning_fn() { let input_tokens: TokenStream = quote! { pub fn get_magic_number() -> usize { 42 } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "get_magic_number"); assert!(!item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert_eq!(item_fn.arg_list().count(), 0); assert_eq!( item_fn.return_type().unwrap(), &syn::Type::Path(syn::TypePath { qself: None, path: syn::parse2::(quote! { usize }).unwrap() }) ); } #[test] fn ref_returning_fn() { let input_tokens: TokenStream = quote! { pub fn get_magic_phrase() -> &'static str { "open sesame" } }; let err = syn::parse2::(input_tokens).unwrap_err(); assert_eq!(format!("{err}"), "Rhai functions cannot return references"); } #[test] fn ptr_returning_fn() { let input_tokens: TokenStream = quote! { pub fn get_magic_phrase() -> *const str { "open sesame" } }; let err = syn::parse2::(input_tokens).unwrap_err(); assert_eq!(format!("{err}"), "Rhai functions cannot return pointers"); } #[test] fn ref_arg_fn() { let input_tokens: TokenStream = quote! { pub fn greet(who: &Person) { } }; let err = syn::parse2::(input_tokens).unwrap_err(); assert_eq!( format!("{err}"), "references from Rhai in this position must be mutable" ); } #[test] fn ref_second_arg_fn() { let input_tokens: TokenStream = quote! { pub fn greet(count: usize, who: &Person) { } }; let err = syn::parse2::(input_tokens).unwrap_err(); assert_eq!( format!("{err}"), "function parameters other than the first one cannot be passed by reference" ); } #[test] fn mut_ref_second_arg_fn() { let input_tokens: TokenStream = quote! { pub fn give(item_name: &str, who: &mut Person) { } }; let err = syn::parse2::(input_tokens).unwrap_err(); assert_eq!( format!("{err}"), "function parameters other than the first one cannot be passed by reference" ); } #[test] fn str_arg_fn() { let input_tokens: TokenStream = quote! { pub fn log(message: &str) { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "log"); assert_eq!(item_fn.arg_list().count(), 1); assert!(!item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!( item_fn.arg_list().next().unwrap(), &syn::parse2::(quote! { message: &str }).unwrap() ); } #[test] fn str_second_arg_fn() { let input_tokens: TokenStream = quote! { pub fn log(level: usize, message: &str) { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "log"); assert_eq!(item_fn.arg_list().count(), 2); assert!(!item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!( item_fn.arg_list().next().unwrap(), &syn::parse2::(quote! { level: usize }).unwrap() ); assert_eq!( item_fn.arg_list().nth(1).unwrap(), &syn::parse2::(quote! { message: &str }).unwrap() ); } #[test] fn private_fn() { let input_tokens: TokenStream = quote! { fn do_nothing() { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "do_nothing"); assert!(!item_fn.mutable_receiver()); assert!(!item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!(item_fn.arg_list().count(), 0); } #[test] fn receiver_fn() { let input_tokens: TokenStream = quote! { pub fn act_upon(&mut self) { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "act_upon"); assert!(item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!(item_fn.arg_list().count(), 1); } #[test] fn immutable_receiver_fn() { let input_tokens: TokenStream = quote! { pub fn act_upon(&self) { } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_eq!(&item_fn.name().to_string(), "act_upon"); assert!(item_fn.mutable_receiver()); assert!(item_fn.is_public()); assert!(item_fn.return_type().is_none()); assert_eq!(item_fn.arg_list().count(), 1); } } #[cfg(test)] mod generate_tests { use crate::function::ExportedFn; use proc_macro2::TokenStream; use quote::quote; fn assert_streams_eq(actual: TokenStream, expected: TokenStream) { let actual = actual.to_string(); let expected = expected.to_string(); if actual != expected { let mut counter = 0; let _iter = actual.chars().zip(expected.chars()).skip_while(|(a, e)| { if *a == *e { counter += 1; true } else { false } }); let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { actual_diff.push(a); expected_diff.push(e); } (actual_diff, expected_diff) }; eprintln!("actual != expected, diverge at char {counter}"); // eprintln!(" actual: {}", _actual_diff); // eprintln!("expected: {}", _expected_diff); // assert!(false); } assert_eq!(actual, expected); } #[test] fn minimal_fn() { let input_tokens: TokenStream = quote! { pub fn do_nothing() { } }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_do_nothing { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["()"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(do_nothing())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn() -> RhaiResult { Ok(Dynamic::from(do_nothing())) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_fn.generate(), expected_tokens); } #[test] fn one_arg_usize_fn() { let input_tokens: TokenStream = quote! { pub fn do_something(x: usize) { } }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_do_something { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(do_something(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn(x: usize) -> RhaiResult { Ok(Dynamic::from(do_something(x))) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_fn.generate(), expected_tokens); } #[test] fn one_arg_fn_with_context() { let input_tokens: TokenStream = quote! { pub fn do_something(context: NativeCallContext, x: usize) {} }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_do_something { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(do_something(context.unwrap(), arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { true } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> RhaiResult { Ok(Dynamic::from(do_something(context, x))) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert!(item_fn.pass_context()); assert_streams_eq(item_fn.generate(), expected_tokens); } #[test] fn return_dynamic() { let input_tokens: TokenStream = quote! { pub fn return_dynamic() -> (((rhai::Dynamic))) { ().into() } }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_return_dynamic { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["rhai::Dynamic"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(return_dynamic())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn() -> RhaiResult { Ok(Dynamic::from(return_dynamic())) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_fn.generate(), expected_tokens); } #[test] fn one_arg_usize_fn_impl() { let input_tokens: TokenStream = quote! { pub fn do_something(x: usize) { } }; let expected_tokens = quote! { #[doc(hidden)] impl TestStruct { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for TestStruct { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(do_something(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_fn.generate_impl("TestStruct"), expected_tokens); } #[test] fn two_arg_returning_usize_fn() { let input_tokens: TokenStream = quote! { pub fn add_together(x: usize, y: usize) -> usize { x + y } }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_add_together { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["x: usize", "y: usize", "usize"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_together(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn(x: usize, y: usize) -> RhaiResult { Ok(Dynamic::from(add_together(x, y))) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_fn.generate(), expected_tokens); } #[test] fn mut_arg_usize_fn() { let input_tokens: TokenStream = quote! { pub fn increment(x: &mut usize, y: usize) { *x += y; } }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_increment { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut usize", "y: usize", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn(x: &mut usize, y: usize) -> RhaiResult { Ok(Dynamic::from(increment(x, y))) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert!(item_fn.mutable_receiver()); assert_streams_eq(item_fn.generate(), expected_tokens); } #[test] fn str_arg_fn() { let input_tokens: TokenStream = quote! { pub fn special_print(message: &str) { eprintln!("----{}----", message); } }; let expected_tokens = quote! { #[automatically_derived] pub mod rhai_fn_special_print { use super::*; #[doc(hidden)] pub struct Token(); #[doc(hidden)] impl Token { pub const PARAM_NAMES: &'static [&'static str] = &["message: &str", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for Token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap(); Ok(Dynamic::from(special_print(&arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(unused)] #[doc(hidden)] #[inline(always)] pub fn dynamic_result_fn(message: &str) -> RhaiResult { Ok(Dynamic::from(special_print(message))) } } }; let item_fn = syn::parse2::(input_tokens).unwrap(); assert!(!item_fn.mutable_receiver()); assert_streams_eq(item_fn.generate(), expected_tokens); } } rhai_codegen-2.0.0/src/test/mod.rs000064400000000000000000000021340072674642500151550ustar 00000000000000use proc_macro2::TokenStream; mod custom_type; mod function; mod module; pub fn assert_streams_eq(actual: TokenStream, expected: TokenStream) { let actual = actual.to_string(); let expected = expected.to_string(); if actual != expected { let mut counter = 0; let _iter = actual.chars().zip(expected.chars()).skip_while(|(a, e)| { if *a == *e { counter += 1; true } else { false } }); let (_actual_diff, _expected_diff) = { let mut actual_diff = String::new(); let mut expected_diff = String::new(); for (a, e) in _iter.take(50) { actual_diff.push(a); expected_diff.push(e); } (actual_diff, expected_diff) }; eprintln!("actual != expected, diverge at char {counter}"); // eprintln!(" actual: {}", _actual_diff); // eprintln!("expected: {}", _expected_diff); // assert!(false); } assert_eq!(actual, expected); } rhai_codegen-2.0.0/src/test/module.rs000064400000000000000000003227010072674642500156700ustar 00000000000000#[cfg(test)] mod module_tests { use crate::module::Module; use proc_macro2::TokenStream; use quote::quote; #[test] fn empty_module() { let input_tokens: TokenStream = quote! { pub mod empty { } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.fns().is_empty()); assert!(item_mod.consts().is_empty()); } #[test] fn one_factory_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn get_mystic_number() -> INT { 42 } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.fns().len(), 1); assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number"); assert_eq!(item_mod.fns()[0].arg_count(), 0); assert_eq!( item_mod.fns()[0].return_type().unwrap(), &syn::parse2::(quote! { INT }).unwrap() ); } #[test] fn one_factory_fn_with_custom_type_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub type Hello = (); /// We are the world! pub type World = String; pub fn get_mystic_number() -> INT { 42 } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.custom_types().len(), 2); assert_eq!(item_mod.custom_types()[0].name.to_string(), "Hello"); assert_eq!(item_mod.custom_types()[1].name.to_string(), "World"); #[cfg(feature = "metadata")] assert_eq!( item_mod.custom_types()[1].comments[0], "/// We are the world!" ); assert_eq!(item_mod.fns().len(), 1); assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number"); assert_eq!(item_mod.fns()[0].arg_count(), 0); assert_eq!( item_mod.fns()[0].return_type().unwrap(), &syn::parse2::(quote! { INT }).unwrap() ); } #[test] #[cfg(feature = "metadata")] fn one_factory_fn_with_comments_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { /// This is a doc-comment. /// Another line. /** block doc-comment */ // Regular comment /// Final line. /** doc-comment in multiple lines */ pub fn get_mystic_number() -> INT { 42 } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.fns().len(), 1); assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number"); assert_eq!( item_mod.fns()[0].comments().to_vec(), vec![ "\ /// This is a doc-comment.\n\ /// Another line.\n\ /// block doc-comment \n\ /// Final line.", "/** doc-comment\n in multiple lines\n */" ] ); assert_eq!(item_mod.fns()[0].arg_count(), 0); assert_eq!( item_mod.fns()[0].return_type().unwrap(), &syn::parse2::(quote! { INT }).unwrap() ); } #[test] fn one_single_arg_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn add_one_to(x: INT) -> INT { x + 1 } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.fns().len(), 1); assert_eq!(item_mod.fns()[0].name().to_string(), "add_one_to"); assert_eq!(item_mod.fns()[0].arg_count(), 1); assert_eq!( item_mod.fns()[0].arg_list().next().unwrap(), &syn::parse2::(quote! { x: INT }).unwrap() ); assert_eq!( item_mod.fns()[0].return_type().unwrap(), &syn::parse2::(quote! { INT }).unwrap() ); } #[test] fn one_double_arg_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn add_together(x: INT, y: INT) -> INT { x + y } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); let mut args = item_mod.fns()[0].arg_list(); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.fns().len(), 1); assert_eq!(item_mod.fns()[0].name().to_string(), "add_together"); assert_eq!(item_mod.fns()[0].arg_count(), 2); assert_eq!( args.next().unwrap(), &syn::parse2::(quote! { x: INT }).unwrap() ); assert_eq!( args.next().unwrap(), &syn::parse2::(quote! { y: INT }).unwrap() ); assert!(args.next().is_none()); assert_eq!( item_mod.fns()[0].return_type().unwrap(), &syn::parse2::(quote! { INT }).unwrap() ); } #[test] fn one_constant_nested_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { pub mod it_is { pub const MYSTIC_NUMBER: INT = 42; } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.fns().is_empty()); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.sub_modules().len(), 1); assert_eq!(&item_mod.sub_modules()[0].consts()[0].name, "MYSTIC_NUMBER"); assert_eq!( item_mod.sub_modules()[0].consts()[0].expr, syn::parse2::(quote! { 42 }).unwrap() ); } #[test] fn one_skipped_fn_nested_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub mod skip_this { #[rhai_fn(skip)] pub fn get_mystic_number() -> INT { 42 } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.fns().is_empty()); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.sub_modules().len(), 1); assert_eq!(item_mod.sub_modules()[0].fns().len(), 1); assert!(item_mod.sub_modules()[0].fns()[0].skipped()); assert!(item_mod.sub_modules()[0].consts().is_empty()); assert!(item_mod.sub_modules()[0].sub_modules().is_empty()); } #[test] fn one_skipped_nested_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_mod(skip)] pub mod skip_this { pub fn get_mystic_number() -> INT { 42 } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.fns().is_empty()); assert!(item_mod.consts().is_empty()); assert_eq!(item_mod.sub_modules().len(), 1); assert!(item_mod.sub_modules()[0].skipped()); } #[test] fn one_constant_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { pub const MYSTIC_NUMBER: INT = 42; } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.fns().is_empty()); assert_eq!(item_mod.consts().len(), 1); assert_eq!(&item_mod.consts()[0].name, "MYSTIC_NUMBER"); assert_eq!( item_mod.consts()[0].expr, syn::parse2::(quote! { 42 }).unwrap() ); } #[test] fn one_skipped_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(skip)] pub fn get_mystic_number() -> INT { 42 } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_eq!(item_mod.fns().len(), 1); assert!(item_mod.fns()[0].skipped()); assert!(item_mod.consts().is_empty()); } #[test] fn one_private_constant_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { const MYSTIC_NUMBER: INT = 42; } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert!(item_mod.fns().is_empty()); assert!(item_mod.consts().is_empty()); } } #[cfg(test)] mod generate_tests { use super::super::assert_streams_eq; use crate::module::Module; use proc_macro2::TokenStream; use quote::quote; #[test] fn empty_module() { let input_tokens: TokenStream = quote! { pub mod empty { } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod empty { #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_factory_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn get_mystic_number() -> INT { 42 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn get_mystic_number() -> INT { 42 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("get_mystic_number").with_params_info(get_mystic_number_token::PARAM_NAMES) .set_into_module_raw(_m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_mystic_number_token(); #[doc(hidden)] impl get_mystic_number_token { pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(get_mystic_number())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_factory_fn_with_comments_module() { let input_tokens: TokenStream = quote! { /// This is the one_fn module! /** block doc-comment * multi-line */ /// Another line! /// Final line! pub mod one_fn { /// We are the world! pub type World = String; /// This is a doc-comment. /// Another line. /** block doc-comment */ // Regular comment /// Final line. /** doc-comment in multiple lines */ pub fn get_mystic_number() -> INT { 42 } } }; let expected_tokens = quote! { /// This is the one_fn module! /** block doc-comment * multi-line */ /// Another line! /// Final line! #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { /// We are the world! pub type World = String; /// This is a doc-comment. /// Another line. /** block doc-comment */ // Regular comment /// Final line. /** doc-comment in multiple lines */ pub fn get_mystic_number() -> INT { 42 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); m.set_doc("/// This is the one_fn module!\n/** block doc-comment\n * multi-line\n */\n/// Another line!\n/// Final line!"); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("get_mystic_number").with_params_info(get_mystic_number_token::PARAM_NAMES) .with_comments(&[ "/// This is a doc-comment.\n/// Another line.\n/// block doc-comment \n/// Final line.", "/** doc-comment\n in multiple lines\n */" ]) .set_into_module_raw(_m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); _m.set_custom_type_with_comments::("World", &["/// We are the world!"]); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_mystic_number_token(); #[doc(hidden)] impl get_mystic_number_token { pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(get_mystic_number())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_single_arg_global_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_global_fn { #[rhai_fn(global)] pub fn add_one_to(x: INT) -> INT { x + 1 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_global_fn { pub fn add_one_to(x: INT) -> INT { x + 1 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("add_one_to").with_namespace(FnNamespace::Global).with_params_info(add_one_to_token::PARAM_NAMES) .set_into_module_raw(_m, &add_one_to_token::param_types(), add_one_to_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct add_one_to_token(); #[doc(hidden)] impl add_one_to_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for add_one_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(add_one_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_single_arg_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn add_one_to(x: INT) -> INT { x + 1 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn add_one_to(x: INT) -> INT { x + 1 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("add_one_to").with_params_info(add_one_to_token::PARAM_NAMES) .set_into_module_raw(_m, &add_one_to_token::param_types(), add_one_to_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct add_one_to_token(); #[doc(hidden)] impl add_one_to_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for add_one_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(add_one_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn two_fn_overload_module() { let input_tokens: TokenStream = quote! { pub mod two_fns { #[rhai_fn(name = "add_n")] pub fn add_one_to(x: INT) -> INT { x + 1 } #[rhai_fn(name = "add_n")] pub fn add_n_to(x: INT, y: INT) -> INT { x + y } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod two_fns { pub fn add_one_to(x: INT) -> INT { x + 1 } pub fn add_n_to(x: INT, y: INT) -> INT { x + y } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("add_n").with_params_info(add_one_to_token::PARAM_NAMES) .set_into_module_raw(_m, &add_one_to_token::param_types(), add_one_to_token().into()); FuncRegistration::new("add_n").with_params_info(add_n_to_token::PARAM_NAMES) .set_into_module_raw(_m, &add_n_to_token::param_types(), add_n_to_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct add_one_to_token(); #[doc(hidden)] impl add_one_to_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for add_one_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); Ok(Dynamic::from(add_one_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct add_n_to_token(); #[doc(hidden)] impl add_n_to_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "y: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for add_n_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_n_to(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_double_arg_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn add_together(x: INT, y: INT) -> INT { x + y } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn add_together(x: INT, y: INT) -> INT { x + y } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("add_together").with_params_info(add_together_token::PARAM_NAMES) .set_into_module_raw(_m, &add_together_token::param_types(), add_together_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct add_together_token(); #[doc(hidden)] impl add_together_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "y: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for add_together_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_together(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_double_rename_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(name = "add", name = "+", name = "add_together")] pub fn add_together(x: INT, y: INT) -> INT { x + y } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn add_together(x: INT, y: INT) -> INT { x + y } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("add").with_params_info(add_together_token::PARAM_NAMES) .set_into_module_raw(_m, &add_together_token::param_types(), add_together_token().into()); FuncRegistration::new("+").with_params_info(add_together_token::PARAM_NAMES) .set_into_module_raw(_m, &add_together_token::param_types(), add_together_token().into()); FuncRegistration::new("add_together").with_params_info(add_together_token::PARAM_NAMES) .set_into_module_raw(_m, &add_together_token::param_types(), add_together_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct add_together_token(); #[doc(hidden)] impl add_together_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: INT", "y: INT", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for add_together_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).cast::(); let arg1 = mem::take(args[1usize]).cast::(); Ok(Dynamic::from(add_together(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_constant_type_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { #[derive(Debug, Clone)] pub struct Foo(pub INT); pub type Hello = Foo; pub const MYSTIC_NUMBER: Foo = Foo(42); pub fn get_mystic_number(x: &mut Hello) -> INT { x.0 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_constant { #[derive(Debug, Clone)] pub struct Foo(pub INT); pub type Hello = Foo; pub const MYSTIC_NUMBER: Foo = Foo(42); pub fn get_mystic_number(x: &mut Hello) -> INT { x.0 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("get_mystic_number").with_params_info(get_mystic_number_token::PARAM_NAMES) .set_into_module_raw(_m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); _m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER); _m.set_custom_type::("Hello"); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_mystic_number_token(); #[doc(hidden)] impl get_mystic_number_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut Hello", "INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(get_mystic_number(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_constant_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { pub const MYSTIC_NUMBER: INT = 42; } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_constant { pub const MYSTIC_NUMBER: INT = 42; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER); } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_constant_module_imports_preserved() { let input_tokens: TokenStream = quote! { pub mod one_constant { pub use rhai::INT; pub const MYSTIC_NUMBER: INT = 42; } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_constant { pub use rhai::INT; pub const MYSTIC_NUMBER: INT = 42; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER); } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_private_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { fn get_mystic_number() -> INT { 42 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { fn get_mystic_number() -> INT { 42 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_skipped_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(skip)] pub fn get_mystic_number() -> INT { 42 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn get_mystic_number() -> INT { 42 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_skipped_sub_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub fn get_mystic_number() -> INT { 42 } #[rhai_mod(skip)] pub mod inner_secrets { pub const SECRET_NUMBER: INT = 86; } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn get_mystic_number() -> INT { 42 } pub mod inner_secrets { pub const SECRET_NUMBER: INT = 86; } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("get_mystic_number").with_params_info(get_mystic_number_token::PARAM_NAMES) .set_into_module_raw(_m, &get_mystic_number_token::param_types(), get_mystic_number_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_mystic_number_token(); #[doc(hidden)] impl get_mystic_number_token { pub const PARAM_NAMES: &'static [&'static str] = &["INT"]; #[inline(always)] pub fn param_types() -> [TypeId; 0usize] { [] } } impl PluginFunc for get_mystic_number_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { Ok(Dynamic::from(get_mystic_number())) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_private_constant_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { const MYSTIC_NUMBER: INT = 42; } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_constant { const MYSTIC_NUMBER: INT = 42; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_str_arg_fn_module() { let input_tokens: TokenStream = quote! { pub mod str_fn { pub fn print_out_to(x: &str) { x + 1 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod str_fn { pub fn print_out_to(x: &str) { x + 1 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("print_out_to").with_params_info(print_out_to_token::PARAM_NAMES) .set_into_module_raw(_m, &print_out_to_token::param_types(), print_out_to_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct print_out_to_token(); #[doc(hidden)] impl print_out_to_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &str", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for print_out_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).into_immutable_string().unwrap(); Ok(Dynamic::from(print_out_to(&arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_string_arg_fn_module() { let input_tokens: TokenStream = quote! { pub mod str_fn { pub fn print_out_to(x: String) { x + 1 } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod str_fn { pub fn print_out_to(x: String) { x + 1 } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("print_out_to").with_params_info(print_out_to_token::PARAM_NAMES) .set_into_module_raw(_m, &print_out_to_token::param_types(), print_out_to_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct print_out_to_token(); #[doc(hidden)] impl print_out_to_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: String", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for print_out_to_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = mem::take(args[0usize]).into_string().unwrap(); Ok(Dynamic::from(print_out_to(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { false } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn mut_ref_pure_fn_module() { let input_tokens: TokenStream = quote! { pub mod ref_fn { #[rhai_fn(pure)] pub fn foo(x: &mut FLOAT, y: INT) -> FLOAT { *x + y as FLOAT } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod ref_fn { pub fn foo(x: &mut FLOAT, y: INT) -> FLOAT { *x + y as FLOAT } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("foo").with_params_info(foo_token::PARAM_NAMES) .set_into_module_raw(_m, &foo_token::param_types(), foo_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct foo_token(); #[doc(hidden)] impl foo_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "y: INT", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(foo(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { true } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_mut_ref_fn_module() { let input_tokens: TokenStream = quote! { pub mod ref_fn { pub fn increment(x: &mut FLOAT) { *x += 1.0 as FLOAT; } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod ref_fn { pub fn increment(x: &mut FLOAT) { *x += 1.0 as FLOAT; } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("increment").with_params_info(increment_token::PARAM_NAMES) .set_into_module_raw(_m, &increment_token::param_types(), increment_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct increment_token(); #[doc(hidden)] impl increment_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for increment_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_fn_nested_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { pub mod it_is { pub fn increment(x: &mut FLOAT) { *x += 1.0 as FLOAT; } } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod it_is { pub fn increment(x: &mut FLOAT) { *x += 1.0 as FLOAT; } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("increment").with_params_info(increment_token::PARAM_NAMES) .set_into_module_raw(_m, &increment_token::param_types(), increment_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct increment_token(); #[doc(hidden)] impl increment_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for increment_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { if _flatten { self::it_is::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("it_is", self::it_is::rhai_module_generate()); } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_fn_with_cfg_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[cfg(not(feature = "no_float"))] pub mod it_is { pub fn increment(x: &mut FLOAT) { *x += 1.0 as FLOAT; } } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { #[cfg(not(feature = "no_float"))] #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod it_is { pub fn increment(x: &mut FLOAT) { *x += 1.0 as FLOAT; } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("increment").with_params_info(increment_token::PARAM_NAMES) .set_into_module_raw(_m, &increment_token::param_types(), increment_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct increment_token(); #[doc(hidden)] impl increment_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for increment_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { if _flatten { #[cfg(not(feature = "no_float"))] self::it_is::rhai_generate_into_module(_m, _flatten); } else { #[cfg(not(feature = "no_float"))] _m.set_sub_module("it_is", self::it_is::rhai_module_generate()); } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_getter_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(get = "square")] pub fn int_foo(x: &mut u64) -> u64 { (*x) * (*x) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn int_foo(x: &mut u64) -> u64 { (*x) * (*x) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("get$square").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) .set_into_module_raw(_m, &int_foo_token::param_types(), int_foo_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct int_foo_token(); #[doc(hidden)] impl int_foo_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "u64"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_getter_and_rename_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(name = "square", get = "square")] pub fn int_foo(x: &mut u64) -> u64 { (*x) * (*x) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn int_foo(x: &mut u64) -> u64 { (*x) * (*x) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("square").with_params_info(int_foo_token::PARAM_NAMES) .set_into_module_raw(_m, &int_foo_token::param_types(), int_foo_token().into()); FuncRegistration::new("get$square").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) .set_into_module_raw(_m, &int_foo_token::param_types(), int_foo_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct int_foo_token(); #[doc(hidden)] impl int_foo_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "u64"]; #[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::()] } } impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_setter_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(set = "squared")] pub fn int_foo(x: &mut u64, y: u64) { *x = y * y } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn int_foo(x: &mut u64, y: u64) { *x = y * y } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("set$squared").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) .set_into_module_raw(_m, &int_foo_token::param_types(), int_foo_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct int_foo_token(); #[doc(hidden)] impl int_foo_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "y: u64", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_setter_and_rename_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_fn { #[rhai_fn(name = "set_sq", set = "squared")] pub fn int_foo(x: &mut u64, y: u64) { *x = y * y } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_fn { pub fn int_foo(x: &mut u64, y: u64) { *x = y * y } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("set_sq").with_params_info(int_foo_token::PARAM_NAMES) .set_into_module_raw(_m, &int_foo_token::param_types(), int_foo_token().into()); FuncRegistration::new("set$squared").with_namespace(FnNamespace::Global).with_params_info(int_foo_token::PARAM_NAMES) .set_into_module_raw(_m, &int_foo_token::param_types(), int_foo_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct int_foo_token(); #[doc(hidden)] impl int_foo_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut u64", "y: u64", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for int_foo_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_index_getter_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_index_fn { #[rhai_fn(index_get)] pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { x.get(i) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_index_fn { pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { x.get(i) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("index$get$").with_namespace(FnNamespace::Global).with_params_info(get_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &get_by_index_token::param_types(), get_by_index_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_by_index_token(); #[doc(hidden)] impl get_by_index_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for get_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(get_by_index(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_index_getter_fn_with_cfg_attr_module() { let input_tokens: TokenStream = quote! { pub mod one_index_fn { #[cfg(hello)] #[rhai_fn(index_get)] #[some_other_attr] pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { x.get(i) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_index_fn { #[cfg(hello)] #[some_other_attr] pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { x.get(i) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { #[cfg(hello)] FuncRegistration::new("index$get$").with_namespace(FnNamespace::Global).with_params_info(get_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &get_by_index_token::param_types(), get_by_index_token().into()); } #[cfg(hello)] #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_by_index_token(); #[cfg(hello)] #[doc(hidden)] impl get_by_index_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } #[cfg(hello)] impl PluginFunc for get_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(get_by_index(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_index_getter_and_rename_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_index_fn { #[rhai_fn(name = "get", index_get)] pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { x.get(i) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_index_fn { pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT { x.get(i) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("get").with_params_info(get_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &get_by_index_token::param_types(), get_by_index_token().into()); FuncRegistration::new("index$get$").with_namespace(FnNamespace::Global).with_params_info(get_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &get_by_index_token::param_types(), get_by_index_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct get_by_index_token(); #[doc(hidden)] impl get_by_index_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "FLOAT"]; #[inline(always)] pub fn param_types() -> [TypeId; 2usize] { [TypeId::of::(), TypeId::of::()] } } impl PluginFunc for get_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(get_by_index(arg0, arg1))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_index_setter_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_index_fn { #[rhai_fn(index_set)] pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { x.entry(i).set(item) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_index_fn { pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { x.entry(i).set(item) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("index$set$").with_namespace(FnNamespace::Global).with_params_info(set_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &set_by_index_token::param_types(), set_by_index_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct set_by_index_token(); #[doc(hidden)] impl set_by_index_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 3usize] { [TypeId::of::(), TypeId::of::(), TypeId::of::()] } } impl PluginFunc for set_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg2 = mem::take(args[2usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(set_by_index(arg0, arg1, arg2))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_index_setter_and_rename_fn_module() { let input_tokens: TokenStream = quote! { pub mod one_index_fn { #[rhai_fn(name = "set", index_set)] pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { x.entry(i).set(item) } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_index_fn { pub fn set_by_index(x: &mut MyCollection, i: u64, item: FLOAT) { x.entry(i).set(item) } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { FuncRegistration::new("set").with_params_info(set_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &set_by_index_token::param_types(), set_by_index_token().into()); FuncRegistration::new("index$set$").with_namespace(FnNamespace::Global).with_params_info(set_by_index_token::PARAM_NAMES) .set_into_module_raw(_m, &set_by_index_token::param_types(), set_by_index_token().into()); } #[allow(non_camel_case_types)] #[doc(hidden)] pub struct set_by_index_token(); #[doc(hidden)] impl set_by_index_token { pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut MyCollection", "i: u64", "item: FLOAT", "()"]; #[inline(always)] pub fn param_types() -> [TypeId; 3usize] { [TypeId::of::(), TypeId::of::(), TypeId::of::()] } } impl PluginFunc for set_by_index_token { #[inline(always)] fn call(&self, context: Option, args: &mut [&mut Dynamic]) -> RhaiResult { let arg1 = mem::take(args[1usize]).cast::(); let arg2 = mem::take(args[2usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(set_by_index(arg0, arg1, arg2))) } #[inline(always)] fn is_method_call(&self) -> bool { true } #[inline(always)] fn is_pure(&self) -> bool { false } #[inline(always)] fn is_volatile(&self) -> bool { false } #[inline(always)] fn has_context(&self) -> bool { false } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn one_constant_nested_module() { let input_tokens: TokenStream = quote! { pub mod one_constant { pub mod it_is { pub const MYSTIC_NUMBER: INT = 42; } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod one_constant { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod it_is { pub const MYSTIC_NUMBER: INT = 42; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER); } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { if _flatten { self::it_is::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("it_is", self::it_is::rhai_module_generate()); } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn dual_constant_nested_module() { let input_tokens: TokenStream = quote! { pub mod two_constants { pub mod first_is { pub const MYSTIC_NUMBER: INT = 42; } pub mod second_is { #[cfg(hello)] pub const SPECIAL_CPU_NUMBER: INT = 68000; } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod two_constants { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod first_is { pub const MYSTIC_NUMBER: INT = 42; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER); } } #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod second_is { #[cfg(hello)] pub const SPECIAL_CPU_NUMBER: INT = 68000; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { #[cfg(hello)] _m.set_var("SPECIAL_CPU_NUMBER", SPECIAL_CPU_NUMBER); } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { if _flatten { self::first_is::rhai_generate_into_module(_m, _flatten); self::second_is::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("first_is", self::first_is::rhai_module_generate()); _m.set_sub_module("second_is", self::second_is::rhai_module_generate()); } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } #[test] fn deep_tree_nested_module() { let input_tokens: TokenStream = quote! { pub mod heap_root { pub const VALUE: INT = 100; pub mod left { pub const VALUE: INT = 19; pub mod left { pub const VALUE: INT = 17; pub mod left { pub const VALUE: INT = 2; } pub mod right { pub const VALUE: INT = 7; } } pub mod right { pub const VALUE: INT = 3; } } pub mod right { pub const VALUE: INT = 36; pub mod left { pub const VALUE: INT = 25; } pub mod right { pub const VALUE: INT = 1; } } } }; let expected_tokens = quote! { #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod heap_root { pub const VALUE: INT = 100; #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod left { pub const VALUE: INT = 19; #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod left { pub const VALUE: INT = 17; #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod left { pub const VALUE: INT = 2; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); } } #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod right { pub const VALUE: INT = 7; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); if _flatten { self::left::rhai_generate_into_module(_m, _flatten); self::right::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("left", self::left::rhai_module_generate()); _m.set_sub_module("right", self::right::rhai_module_generate()); } } } #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod right { pub const VALUE: INT = 3; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); if _flatten { self::left::rhai_generate_into_module(_m, _flatten); self::right::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("left", self::left::rhai_module_generate()); _m.set_sub_module("right", self::right::rhai_module_generate()); } } } #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod right { pub const VALUE: INT = 36; #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod left { pub const VALUE: INT = 25; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); } } #[allow(clippy::needless_pass_by_value, clippy::needless_pass_by_ref_mut)] pub mod right { pub const VALUE: INT = 1; #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); if _flatten { self::left::rhai_generate_into_module(_m, _flatten); self::right::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("left", self::left::rhai_module_generate()); _m.set_sub_module("right", self::right::rhai_module_generate()); } } } #[allow(unused_imports)] use super::*; #[doc(hidden)] #[inline(always)] pub fn rhai_module_generate() -> Module { let mut m = Module::new(); rhai_generate_into_module(&mut m, false); m.build_index(); m } #[doc(hidden)] #[inline(always)] pub fn rhai_generate_into_module(_m: &mut Module, _flatten: bool) { _m.set_var("VALUE", VALUE); if _flatten { self::left::rhai_generate_into_module(_m, _flatten); self::right::rhai_generate_into_module(_m, _flatten); } else { _m.set_sub_module("left", self::left::rhai_module_generate()); _m.set_sub_module("right", self::right::rhai_module_generate()); } } } }; let item_mod = syn::parse2::(input_tokens).unwrap(); assert_streams_eq(item_mod.generate(), expected_tokens); } } rhai_codegen-2.0.0/tests/test_custom_type.rs000064400000000000000000000026010072674642500174030ustar 00000000000000use rhai::{CustomType, Engine, TypeBuilder, INT}; // Sanity check to make sure everything compiles #[derive(Clone, CustomType)] pub struct Bar( #[rhai_type(skip)] #[cfg(not(feature = "no_float"))] // check other attributes rhai::FLOAT, INT, #[rhai_type(name = "boo", readonly)] String, Vec, ); #[derive(Clone, Default, CustomType)] #[rhai_type(name = "MyFoo", extra = Self::build_extra)] pub struct Foo { #[cfg(not(feature = "no_float"))] // check other attributes #[rhai_type(skip)] _dummy: rhai::FLOAT, #[rhai_type(get = get_bar)] pub bar: INT, #[rhai_type(name = "boo", readonly)] pub(crate) baz: String, #[rhai_type(set = Self::set_qux)] pub qux: Vec, } impl Foo { pub fn set_qux(&mut self, value: Vec) { self.qux = value; } fn build_extra(builder: &mut TypeBuilder) { builder.with_fn("new_foo", || Self::default()); } } fn get_bar(_this: &Foo) -> INT { 42 } #[test] fn test() { let mut engine = Engine::new(); engine.build_type::().build_type::(); assert_eq!( engine .eval::( " let foo = new_foo(); foo.bar = 42; foo.bar " ) .unwrap(), 42 ); } rhai_codegen-2.0.0/tests/test_modules.rs000064400000000000000000000275440072674642500165150ustar 00000000000000use rhai::{Array, Engine, EvalAltResult, FLOAT, INT}; pub mod empty_module { use rhai::plugin::*; #[allow(non_snake_case)] #[export_module] pub mod EmptyModule {} } #[test] fn empty_module_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::empty_module::EmptyModule); engine.register_static_module("Module::Empty", m.into()); Ok(()) } pub mod one_fn_module { use rhai::plugin::*; #[export_module] pub mod advanced_math { use rhai::FLOAT; pub fn get_mystic_number() -> FLOAT { 42.0 as FLOAT } } } #[test] fn one_fn_module_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::one_fn_module::advanced_math); engine.register_static_module("Math::Advanced", m.into()); assert_eq!( engine.eval::(r#"let m = Math::Advanced::get_mystic_number();m"#)?, 42.0 ); Ok(()) } pub mod one_fn_and_const_module { use rhai::plugin::*; #[export_module] pub mod advanced_math { use rhai::FLOAT; pub const MYSTIC_NUMBER: FLOAT = 42.0 as FLOAT; pub fn euclidean_distance(x1: FLOAT, y1: FLOAT, x2: FLOAT, y2: FLOAT) -> FLOAT { ((y2 - y1).abs().powf(2.0) + (x2 - x1).abs().powf(2.0)).sqrt() } } } #[test] fn one_fn_and_const_module_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::one_fn_and_const_module::advanced_math); engine.register_static_module("Math::Advanced", m.into()); assert_eq!( engine.eval::( " let m = Math::Advanced::MYSTIC_NUMBER; let x = Math::Advanced::euclidean_distance(0.0, 1.0, 0.0, m); x " )?, 41.0 ); Ok(()) } pub mod raw_fn_str_module { use rhai::plugin::*; #[export_module] pub mod host_io { pub fn write_out_str(message: &str) -> bool { eprintln!("{message}"); true } } } #[test] fn raw_fn_str_module_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::raw_fn_str_module::host_io); engine.register_static_module("Host::IO", m.into()); assert!(engine .eval::(r#"let x = Host::IO::write_out_str("hello world!"); x"#) .unwrap()); Ok(()) } pub mod mut_opaque_ref_module { use rhai::plugin::*; use rhai::INT; #[allow(dead_code)] // used inside `exported_module!` #[derive(Clone)] pub struct StatusMessage { os_code: Option, message: String, is_ok: bool, } #[export_module] pub mod host_msg { use super::{StatusMessage, INT}; pub fn new_message(is_ok: bool, message: &str) -> StatusMessage { StatusMessage { is_ok, os_code: None, message: message.to_string(), } } pub fn new_os_message(is_ok: bool, os_code: INT) -> StatusMessage { StatusMessage { is_ok, os_code: Some(os_code), message: format!("OS Code {os_code}"), } } pub fn write_out_message(message: &mut StatusMessage) -> bool { eprintln!("{}", message.message); true } } } #[test] fn mut_opaque_ref_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::mut_opaque_ref_module::host_msg); engine.register_static_module("Host::Msg", m.into()); assert!(engine .eval::( r#" let success = "it worked"; let message1 = Host::Msg::new_message(true, success); let ok1 = Host::Msg::write_out_message(message1); let message2 = Host::Msg::new_os_message(true, 0); let ok2 = Host::Msg::write_out_message(message2); ok1 && ok2 "# ) .unwrap()); Ok(()) } mod duplicate_fn_rename { use rhai::plugin::*; #[export_module] pub mod my_adds { use rhai::{FLOAT, INT}; #[rhai_fn(name = "add")] pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } #[rhai_fn(name = "add")] pub fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 } } } #[test] fn duplicate_fn_rename_test() -> Result<(), Box> { let mut engine = Engine::new(); engine.register_fn("get_mystic_number", || 42 as FLOAT); let m = rhai::exported_module!(crate::duplicate_fn_rename::my_adds); engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( " let fx = get_mystic_number(); let fy = Math::Advanced::add(fx, 1.0); let ix = 42; let iy = Math::Advanced::add(ix, 1); [fy, iy] ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &43.0); assert_eq!(&output_array[1].as_int().unwrap(), &43); Ok(()) } mod multiple_fn_rename { use rhai::plugin::*; #[export_module] pub mod my_adds { use rhai::{FLOAT, INT}; pub fn get_mystic_number() -> FLOAT { 42.0 } #[rhai_fn(name = "add", name = "+", name = "add_together")] pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 * 2.0 } #[rhai_fn(name = "add", name = "+", name = "add_together")] pub fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 * 2 } #[rhai_fn(name = "prop", get = "prop")] pub fn get_prop(x: FLOAT) -> FLOAT { x * 2.0 } #[rhai_fn(name = "idx", index_get)] pub fn index(x: FLOAT, i: INT) -> FLOAT { x + (i as FLOAT) } } } #[test] fn multiple_fn_rename_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::multiple_fn_rename::my_adds); engine.register_global_module(m.into()); engine.set_fast_operators(false); let output_array = engine.eval::( " let fx = get_mystic_number(); let fy1 = add(fx, 1.0); let fy2 = add_together(fx, 1.0); let fy3 = fx + 1.0; let p1 = fx.prop; let p2 = prop(fx); let idx1 = fx[1]; let idx2 = idx(fx, 1); let ix = 42; let iy1 = add(ix, 1); let iy2 = add_together(ix, 1); let iy3 = ix + 1; [fy1, fy2, fy3, iy1, iy2, iy3, p1, p2, idx1, idx2] ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &44.0); assert_eq!(&output_array[1].as_float().unwrap(), &44.0); assert_eq!(&output_array[2].as_float().unwrap(), &44.0); assert_eq!(&output_array[3].as_int().unwrap(), &44); assert_eq!(&output_array[4].as_int().unwrap(), &44); assert_eq!(&output_array[5].as_int().unwrap(), &44); assert_eq!(&output_array[6].as_float().unwrap(), &84.0); assert_eq!(&output_array[7].as_float().unwrap(), &84.0); assert_eq!(&output_array[8].as_float().unwrap(), &43.0); assert_eq!(&output_array[9].as_float().unwrap(), &43.0); Ok(()) } #[allow(dead_code)] // used inside `export_module!` mod export_by_prefix { use rhai::plugin::*; #[export_module(export_prefix = "foo_")] pub mod my_adds { use rhai::{FLOAT, INT}; #[rhai_fn(name = "foo_add_f")] pub fn foo_add1(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } #[rhai_fn(name = "bar_add_i")] fn foo_add_int(i1: INT, i2: INT) -> INT { i1 + i2 } #[rhai_fn(name = "foo_add_float2")] pub fn add_float2(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } pub fn foo_m(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } fn foo_n(i1: INT, i2: INT) -> INT { i1 + i2 } pub fn bar_m(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } } } #[test] fn export_by_prefix_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::export_by_prefix::my_adds); engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( " let ex = 41.0; let fx = Math::Advanced::foo_add_f(ex, 1.0); let gx = Math::Advanced::foo_m(41.0, 1.0); let ei = 41; let fi = Math::Advanced::bar_add_i(ei, 1); let gi = Math::Advanced::foo_n(41, 1); [fx, gx, fi, gi] ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &42.0); assert_eq!(&output_array[1].as_float().unwrap(), &42.0); assert_eq!(&output_array[2].as_int().unwrap(), &42); assert_eq!(&output_array[3].as_int().unwrap(), &42); assert!(matches!(*engine.eval::( " let ex = 41.0; let fx = Math::Advanced::foo_add_float2(ex, 1.0); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::foo_add_float2 (f64, f64)")); assert!(matches!(*engine.eval::( " let ex = 41.0; let fx = Math::Advanced::bar_m(ex, 1.0); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::bar_m (f64, f64)")); Ok(()) } #[allow(dead_code)] // used inside `export_module!` mod export_all { use rhai::plugin::*; #[export_module(export_all)] pub mod my_adds { use rhai::{FLOAT, INT}; #[rhai_fn(name = "foo_add_f")] pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } #[rhai_fn(name = "foo_add_i")] fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 } #[rhai_fn(skip)] pub fn add_float2(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } pub fn foo_m(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } fn foo_n(i1: INT, i2: INT) -> INT { i1 + i2 } #[rhai_fn(skip)] fn foo_p(i1: INT, i2: INT) -> INT { i1 * i2 } } } #[test] fn export_all_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::export_all::my_adds); engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( " let ex = 41.0; let fx = Math::Advanced::foo_add_f(ex, 1.0); let gx = Math::Advanced::foo_m(41.0, 1.0); let ei = 41; let fi = Math::Advanced::foo_add_i(ei, 1); let gi = Math::Advanced::foo_n(41, 1); [fx, gx, fi, gi] ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &42.0); assert_eq!(&output_array[1].as_float().unwrap(), &42.0); assert_eq!(&output_array[2].as_int().unwrap(), &42); assert_eq!(&output_array[3].as_int().unwrap(), &42); assert!(matches!(*engine.eval::( " let ex = 41; let fx = Math::Advanced::foo_p(ex, 1); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::foo_p (i64, i64)")); Ok(()) } rhai_codegen-2.0.0/tests/test_nested.rs000064400000000000000000000127060072674642500163210ustar 00000000000000use rhai::{Array, Engine, EvalAltResult, FLOAT}; pub mod one_fn_module_nested_attr { use rhai::plugin::*; #[export_module] pub mod advanced_math { use rhai::plugin::*; use rhai::FLOAT; #[rhai_fn(return_raw)] pub fn get_mystic_number() -> Result> { Ok(42.0) } } } #[test] fn one_fn_module_nested_attr_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::one_fn_module_nested_attr::advanced_math); engine.register_static_module("Math::Advanced", m.into()); assert_eq!( engine.eval::(r#"let m = Math::Advanced::get_mystic_number(); m"#)?, 42.0 ); Ok(()) } pub mod one_fn_sub_module_nested_attr { use rhai::plugin::*; #[export_module] pub mod advanced_math { #[rhai_mod(name = "constants")] pub mod my_module { use rhai::plugin::*; use rhai::FLOAT; #[rhai_fn(return_raw)] pub fn get_mystic_number() -> Result> { Ok(42.0) } } } } #[test] fn one_fn_sub_module_nested_attr_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::one_fn_sub_module_nested_attr::advanced_math); engine.register_static_module("Math::Advanced", m.into()); assert_eq!( engine.eval::( " let m = Math::Advanced::constants::get_mystic_number(); m " )?, 42.0 ); Ok(()) } mod export_nested_by_prefix { use rhai::plugin::*; #[export_module(export_prefix = "foo_")] pub mod my_adds { pub mod foo_first_adders { use rhai::{FLOAT, INT}; pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } pub fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 } } pub mod foo_second_adders { use rhai::{FLOAT, INT}; pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } pub fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 } } #[allow(dead_code)] // used inside a `exported_module!` #[rhai_mod(name = "foo_third_adders")] pub mod baz_third_adders { use rhai::{FLOAT, INT}; pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } pub fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 } } #[allow(dead_code)] // used inside a `exported_module!` pub mod bar_fourth_adders { use rhai::{FLOAT, INT}; pub fn add_float(f1: FLOAT, f2: FLOAT) -> FLOAT { f1 + f2 } pub fn add_int(i1: INT, i2: INT) -> INT { i1 + i2 } } } } #[test] fn export_nested_by_prefix_test() -> Result<(), Box> { let mut engine = Engine::new(); let m = rhai::exported_module!(crate::export_nested_by_prefix::my_adds); engine.register_static_module("Math::Advanced", m.into()); let output_array = engine.eval::( " let ex = 41.0; let fx = Math::Advanced::foo_first_adders::add_float(ex, 1.0); let ei = 41; let fi = Math::Advanced::foo_first_adders::add_int(ei, 1); let gx = 41.0; let hx = Math::Advanced::foo_second_adders::add_float(gx, 1.0); let gi = 41; let hi = Math::Advanced::foo_second_adders::add_int(gi, 1); [fx, hx, fi, hi] ", )?; assert_eq!(&output_array[0].as_float().unwrap(), &42.0); assert_eq!(&output_array[1].as_float().unwrap(), &42.0); assert_eq!(&output_array[2].as_int().unwrap(), &42); assert_eq!(&output_array[3].as_int().unwrap(), &42); assert!(matches!(*engine.eval::( " let ex = 41.0; let fx = Math::Advanced::foo_third_adders::add_float(ex, 1.0); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::foo_third_adders::add_float (f64, f64)")); assert!(matches!(*engine.eval::( " let ex = 41; let fx = Math::Advanced::foo_third_adders::add_int(ex, 1); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::foo_third_adders::add_int (i64, i64)")); assert!(matches!(*engine.eval::( " let ex = 41; let fx = Math::Advanced::bar_fourth_adders::add_int(ex, 1); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::bar_fourth_adders::add_int (i64, i64)")); assert!(matches!(*engine.eval::( " let ex = 41.0; let fx = Math::Advanced::bar_fourth_adders::add_float(ex, 1.0); fx ").unwrap_err(), EvalAltResult::ErrorFunctionNotFound(s, ..) if s == "Math::Advanced::bar_fourth_adders::add_float (f64, f64)")); Ok(()) } rhai_codegen-2.0.0/tests/ui_tests.rs000064400000000000000000000002350072674642500156310ustar 00000000000000#![cfg(test)] mod ui_tests { #[test] fn all() { let t = trybuild::TestCases::new(); t.compile_fail("ui_tests/*.rs"); } } rhai_codegen-2.0.0/ui_tests/export_fn_bad_attr.rs000064400000000000000000000005520072674642500203350ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(unknown = "thing")] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_bad_attr.stderr000064400000000000000000000005010072674642500212060ustar 00000000000000error: unknown attribute 'unknown' --> ui_tests/export_fn_bad_attr.rs:10:13 | 10 | #[export_fn(unknown = "thing")] | ^^^^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_bad_attr.rs:17:8 | 17 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_bad_value.rs000064400000000000000000000005440072674642500205000ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(name = true)] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_bad_value.stderr000064400000000000000000000004760072674642500213630ustar 00000000000000error: expecting string literal --> ui_tests/export_fn_bad_value.rs:10:20 | 10 | #[export_fn(name = true)] | ^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_bad_value.rs:17:8 | 17 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_cfg.rs000064400000000000000000000005710072674642500173150ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[cfg(not(feature = "foo"))] #[export_fn] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_cfg.stderr000064400000000000000000000004660072674642500201770ustar 00000000000000error: `cfg` attributes are not allowed for `export_fn` --> ui_tests/export_fn_cfg.rs:10:1 | 10 | #[cfg(not(feature = "foo"))] | ^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_cfg.rs:18:8 | 18 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_extra_value.rs000064400000000000000000000005530072674642500210750ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(return_raw = "yes")] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_extra_value.stderr000064400000000000000000000005100072674642500217450ustar 00000000000000error: extraneous value --> ui_tests/export_fn_extra_value.rs:10:26 | 10 | #[export_fn(return_raw = "yes")] | ^^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_extra_value.rs:17:8 | 17 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_junk_arg.rs000064400000000000000000000005420072674642500203540ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn("wheeeee")] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_junk_arg.stderr000064400000000000000000000004640072674642500212360ustar 00000000000000error: expecting identifier --> ui_tests/export_fn_junk_arg.rs:10:13 | 10 | #[export_fn("wheeeee")] | ^^^^^^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_junk_arg.rs:17:8 | 17 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_missing_value.rs000064400000000000000000000005350072674642500214230ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(name)] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_missing_value.stderr000064400000000000000000000004560072674642500223040ustar 00000000000000error: requires value --> ui_tests/export_fn_missing_value.rs:10:13 | 10 | #[export_fn(name)] | ^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_missing_value.rs:17:8 | 17 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_path_attr.rs000064400000000000000000000005550072674642500205460ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(rhai::name = "thing")] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_path_attr.stderr000064400000000000000000000005000072674642500214130ustar 00000000000000error: expecting attribute name --> ui_tests/export_fn_path_attr.rs:10:13 | 10 | #[export_fn(rhai::name = "thing")] | ^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_path_attr.rs:17:8 | 17 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_raw_noreturn.rs000064400000000000000000000005650072674642500213060ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(return_raw)] pub fn test_fn(input: &mut Point) { input.x += 1.0; } fn main() { let n = Point { x: 0.0, y: 10.0 }; test_fn(&mut n); if n.x >= 10.0 { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_raw_noreturn.stderr000064400000000000000000000005640072674642500221640ustar 00000000000000error: functions marked with 'return_raw' must return Result> --> ui_tests/export_fn_raw_noreturn.rs:10:13 | 10 | #[export_fn(return_raw)] | ^^^^^^^^^^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/export_fn_raw_noreturn.rs:17:5 | 17 | test_fn(&mut n); | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/export_fn_raw_return.rs000064400000000000000000000005430072674642500207450ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_fn(return_raw)] pub fn test_fn(input: Point) -> bool { input.x > input.y } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_fn_raw_return.stderr000064400000000000000000000011230072674642500216170ustar 00000000000000error[E0599]: `bool` is not an iterator --> ui_tests/export_fn_raw_return.rs:11:33 | 10 | #[export_fn(return_raw)] | ------------------------ in this procedural macro expansion 11 | pub fn test_fn(input: Point) -> bool { | ^^^^ `bool` is not an iterator | = note: the following trait bounds were not satisfied: `bool: std::iter::Iterator` which is required by `&mut bool: std::iter::Iterator` = note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info) rhai_codegen-2.0.0/ui_tests/export_mod_bad_attr.rs000064400000000000000000000006340072674642500205120ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(unknown = "thing")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_bad_attr.stderr000064400000000000000000000005750072674642500213750ustar 00000000000000error: unknown attribute 'unknown' --> ui_tests/export_mod_bad_attr.rs:11:11 | 11 | #[rhai_fn(unknown = "thing")] | ^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_bad_attr.rs:22:8 | 22 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_bad_value.rs000064400000000000000000000006260072674642500206550ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(name = true)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_bad_value.stderr000064400000000000000000000005720072674642500215340ustar 00000000000000error: expecting string literal --> ui_tests/export_mod_bad_value.rs:11:18 | 11 | #[rhai_fn(name = true)] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_bad_value.rs:22:8 | 22 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_cfg.rs000064400000000000000000000006530072674642500174720ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[cfg(not(feature = "foo"))] #[rhai_fn] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_cfg.stderr000064400000000000000000000005700072674642500203470ustar 00000000000000error: expected attribute arguments in parentheses: #[rhai_fn(...)] --> ui_tests/export_mod_cfg.rs:12:3 | 12 | #[rhai_fn] | ^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_cfg.rs:23:8 | 23 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_extra_value.rs000064400000000000000000000006350072674642500212520ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(return_raw = "yes")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_extra_value.stderr000064400000000000000000000006040072674642500221250ustar 00000000000000error: extraneous value --> ui_tests/export_mod_extra_value.rs:11:24 | 11 | #[rhai_fn(return_raw = "yes")] | ^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_extra_value.rs:22:8 | 22 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_junk_arg.rs000064400000000000000000000006240072674642500205310ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn("wheeeee")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_junk_arg.stderr000064400000000000000000000005600072674642500214070ustar 00000000000000error: expecting identifier --> ui_tests/export_mod_junk_arg.rs:11:11 | 11 | #[rhai_fn("wheeeee")] | ^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_junk_arg.rs:22:8 | 22 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_missing_value.rs000064400000000000000000000006170072674642500216000ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(name)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_missing_value.stderr000064400000000000000000000005520072674642500224550ustar 00000000000000error: requires value --> ui_tests/export_mod_missing_value.rs:11:11 | 11 | #[rhai_fn(name)] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_missing_value.rs:22:8 | 22 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_path_attr.rs000064400000000000000000000006370072674642500207230ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(rhai::name = "thing")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_path_attr.stderr000064400000000000000000000005740072674642500216020ustar 00000000000000error: expecting attribute name --> ui_tests/export_mod_path_attr.rs:11:11 | 11 | #[rhai_fn(rhai::name = "thing")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_path_attr.rs:22:8 | 22 | if test_mod::test_fn(n) { | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_raw_noreturn.rs000064400000000000000000000006470072674642500214630ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(return_raw)] pub fn test_fn(input: &mut Point) { input.x += 1.0; } } fn main() { let n = Point { x: 0.0, y: 10.0, }; test_mod::test_fn(&mut n); if n.x >= 10.0 { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_raw_noreturn.stderr000064400000000000000000000006600072674642500223350ustar 00000000000000error: functions marked with 'return_raw' must return Result> --> ui_tests/export_mod_raw_noreturn.rs:11:11 | 11 | #[rhai_fn(return_raw)] | ^^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_mod` --> ui_tests/export_mod_raw_noreturn.rs:22:5 | 22 | test_mod::test_fn(&mut n); | ^^^^^^^^ use of undeclared crate or module `test_mod` rhai_codegen-2.0.0/ui_tests/export_mod_raw_return.rs000064400000000000000000000006250072674642500211220ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_mod { #[rhai_fn(return_raw)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/export_mod_raw_return.stderr000064400000000000000000000011310072674642500217720ustar 00000000000000error[E0599]: `bool` is not an iterator --> ui_tests/export_mod_raw_return.rs:12:33 | 9 | #[export_module] | ---------------- in this procedural macro expansion ... 12 | pub fn test_fn(input: Point) -> bool { | ^^^^ `bool` is not an iterator | = note: the following trait bounds were not satisfied: `bool: std::iter::Iterator` which is required by `&mut bool: std::iter::Iterator` = note: this error originates in the attribute macro `export_module` (in Nightly builds, run with -Z macro-backtrace for more info) rhai_codegen-2.0.0/ui_tests/first_shared_ref.rs000064400000000000000000000006430072674642500200030ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; struct NonClonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: &NonClonable) -> bool { input.d } fn main() { let n = NonClonable { a: 0.0, b: 10, c: 'a', d: true, }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/first_shared_ref.stderr000064400000000000000000000005510072674642500206600ustar 00000000000000error: references from Rhai in this position must be mutable --> ui_tests/first_shared_ref.rs:12:23 | 12 | pub fn test_fn(input: &NonClonable) -> bool { | ^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/first_shared_ref.rs:23:8 | 23 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/non_clonable.rs000064400000000000000000000006420072674642500171220ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; struct NonClonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: NonClonable) -> bool { input.d } fn main() { let n = NonClonable { a: 0.0, b: 10, c: 'a', d: true, }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/non_clonable.stderr000064400000000000000000000013400072674642500177750ustar 00000000000000error[E0277]: the trait bound `NonClonable: Clone` is not satisfied --> ui_tests/non_clonable.rs:12:23 | 12 | pub fn test_fn(input: NonClonable) -> bool { | ^^^^^^^^^^^ | | | the trait `Clone` is not implemented for `NonClonable` | required by a bound introduced by this call | note: required by a bound in `rhai::Dynamic::cast` --> $WORKSPACE/src/types/dynamic.rs | | pub fn cast(self) -> T { | ^^^^^ required by this bound in `Dynamic::cast` help: consider annotating `NonClonable` with `#[derive(Clone)]` | 4 + #[derive(Clone)] 5 | struct NonClonable { | rhai_codegen-2.0.0/ui_tests/non_clonable_second.rs000064400000000000000000000006600072674642500204550ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; struct NonClonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(a: u32, b: NonClonable) -> bool { a == 0 && b.d } fn main() { let n = NonClonable { a: 0.0, b: 10, c: 'a', d: true, }; if test_fn(10, n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/non_clonable_second.stderr000064400000000000000000000013730072674642500213360ustar 00000000000000error[E0277]: the trait bound `NonClonable: Clone` is not satisfied --> ui_tests/non_clonable_second.rs:12:27 | 12 | pub fn test_fn(a: u32, b: NonClonable) -> bool { | ^^^^^^^^^^^ | | | the trait `Clone` is not implemented for `NonClonable` | required by a bound introduced by this call | note: required by a bound in `rhai::Dynamic::cast` --> $WORKSPACE/src/types/dynamic.rs | | pub fn cast(self) -> T { | ^^^^^ required by this bound in `Dynamic::cast` help: consider annotating `NonClonable` with `#[derive(Clone)]` | 4 + #[derive(Clone)] 5 | struct NonClonable { | rhai_codegen-2.0.0/ui_tests/return_mut_ref.rs000064400000000000000000000007210072674642500175270ustar 00000000000000#![allow(deprecated)] #![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Clonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: &mut Clonable) -> &mut bool { &mut input.d } fn main() { let n = Clonable { a: 0.0, b: 10, c: 'a', d: true, }; if test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/return_mut_ref.stderr000064400000000000000000000005540072674642500204120ustar 00000000000000error: Rhai functions cannot return references --> ui_tests/return_mut_ref.rs:14:38 | 14 | pub fn test_fn(input: &mut Clonable) -> &mut bool { | ^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/return_mut_ref.rs:25:8 | 25 | if test_fn(n) { | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/return_pointer.rs000064400000000000000000000006450072674642500175530ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Clonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: Clonable) -> *const str { "yes" } fn main() { let n = Clonable { a: 0.0, b: 10, c: 'a', d: true, }; println!("{}", unsafe { let ptr = test_fn(n); *ptr }); } rhai_codegen-2.0.0/ui_tests/return_pointer.stderr000064400000000000000000000005670072674642500204350ustar 00000000000000error: Rhai functions cannot return pointers --> ui_tests/return_pointer.rs:13:33 | 13 | pub fn test_fn(input: Clonable) -> *const str { | ^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/return_pointer.rs:25:19 | 25 | let ptr = test_fn(n); | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/return_shared_ref.rs000064400000000000000000000005650072674642500201760ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] struct Clonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: Clonable) -> &'static str { "yes" } fn main() { let n = Clonable { a: 0.0, b: 10, c: 'a', d: true, }; println!("{}", test_fn(n)); } rhai_codegen-2.0.0/ui_tests/return_shared_ref.stderr000064400000000000000000000006040072674642500210470ustar 00000000000000error: Rhai functions cannot return references --> ui_tests/return_shared_ref.rs:13:33 | 13 | pub fn test_fn(input: Clonable) -> &'static str { | ^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/return_shared_ref.rs:24:20 | 24 | println!("{}", test_fn(n)); | ^^^^^^^ not found in this scope rhai_codegen-2.0.0/ui_tests/rhai_fn_bad_attr.rs000064400000000000000000000006420072674642500177370ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_fn(unknown = "thing")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_bad_attr.stderr000064400000000000000000000006030072674642500206130ustar 00000000000000error: unknown attribute 'unknown' --> ui_tests/rhai_fn_bad_attr.rs:11:11 | 11 | #[rhai_fn(unknown = "thing")] | ^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_bad_attr.rs:22:8 | 22 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_bad_value.rs000064400000000000000000000006340072674642500201020ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_fn(name = true)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_bad_value.stderr000064400000000000000000000006000072674642500207520ustar 00000000000000error: expecting string literal --> ui_tests/rhai_fn_bad_value.rs:11:18 | 11 | #[rhai_fn(name = true)] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_bad_value.rs:22:8 | 22 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_duplicate_attr.rs000064400000000000000000000005030072674642500211570ustar 00000000000000use rhai::plugin::*; #[export_module] pub mod test_module { #[rhai_fn(name = "test")] #[rhai_fn(pure)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_duplicate_attr.stderr000064400000000000000000000011050072674642500220350ustar 00000000000000error: duplicated attribute 'rhai_fn' --> ui_tests/rhai_fn_duplicate_attr.rs:6:5 | 6 | #[rhai_fn(pure)] | ^ error[E0425]: cannot find value `n` in this scope --> ui_tests/rhai_fn_duplicate_attr.rs:13:29 | 13 | if test_module::test_fn(n) { | ^ not found in this scope error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_duplicate_attr.rs:13:8 | 13 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_extra_value.rs000064400000000000000000000006430072674642500204770ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_fn(return_raw = "yes")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_extra_value.stderr000064400000000000000000000006120072674642500213520ustar 00000000000000error: extraneous value --> ui_tests/rhai_fn_extra_value.rs:11:24 | 11 | #[rhai_fn(return_raw = "yes")] | ^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_extra_value.rs:22:8 | 22 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_conflict.rs000064400000000000000000000007460072674642500213370ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", get = "foo", set = "bar")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_conflict.stderr000064400000000000000000000006740072674642500222160ustar 00000000000000error: conflicting setter --> ui_tests/rhai_fn_getter_conflict.rs:12:42 | 12 | #[rhai_fn(name = "foo", get = "foo", set = "bar")] | ^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_getter_conflict.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_multiple.rs000064400000000000000000000007460072674642500213710ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", get = "foo", get = "bar")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_multiple.stderr000064400000000000000000000006740072674642500222500ustar 00000000000000error: conflicting getter --> ui_tests/rhai_fn_getter_multiple.rs:12:42 | 12 | #[rhai_fn(name = "foo", get = "foo", get = "bar")] | ^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_getter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_return.rs000064400000000000000000000007400072674642500210470ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(get = "foo")] pub fn test_fn(input: &mut Point) { input.x *= 2.0; } } fn main() { let mut n = Point { x: 0.0, y: 10.0, }; test_module::test_fn(&mut n); if n.x > 10.0 { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_return.stderr000064400000000000000000000006250072674642500217300ustar 00000000000000error: property getter must return a value --> ui_tests/rhai_fn_getter_return.rs:13:9 | 13 | pub fn test_fn(input: &mut Point) { | ^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_getter_return.rs:23:5 | 23 | test_module::test_fn(&mut n); | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_signature.rs000064400000000000000000000007470072674642500215400ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(get = "foo")] pub fn test_fn(input: Point, value: bool) -> bool { value && input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n, true) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_getter_signature.stderr000064400000000000000000000007130072674642500224100ustar 00000000000000error: property getter requires exactly 1 parameter --> ui_tests/rhai_fn_getter_signature.rs:13:20 | 13 | pub fn test_fn(input: Point, value: bool) -> bool { | ^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_getter_signature.rs:23:8 | 23 | if test_module::test_fn(n, true) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_global_multiple.rs000064400000000000000000000007170072674642500213350ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(global, internal)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_global_multiple.stderr000064400000000000000000000006520072674642500222120ustar 00000000000000error: namespace is already set to 'global' --> ui_tests/rhai_fn_global_multiple.rs:12:23 | 12 | #[rhai_fn(global, internal)] | ^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_global_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_index_getter_multiple.rs000064400000000000000000000007420072674642500225540ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", index_get, index_get)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_index_getter_multiple.stderr000064400000000000000000000007130072674642500234310ustar 00000000000000error: conflicting index_get --> ui_tests/rhai_fn_index_getter_multiple.rs:12:40 | 12 | #[rhai_fn(name = "foo", index_get, index_get)] | ^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_index_getter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_index_getter_return.rs000064400000000000000000000007320072674642500222370ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(index_get)] pub fn test_fn(input: &mut Point, i: f32) { input.x *= 2.0; } } fn main() { let mut n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(&mut n, 5.0) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_index_getter_return.stderr000064400000000000000000000006620072674642500231200ustar 00000000000000error: index getter must return a value --> ui_tests/rhai_fn_index_getter_return.rs:13:9 | 13 | pub fn test_fn(input: &mut Point, i: f32) { | ^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_index_getter_return.rs:23:8 | 23 | if test_module::test_fn(&mut n, 5.0) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_index_getter_signature.rs000064400000000000000000000007110072674642500227160ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(index_get)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_index_getter_signature.stderr000064400000000000000000000007020072674642500235750ustar 00000000000000error: index getter requires exactly 2 parameters --> ui_tests/rhai_fn_index_getter_signature.rs:13:20 | 13 | pub fn test_fn(input: Point) -> bool { | ^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_index_getter_signature.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_index_setter_multiple.rs000064400000000000000000000007420072674642500225700ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", index_set, index_set)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_index_setter_multiple.stderr000064400000000000000000000007130072674642500234450ustar 00000000000000error: conflicting index_set --> ui_tests/rhai_fn_index_setter_multiple.rs:12:40 | 12 | #[rhai_fn(name = "foo", index_set, index_set)] | ^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_index_setter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_junk_arg.rs000064400000000000000000000006320072674642500177560ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_fn("wheeeee")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_junk_arg.stderr000064400000000000000000000005660072674642500206430ustar 00000000000000error: expecting identifier --> ui_tests/rhai_fn_junk_arg.rs:11:11 | 11 | #[rhai_fn("wheeeee")] | ^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_junk_arg.rs:22:8 | 22 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_missing_value.rs000064400000000000000000000006250072674642500210250ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_fn(name)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_missing_value.stderr000064400000000000000000000005600072674642500217020ustar 00000000000000error: requires value --> ui_tests/rhai_fn_missing_value.rs:11:11 | 11 | #[rhai_fn(name)] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_missing_value.rs:22:8 | 22 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_non_clonable_return.rs000064400000000000000000000006510072674642500222070ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; struct NonClonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: f32) -> NonClonable { NonClonable { a: input, b: 10, c: 'a', d: true, } } fn main() { let n = test_fn(20.0); if n.c == 'a' { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_non_clonable_return.stderr000064400000000000000000000015200072674642500230620ustar 00000000000000error[E0277]: the trait bound `NonClonable: Clone` is not satisfied --> ui_tests/rhai_fn_non_clonable_return.rs:12:31 | 11 | #[export_fn] | ------------ in this procedural macro expansion 12 | pub fn test_fn(input: f32) -> NonClonable { | ^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | note: required by a bound in `rhai::Dynamic::from` --> $WORKSPACE/src/types/dynamic.rs | | pub fn from(value: T) -> Self { | ^^^^^ required by this bound in `Dynamic::from` = note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NonClonable` with `#[derive(Clone)]` | 4 + #[derive(Clone)] 5 | struct NonClonable { | rhai_codegen-2.0.0/ui_tests/rhai_fn_path_attr.rs000064400000000000000000000006450072674642500201500ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_fn(rhai::name = "thing")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_path_attr.stderr000064400000000000000000000006020072674642500210200ustar 00000000000000error: expecting attribute name --> ui_tests/rhai_fn_path_attr.rs:11:11 | 11 | #[rhai_fn(rhai::name = "thing")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_path_attr.rs:22:8 | 22 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision.rs000064400000000000000000000010740072674642500215010ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo")] pub fn test_fn(input: Point) -> bool { input.x > input.y } #[rhai_fn(name = "foo")] pub fn test_fn_2(input: Point) -> bool { input.x < input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision.stderr000064400000000000000000000010720072674642500223560ustar 00000000000000error: duplicate Rhai signature for 'foo' --> ui_tests/rhai_fn_rename_collision.rs:17:15 | 17 | #[rhai_fn(name = "foo")] | ^^^^ error: duplicated function renamed 'foo' --> ui_tests/rhai_fn_rename_collision.rs:12:15 | 12 | #[rhai_fn(name = "foo")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_collision.rs:28:8 | 28 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision_oneattr.rs000064400000000000000000000010300072674642500232250ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo")] pub fn test_fn(input: Point) -> bool { input.x > input.y } pub fn foo(input: Point) -> bool { input.x < input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision_oneattr.stderr000064400000000000000000000011200072674642500241040ustar 00000000000000error: duplicate Rhai signature for 'foo' --> ui_tests/rhai_fn_rename_collision_oneattr.rs:17:12 | 17 | pub fn foo(input: Point) -> bool { | ^^^ error: duplicated function 'foo' --> ui_tests/rhai_fn_rename_collision_oneattr.rs:12:15 | 12 | #[rhai_fn(name = "foo")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_collision_oneattr.rs:27:8 | 27 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision_oneattr_multiple.rs000064400000000000000000000010520072674642500251440ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", get = "bar")] pub fn test_fn(input: Point) -> bool { input.x > input.y } #[rhai_fn(get = "bar")] pub fn foo(input: Point) -> bool { input.x < input.y } } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision_oneattr_multiple.stderr000064400000000000000000000011700072674642500260240ustar 00000000000000error: duplicate Rhai signature for 'bar' --> ui_tests/rhai_fn_rename_collision_oneattr_multiple.rs:17:15 | 17 | #[rhai_fn(get = "bar")] | ^^^ error: duplicated function renamed 'bar' --> ui_tests/rhai_fn_rename_collision_oneattr_multiple.rs:12:15 | 12 | #[rhai_fn(name = "foo", get = "bar")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_collision_oneattr_multiple.rs:25:8 | 25 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision_with_itself.rs000064400000000000000000000007200072674642500240770ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", name = "bar", name = "foo")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_collision_with_itself.stderr000064400000000000000000000012260072674642500247600ustar 00000000000000error: duplicate Rhai signature for 'foo' --> ui_tests/rhai_fn_rename_collision_with_itself.rs:12:15 | 12 | #[rhai_fn(name = "foo", name = "bar", name = "foo")] | ^^^^ error: duplicated function renamed 'foo' --> ui_tests/rhai_fn_rename_collision_with_itself.rs:12:15 | 12 | #[rhai_fn(name = "foo", name = "bar", name = "foo")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_collision_with_itself.rs:20:8 | 20 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_index_getter.rs000064400000000000000000000007230072674642500226710ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "index$get$")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_index_getter.stderr000064400000000000000000000006540072674642500235530ustar 00000000000000error: use attribute 'index_get' instead --> ui_tests/rhai_fn_rename_to_index_getter.rs:12:15 | 12 | #[rhai_fn(name = "index$get$")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_to_index_getter.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_index_setter.rs000064400000000000000000000007230072674642500227050ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "index$set$")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_index_setter.stderr000064400000000000000000000006540072674642500235670ustar 00000000000000error: use attribute 'index_set' instead --> ui_tests/rhai_fn_rename_to_index_setter.rs:12:15 | 12 | #[rhai_fn(name = "index$set$")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_to_index_setter.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_prop_getter.rs000064400000000000000000000007200072674642500225370ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "get$foo")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_prop_getter.stderr000064400000000000000000000006540072674642500234240ustar 00000000000000error: use attribute 'getter = "foo"' instead --> ui_tests/rhai_fn_rename_to_prop_getter.rs:12:15 | 12 | #[rhai_fn(name = "get$foo")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_to_prop_getter.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_prop_setter.rs000064400000000000000000000007200072674642500225530ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "get$foo")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_rename_to_prop_setter.stderr000064400000000000000000000006540072674642500234400ustar 00000000000000error: use attribute 'getter = "foo"' instead --> ui_tests/rhai_fn_rename_to_prop_setter.rs:12:15 | 12 | #[rhai_fn(name = "get$foo")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_rename_to_prop_setter.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_index_signature.rs000064400000000000000000000007110072674642500227320ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(index_set)] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_index_signature.stderr000064400000000000000000000007020072674642500236110ustar 00000000000000error: index setter requires exactly 3 parameters --> ui_tests/rhai_fn_setter_index_signature.rs:13:20 | 13 | pub fn test_fn(input: Point) -> bool { | ^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_setter_index_signature.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_multiple.rs000064400000000000000000000007460072674642500214050ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(name = "foo", set = "foo", set = "bar")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_multiple.stderr000064400000000000000000000006740072674642500222640ustar 00000000000000error: conflicting setter --> ui_tests/rhai_fn_setter_multiple.rs:12:42 | 12 | #[rhai_fn(name = "foo", set = "foo", set = "bar")] | ^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_setter_multiple.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_return.rs000064400000000000000000000010420072674642500210570ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(set = "foo")] pub fn test_fn(input: &mut Point, value: f32) -> bool { let z = if value % 2 { input.x } else { input.y }; *input.x = z; } } fn main() { let mut n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(&mut n, 5.0) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_return.stderr000064400000000000000000000007430072674642500217450ustar 00000000000000error: property setter cannot return any value --> ui_tests/rhai_fn_setter_return.rs:13:51 | 13 | pub fn test_fn(input: &mut Point, value: f32) -> bool { | ^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_setter_return.rs:24:8 | 24 | if test_module::test_fn(&mut n, 5.0) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_signature.rs000064400000000000000000000007130072674642500215450ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; #[rhai_fn(set = "foo")] pub fn test_fn(input: Point) -> bool { input.x > input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_fn_setter_signature.stderr000064400000000000000000000006710072674642500224270ustar 00000000000000error: property setter requires exactly 2 parameters --> ui_tests/rhai_fn_setter_signature.rs:13:20 | 13 | pub fn test_fn(input: Point) -> bool { | ^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_fn_setter_signature.rs:23:8 | 23 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_bad_attr.rs000064400000000000000000000006720072674642500201160ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_mod(unknown = "thing")] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_bad_attr.stderr000064400000000000000000000006070072674642500207730ustar 00000000000000error: unknown attribute 'unknown' --> ui_tests/rhai_mod_bad_attr.rs:11:12 | 11 | #[rhai_mod(unknown = "thing")] | ^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_bad_attr.rs:24:8 | 24 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_bad_value.rs000064400000000000000000000006640072674642500202610ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_mod(name = true)] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_bad_value.stderr000064400000000000000000000006040072674642500211320ustar 00000000000000error: expecting string literal --> ui_tests/rhai_mod_bad_value.rs:11:19 | 11 | #[rhai_mod(name = true)] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_bad_value.rs:24:8 | 24 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_inner_cfg_false.rs000064400000000000000000000007570072674642500214460ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[cfg(feature = "unset_feature")] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_mod::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_inner_cfg_false.stderr000064400000000000000000000004040072674642500223120ustar 00000000000000error[E0433]: failed to resolve: could not find `test_mod` in `test_module` --> ui_tests/rhai_mod_inner_cfg_false.rs:24:21 | 24 | if test_module::test_mod::test_fn(n) { | ^^^^^^^^ could not find `test_mod` in `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_junk_arg.rs000064400000000000000000000006620072674642500201350ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_mod("wheeeee")] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_junk_arg.stderr000064400000000000000000000005720072674642500210140ustar 00000000000000error: expecting identifier --> ui_tests/rhai_mod_junk_arg.rs:11:12 | 11 | #[rhai_mod("wheeeee")] | ^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_junk_arg.rs:24:8 | 24 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_missing_value.rs000064400000000000000000000006550072674642500212040ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_mod(name)] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_missing_value.stderr000064400000000000000000000005640072674642500220620ustar 00000000000000error: requires value --> ui_tests/rhai_mod_missing_value.rs:11:12 | 11 | #[rhai_mod(name)] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_missing_value.rs:24:8 | 24 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_name_collisions.rs000064400000000000000000000007760072674642500215210ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; pub fn test_fn(input: Point) -> bool { input.x > input.y } pub fn test_fn(input: Point) -> bool { input.x < input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_name_collisions.stderr000064400000000000000000000011140072674642500223630ustar 00000000000000error: duplicate function 'test_fn' --> ui_tests/rhai_mod_name_collisions.rs:16:12 | 16 | pub fn test_fn(input: Point) -> bool { | ^^^^^^^ error: duplicated function 'test_fn' --> ui_tests/rhai_mod_name_collisions.rs:12:12 | 12 | pub fn test_fn(input: Point) -> bool { | ^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_name_collisions.rs:26:8 | 26 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_non_clonable_return.rs000064400000000000000000000007270072674642500223670ustar 00000000000000use rhai::plugin::*; struct NonClonable { a: f32, b: u32, c: char, d: bool, } #[export_module] pub mod test_mod { pub fn test_fn(input: f32) -> NonClonable { NonClonable { a: input, b: 10, c: 'a', d: true, } } } fn main() { let n = test_mod::test_fn(20.0); if n.c == 'a' { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_non_clonable_return.stderr000064400000000000000000000016230072674642500232420ustar 00000000000000error[E0277]: the trait bound `NonClonable: Clone` is not satisfied --> ui_tests/rhai_mod_non_clonable_return.rs:12:35 | 10 | #[export_module] | ---------------- in this procedural macro expansion 11 | pub mod test_mod { 12 | pub fn test_fn(input: f32) -> NonClonable { | ^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | note: required by a bound in `rhai::Dynamic::from` --> $WORKSPACE/src/types/dynamic.rs | | pub fn from(value: T) -> Self { | ^^^^^ required by this bound in `Dynamic::from` = note: this error originates in the attribute macro `export_module` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `NonClonable` with `#[derive(Clone)]` | 3 + #[derive(Clone)] 4 | struct NonClonable { | rhai_codegen-2.0.0/ui_tests/rhai_mod_path_attr.rs000064400000000000000000000006750072674642500203270ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_mod(rhai::name = "thing")] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_path_attr.stderr000064400000000000000000000006060072674642500212000ustar 00000000000000error: expecting attribute name --> ui_tests/rhai_mod_path_attr.rs:11:12 | 11 | #[rhai_mod(rhai::name = "thing")] | ^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_path_attr.rs:24:8 | 24 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_return_raw.rs000064400000000000000000000006730072674642500205270ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { #[rhai_mod(return_raw = "yes")] pub mod test_mod { pub fn test_fn(input: Point) -> bool { input.x > input.y } } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_return_raw.stderr000064400000000000000000000006220072674642500214000ustar 00000000000000error: unknown attribute 'return_raw' --> ui_tests/rhai_mod_return_raw.rs:11:12 | 11 | #[rhai_mod(return_raw = "yes")] | ^^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared crate or module `test_module` --> ui_tests/rhai_mod_return_raw.rs:24:8 | 24 | if test_module::test_fn(n) { | ^^^^^^^^^^^ use of undeclared crate or module `test_module` rhai_codegen-2.0.0/ui_tests/rhai_mod_unknown_type.rs000064400000000000000000000006570072674642500211010ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; pub fn test_fn(input: Pointer) -> bool { input.x < input.y } } fn main() { let n = Point { x: 0.0, y: 10.0 }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_unknown_type.stderr000064400000000000000000000010710072674642500217470ustar 00000000000000error[E0412]: cannot find type `Pointer` in this scope --> ui_tests/rhai_mod_unknown_type.rs:12:27 | 4 | pub struct Point { | ---------------- similarly named struct `Point` defined here ... 12 | pub fn test_fn(input: Pointer) -> bool { | ^^^^^^^ | help: a struct with a similar name exists | 12 | pub fn test_fn(input: Point) -> bool { | ~~~~~ help: consider importing one of these items | 11 + use core::fmt::Pointer; | 11 + use std::fmt::Pointer; | rhai_codegen-2.0.0/ui_tests/rhai_mod_unknown_type_return.rs000064400000000000000000000006570072674642500225000ustar 00000000000000use rhai::plugin::*; #[derive(Clone)] pub struct Point { x: f32, y: f32, } #[export_module] pub mod test_module { pub use super::Point; pub fn test_fn(input: Point) -> boool { input.x < input.y } } fn main() { let n = Point { x: 0.0, y: 10.0, }; if test_module::test_fn(n) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/rhai_mod_unknown_type_return.stderr000064400000000000000000000004140072674642500233460ustar 00000000000000error[E0412]: cannot find type `boool` in this scope --> ui_tests/rhai_mod_unknown_type_return.rs:12:37 | 12 | pub fn test_fn(input: Point) -> boool { | ^^^^^ help: a builtin type with a similar name exists: `bool` rhai_codegen-2.0.0/ui_tests/second_shared_ref.rs000064400000000000000000000007160072674642500201300ustar 00000000000000#![allow(deprecated)] use rhai::plugin::*; #[derive(Clone)] pub struct Clonable { a: f32, b: u32, c: char, d: bool, } #[export_fn] pub fn test_fn(input: Clonable, factor: &bool) -> bool { input.d & factor } fn main() { let n = Clonable { a: 0.0, b: 10, c: 'a', d: true, }; if test_fn(n, &true) { println!("yes"); } else { println!("no"); } } rhai_codegen-2.0.0/ui_tests/second_shared_ref.stderr000064400000000000000000000006440072674642500210070ustar 00000000000000error: function parameters other than the first one cannot be passed by reference --> ui_tests/second_shared_ref.rs:13:41 | 13 | pub fn test_fn(input: Clonable, factor: &bool) -> bool { | ^ error[E0425]: cannot find function `test_fn` in this scope --> ui_tests/second_shared_ref.rs:24:8 | 24 | if test_fn(n, &true) { | ^^^^^^^ not found in this scope