Merge pull request #232 from schungx/master

Refine plugins.
This commit is contained in:
Stephen Chung 2020-09-14 22:34:13 +08:00 committed by GitHub
commit 2221d523f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 1613 additions and 148 deletions

View File

@ -8,6 +8,7 @@ New features
------------
* Plugins support via procedural macros.
* Scripted functions are allowed in packages.
Version 0.18.3

View File

@ -22,6 +22,7 @@ pub trait ExportedParams: Sized {
pub struct AttrItem {
pub key: proc_macro2::Ident,
pub value: Option<syn::LitStr>,
pub span: proc_macro2::Span,
}
pub struct ExportInfo {
@ -46,6 +47,7 @@ pub fn parse_punctuated_items(
let mut attrs: Vec<AttrItem> = Vec::new();
for arg in arg_list {
let arg_span = arg.span();
let (key, value) = match arg {
syn::Expr::Assign(syn::ExprAssign {
ref left,
@ -78,7 +80,7 @@ pub fn parse_punctuated_items(
.ok_or_else(|| syn::Error::new(attr_path.span(), "expecting attribute name"))?,
x => return Err(syn::Error::new(x.span(), "expecting identifier")),
};
attrs.push(AttrItem { key, value });
attrs.push(AttrItem { key, value, span: arg_span });
}
Ok(ExportInfo { item_span: list_span, items: attrs })

View File

@ -17,24 +17,43 @@ use syn::{parse::Parse, parse::ParseStream, parse::Parser, spanned::Spanned};
use crate::attrs::{ExportInfo, ExportScope, ExportedParams};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Index {
Get,
Set,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Property {
Get(syn::Ident),
Set(syn::Ident),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FnSpecialAccess {
None,
Index(Index),
Property(Property),
}
impl Default for FnSpecialAccess {
fn default() -> FnSpecialAccess {
FnSpecialAccess::None
}
}
#[derive(Debug, Default)]
pub(crate) struct ExportedFnParams {
pub name: Option<Vec<String>>,
pub return_raw: bool,
pub skip: bool,
pub span: Option<proc_macro2::Span>,
pub special: FnSpecialAccess,
}
pub const FN_IDX_GET: &str = "index$get$";
pub const FN_IDX_SET: &str = "index$set$";
pub fn make_getter(id: &str) -> String {
format!("get${}", id)
}
pub fn make_setter(id: &str) -> String {
format!("set${}", id)
}
impl Parse for ExportedFnParams {
fn parse(args: ParseStream) -> syn::Result<Self> {
if args.is_empty() {
@ -63,26 +82,73 @@ impl ExportedParams for ExportedFnParams {
let mut name = Vec::new();
let mut return_raw = false;
let mut skip = false;
let mut special = FnSpecialAccess::None;
for attr in attrs {
let crate::attrs::AttrItem { key, value } = attr;
let crate::attrs::AttrItem { key, value, span: item_span } = attr;
match (key.to_string().as_ref(), value) {
("name", Some(s)) => {
// check validity of name
if s.value().contains('.') {
return Err(syn::Error::new(
s.span(),
"Rhai function names may not contain dot",
));
}
name.push(s.value())
}
("get", Some(s)) => name.push(make_getter(&s.value())),
("set", Some(s)) => name.push(make_setter(&s.value())),
("get", None) | ("set", None) | ("name", None) => {
return Err(syn::Error::new(key.span(), "requires value"))
}
("index_get", None) => name.push(FN_IDX_GET.to_string()),
("index_set", None) => name.push(FN_IDX_SET.to_string()),
},
("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("get$") => {
return Err(syn::Error::new(item_span,
format!("use attribute 'getter = \"{}\"' instead",
&s.value()["get$".len()..])))
},
("name", Some(s)) if s.value().starts_with("set$") => {
return Err(syn::Error::new(item_span,
format!("use attribute 'setter = \"{}\"' instead",
&s.value()["set$".len()..])))
},
("name", Some(s)) if s.value().contains('$') => {
return Err(syn::Error::new(s.span(),
"Rhai function names may not contain dollar sign"))
},
("name", Some(s)) if s.value().contains('.') => {
return Err(syn::Error::new(s.span(),
"Rhai function names may not contain dot"))
},
("name", Some(s)) => {
name.push(s.value())
},
("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"))
}
},
("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"))
}
},
("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"))
}
},
("return_raw", None) => return_raw = true,
("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => {
return Err(syn::Error::new(s.span(), "extraneous value"))
@ -102,6 +168,7 @@ impl ExportedParams for ExportedFnParams {
name: if name.is_empty() { None } else { Some(name) },
return_raw,
skip,
special,
span: Some(span),
..Default::default()
})
@ -259,6 +326,32 @@ impl ExportedFn {
&self.signature.ident
}
pub(crate) fn exported_names(&self) -> Vec<syn::LitStr> {
let mut literals = self.params.name.as_ref()
.map(|v| v.iter()
.map(|s| syn::LitStr::new(s, proc_macro2::Span::call_site())).collect())
.unwrap_or_else(|| Vec::new());
match self.params.special {
FnSpecialAccess::None => {},
FnSpecialAccess::Property(Property::Get(ref g)) =>
literals.push(syn::LitStr::new(&format!("get${}", g.to_string()), g.span())),
FnSpecialAccess::Property(Property::Set(ref s)) =>
literals.push(syn::LitStr::new(&format!("set${}", s.to_string()), s.span())),
FnSpecialAccess::Index(Index::Get) =>
literals.push(syn::LitStr::new(FN_IDX_GET, proc_macro2::Span::call_site())),
FnSpecialAccess::Index(Index::Set) =>
literals.push(syn::LitStr::new(FN_IDX_SET, proc_macro2::Span::call_site())),
}
if literals.is_empty() {
literals.push(syn::LitStr::new(&self.signature.ident.to_string(),
self.signature.ident.span()));
}
literals
}
pub(crate) fn exported_name<'n>(&'n self) -> Cow<'n, str> {
if let Some(ref name) = self.params.name {
Cow::Borrowed(name.last().unwrap().as_str())
@ -284,9 +377,11 @@ impl ExportedFn {
}
pub fn set_params(&mut self, mut params: ExportedFnParams) -> syn::Result<()> {
// Do not allow non-returning raw functions.
// Several issues are checked here to avoid issues with diagnostics caused by raising them
// later.
//
// 1. Do not allow non-returning raw functions.
//
// This is caught now to avoid issues with diagnostics later.
if params.return_raw
&& mem::discriminant(&self.signature.output)
== mem::discriminant(&syn::ReturnType::Default)
@ -297,6 +392,58 @@ impl ExportedFn {
));
}
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.span(),
"property getter requires exactly 1 argument",
)),
// 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.span(),
"property setter requires exactly 2 arguments",
)),
// 3b. Property setters must return nothing.
FnSpecialAccess::Property(Property::Set(_)) if self.return_type().is_some() =>
return Err(syn::Error::new(
self.signature.span(),
"property setter must return no 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.span(),
"index getter requires exactly 2 arguments",
)),
// 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.span(),
"index setter requires exactly 3 arguments",
)),
// 5b. Index setters must return nothing.
FnSpecialAccess::Index(Index::Set) if self.return_type().is_some() =>
return Err(syn::Error::new(
self.signature.span(),
"index setter must return no value"
)),
_ => {}
}
self.params = params;
Ok(())
}

View File

@ -53,7 +53,7 @@ impl ExportedParams for ExportedModParams {
let mut skip = false;
let mut scope = ExportScope::default();
for attr in attrs {
let AttrItem { key, value } = attr;
let AttrItem { key, value, .. } = attr;
match (key.to_string().as_ref(), value) {
("name", Some(s)) => name = Some(s.value()),
("name", None) => return Err(syn::Error::new(key.span(), "requires value")),

View File

@ -67,11 +67,7 @@ pub(crate) fn generate_body(
&format!("{}_token", function.name().to_string()),
function.name().span(),
);
let reg_names = function
.params()
.name
.clone()
.unwrap_or_else(|| vec![function.name().to_string()]);
let reg_names = function.exported_names();
let fn_input_types: Vec<syn::Expr> = function
.arg_list()
@ -110,9 +106,7 @@ pub(crate) fn generate_body(
})
.collect();
for reg_name in reg_names {
let fn_literal = syn::LitStr::new(&reg_name, proc_macro2::Span::call_site());
for fn_literal in reg_names {
set_fn_stmts.push(
syn::parse2::<syn::Stmt>(quote! {
m.set_fn(#fn_literal, FnAccess::Public, &[#(#fn_input_types),*],

View File

@ -538,6 +538,74 @@ mod generate_tests {
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! {
pub mod one_fn {
pub fn add_together(x: INT, y: INT) -> INT {
x + y
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("add", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
CallableFunction::from_plugin(add_together_token()));
m.set_fn("+", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
CallableFunction::from_plugin(add_together_token()));
m.set_fn("add_together", FnAccess::Public, &[core::any::TypeId::of::<INT>(),
core::any::TypeId::of::<INT>()],
CallableFunction::from_plugin(add_together_token()));
m
}
#[allow(non_camel_case_types)]
struct add_together_token();
impl PluginFunction for add_together_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 2usize,
"wrong arg count: {} != {}", args.len(), 2usize);
let arg0 = mem::take(args[0usize]).clone().cast::<INT>();
let arg1 = mem::take(args[1usize]).clone().cast::<INT>();
Ok(Dynamic::from(add_together(arg0, arg1)))
}
fn is_method_call(&self) -> bool { false }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(add_together_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<INT>(),
TypeId::of::<INT>()].into_boxed_slice()
}
}
pub fn add_together_token_callable() -> CallableFunction {
CallableFunction::from_plugin(add_together_token())
}
pub fn add_together_token_input_types() -> Box<[TypeId]> {
add_together_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
assert_streams_eq(item_mod.generate(), expected_tokens);
}
#[test]
fn one_constant_module() {
let input_tokens: TokenStream = quote! {
@ -1004,6 +1072,521 @@ mod generate_tests {
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! {
pub mod one_fn {
pub fn int_foo(x: &mut u64) -> u64 {
(*x) * (*x)
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("get$square", FnAccess::Public, &[core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(int_foo_token()));
m
}
#[allow(non_camel_case_types)]
struct int_foo_token();
impl PluginFunction for int_foo_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 1usize,
"wrong arg count: {} != {}", args.len(), 1usize);
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice()
}
}
pub fn int_foo_token_callable() -> CallableFunction {
CallableFunction::from_plugin(int_foo_token())
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
pub mod one_fn {
pub fn int_foo(x: &mut u64) -> u64 {
(*x) * (*x)
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("square", FnAccess::Public, &[core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(int_foo_token()));
m.set_fn("get$square", FnAccess::Public, &[core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(int_foo_token()));
m
}
#[allow(non_camel_case_types)]
struct int_foo_token();
impl PluginFunction for int_foo_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 1usize,
"wrong arg count: {} != {}", args.len(), 1usize);
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>()].into_boxed_slice()
}
}
pub fn int_foo_token_callable() -> CallableFunction {
CallableFunction::from_plugin(int_foo_token())
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
pub mod one_fn {
pub fn int_foo(x: &mut u64, y: u64) {
*x = y * y
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("set$squared", FnAccess::Public,
&[core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(int_foo_token()));
m
}
#[allow(non_camel_case_types)]
struct int_foo_token();
impl PluginFunction for int_foo_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 2usize,
"wrong arg count: {} != {}", args.len(), 2usize);
let arg1 = mem::take(args[1usize]).clone().cast::<u64>();
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0, arg1)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
}
}
pub fn int_foo_token_callable() -> CallableFunction {
CallableFunction::from_plugin(int_foo_token())
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
pub mod one_fn {
pub fn int_foo(x: &mut u64, y: u64) {
*x = y * y
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("set_sq", FnAccess::Public,
&[core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(int_foo_token()));
m.set_fn("set$squared", FnAccess::Public,
&[core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(int_foo_token()));
m
}
#[allow(non_camel_case_types)]
struct int_foo_token();
impl PluginFunction for int_foo_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 2usize,
"wrong arg count: {} != {}", args.len(), 2usize);
let arg1 = mem::take(args[1usize]).clone().cast::<u64>();
let arg0: &mut _ = &mut args[0usize].write_lock::<u64>().unwrap();
Ok(Dynamic::from(int_foo(arg0, arg1)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(int_foo_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<u64>(), TypeId::of::<u64>()].into_boxed_slice()
}
}
pub fn int_foo_token_callable() -> CallableFunction {
CallableFunction::from_plugin(int_foo_token())
}
pub fn int_foo_token_input_types() -> Box<[TypeId]> {
int_foo_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
pub mod one_index_fn {
pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT {
x.get(i)
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("index$get$", FnAccess::Public,
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(get_by_index_token()));
m
}
#[allow(non_camel_case_types)]
struct get_by_index_token();
impl PluginFunction for get_by_index_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 2usize,
"wrong arg count: {} != {}", args.len(), 2usize);
let arg1 = mem::take(args[1usize]).clone().cast::<u64>();
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_by_index_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice()
}
}
pub fn get_by_index_token_callable() -> CallableFunction {
CallableFunction::from_plugin(get_by_index_token())
}
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
pub mod one_index_fn {
pub fn get_by_index(x: &mut MyCollection, i: u64) -> FLOAT {
x.get(i)
}
#[allow(unused_imports)]
use super::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("get", FnAccess::Public,
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(get_by_index_token()));
m.set_fn("index$get$", FnAccess::Public,
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>()],
CallableFunction::from_plugin(get_by_index_token()));
m
}
#[allow(non_camel_case_types)]
struct get_by_index_token();
impl PluginFunction for get_by_index_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 2usize,
"wrong arg count: {} != {}", args.len(), 2usize);
let arg1 = mem::take(args[1usize]).clone().cast::<u64>();
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(get_by_index(arg0, arg1)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(get_by_index_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>()].into_boxed_slice()
}
}
pub fn get_by_index_token_callable() -> CallableFunction {
CallableFunction::from_plugin(get_by_index_token())
}
pub fn get_by_index_token_input_types() -> Box<[TypeId]> {
get_by_index_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
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::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("index$set$", FnAccess::Public,
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
CallableFunction::from_plugin(set_by_index_token()));
m
}
#[allow(non_camel_case_types)]
struct set_by_index_token();
impl PluginFunction for set_by_index_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 3usize,
"wrong arg count: {} != {}", args.len(), 3usize);
let arg1 = mem::take(args[1usize]).clone().cast::<u64>();
let arg2 = mem::take(args[2usize]).clone().cast::<FLOAT>();
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(set_by_index(arg0, arg1, arg2)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(set_by_index_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>(),
TypeId::of::<FLOAT>()].into_boxed_slice()
}
}
pub fn set_by_index_token_callable() -> CallableFunction {
CallableFunction::from_plugin(set_by_index_token())
}
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(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! {
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::*;
#[allow(unused_mut)]
pub fn rhai_module_generate() -> Module {
let mut m = Module::new();
m.set_fn("set", FnAccess::Public,
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
CallableFunction::from_plugin(set_by_index_token()));
m.set_fn("index$set$", FnAccess::Public,
&[core::any::TypeId::of::<MyCollection>(),
core::any::TypeId::of::<u64>(),
core::any::TypeId::of::<FLOAT>()],
CallableFunction::from_plugin(set_by_index_token()));
m
}
#[allow(non_camel_case_types)]
struct set_by_index_token();
impl PluginFunction for set_by_index_token {
fn call(&self,
args: &mut [&mut Dynamic], pos: Position
) -> Result<Dynamic, Box<EvalAltResult>> {
debug_assert_eq!(args.len(), 3usize,
"wrong arg count: {} != {}", args.len(), 3usize);
let arg1 = mem::take(args[1usize]).clone().cast::<u64>();
let arg2 = mem::take(args[2usize]).clone().cast::<FLOAT>();
let arg0: &mut _ = &mut args[0usize].write_lock::<MyCollection>().unwrap();
Ok(Dynamic::from(set_by_index(arg0, arg1, arg2)))
}
fn is_method_call(&self) -> bool { true }
fn is_varadic(&self) -> bool { false }
fn clone_boxed(&self) -> Box<dyn PluginFunction> {
Box::new(set_by_index_token())
}
fn input_types(&self) -> Box<[TypeId]> {
new_vec![TypeId::of::<MyCollection>(),
TypeId::of::<u64>(),
TypeId::of::<FLOAT>()].into_boxed_slice()
}
}
pub fn set_by_index_token_callable() -> CallableFunction {
CallableFunction::from_plugin(set_by_index_token())
}
pub fn set_by_index_token_input_types() -> Box<[TypeId]> {
set_by_index_token().input_types()
}
}
};
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
assert_streams_eq(item_mod.generate(), expected_tokens);
}
#[test]
fn one_constant_nested_module() {
let input_tokens: TokenStream = quote! {

View File

@ -4,8 +4,8 @@ error: unknown attribute 'unknown'
11 | #[rhai_fn(unknown = "thing")]
| ^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_bad_attr.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: expecting string literal
11 | #[rhai_fn(name = true)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_bad_value.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: cfg attributes not allowed on this item
11 | #[cfg(not(feature = "foo"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_cfg.rs:23:8
|
23 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: extraneous value
11 | #[rhai_fn(return_raw = "yes")]
| ^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_extra_value.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: expecting identifier
11 | #[rhai_fn("wheeeee")]
| ^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_junk_arg.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: requires value
11 | #[rhai_fn(name)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_missing_value.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: expecting attribute name
11 | #[rhai_fn(rhai::name = "thing")]
| ^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_path_attr.rs:22:8
|
22 | if test_mod::test_fn(n) {
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: return_raw functions must return Result<T>
12 | pub fn test_fn(input: &mut Point) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_mod`
error[E0433]: failed to resolve: use of undeclared crate or module `test_mod`
--> $DIR/export_mod_raw_noreturn.rs:22:5
|
22 | test_mod::test_fn(&mut n);
| ^^^^^^^^ use of undeclared type or module `test_mod`
| ^^^^^^^^ use of undeclared crate or module `test_mod`

View File

@ -4,8 +4,8 @@ error: cfg attributes not allowed on this item
13 | #[cfg(feature = "foo")]
| ^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/module_cfg_const.rs:26:8
|
26 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: cfg attributes not allowed on this item
11 | #[cfg(not(feature = "foo"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/module_cfg_fn.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: unknown attribute 'unknown'
11 | #[rhai_fn(unknown = "thing")]
| ^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_bad_attr.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: expecting string literal
11 | #[rhai_fn(name = true)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_bad_value.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: extraneous value
11 | #[rhai_fn(return_raw = "yes")]
| ^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_extra_value.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: conflicting setter
--> $DIR/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`
--> $DIR/rhai_fn_getter_conflict.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: conflicting getter
--> $DIR/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`
--> $DIR/rhai_fn_getter_multiple.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,29 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: property getter must return a value
--> $DIR/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`
--> $DIR/rhai_fn_getter_return.rs:23:5
|
23 | test_module::test_fn(&mut n);
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: property getter requires exactly 1 argument
--> $DIR/rhai_fn_getter_signature.rs:13:9
|
13 | pub fn test_fn(input: Point, value: bool) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_getter_signature.rs:23:8
|
23 | if test_module::test_fn(n, true) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: conflicting index_get
--> $DIR/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`
--> $DIR/rhai_fn_index_getter_multiple.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: index getter must return a value
--> $DIR/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`
--> $DIR/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`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: index getter requires exactly 2 arguments
--> $DIR/rhai_fn_index_getter_signature.rs:13:9
|
13 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_index_getter_signature.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: conflicting index_set
--> $DIR/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`
--> $DIR/rhai_fn_index_setter_multiple.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: expecting identifier
11 | #[rhai_fn("wheeeee")]
| ^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_junk_arg.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: requires value
11 | #[rhai_fn(name)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_missing_value.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: expecting attribute name
11 | #[rhai_fn(rhai::name = "thing")]
| ^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_path_attr.rs:22:8
|
22 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -10,8 +10,8 @@ error: duplicated function renamed 'foo'
12 | #[rhai_fn(name = "foo")]
| ^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_rename_collision.rs:28:8
|
28 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -10,8 +10,8 @@ error: duplicated function 'foo'
17 | pub fn foo(input: Point) -> bool {
| ^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_rename_collision_oneattr.rs:27:8
|
27 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -1,17 +1,17 @@
error: duplicate Rhai signature for 'get$bar'
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:17:15
|
17 | #[rhai_fn(get = "bar")]
| ^^^^^^^^^^^
error: duplicated function renamed 'get$bar'
error: duplicate Rhai signature for 'foo'
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:12:15
|
12 | #[rhai_fn(name = "foo", get = "bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error: duplicated function 'foo'
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:18:12
|
18 | pub fn foo(input: Point) -> bool {
| ^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_rename_collision_oneattr_multiple.rs:25:8
|
25 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -10,8 +10,8 @@ error: duplicated function renamed 'foo'
12 | #[rhai_fn(name = "foo", name = "bar", name = "foo")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_rename_collision_with_itself.rs:20:8
|
20 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use rhai::plugin::*;
#[derive(Clone)]
pub struct Point {
x: f32,
y: f32,
}
#[export_module]
pub mod test_module {
pub use super::Point;
#[rhai_fn(name = "big$caching")]
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");
}
}

View File

@ -0,0 +1,11 @@
error: Rhai function names may not contain dollar sign
--> $DIR/rhai_fn_rename_dollar_sign.rs:12:22
|
12 | #[rhai_fn(name = "big$caching")]
| ^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_rename_dollar_sign.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: Rhai function names may not contain dot
12 | #[rhai_fn(name = "foo.bar")]
| ^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_rename_dot.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: use attribute 'index_get' instead
--> $DIR/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`
--> $DIR/rhai_fn_rename_to_index_getter.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: use attribute 'index_set' instead
--> $DIR/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`
--> $DIR/rhai_fn_rename_to_index_setter.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: use attribute 'getter = "foo"' instead
--> $DIR/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`
--> $DIR/rhai_fn_rename_to_prop_getter.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: use attribute 'getter = "foo"' instead
--> $DIR/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`
--> $DIR/rhai_fn_rename_to_prop_setter.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: index setter requires exactly 3 arguments
--> $DIR/rhai_fn_setter_index_signature.rs:13:9
|
13 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_setter_index_signature.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: conflicting setter
--> $DIR/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`
--> $DIR/rhai_fn_setter_multiple.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -0,0 +1,29 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: property setter must return no value
--> $DIR/rhai_fn_setter_return.rs:13:9
|
13 | pub fn test_fn(input: &mut Point, value: f32) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/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`

View File

@ -0,0 +1,28 @@
use 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");
}
}

View File

@ -0,0 +1,11 @@
error: property setter requires exactly 2 arguments
--> $DIR/rhai_fn_setter_signature.rs:13:9
|
13 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_fn_setter_signature.rs:23:8
|
23 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: unknown attribute 'unknown'
11 | #[rhai_mod(unknown = "thing")]
| ^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_bad_attr.rs:24:8
|
24 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: expecting string literal
11 | #[rhai_mod(name = true)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_bad_value.rs:24:8
|
24 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: expecting identifier
11 | #[rhai_mod("wheeeee")]
| ^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_junk_arg.rs:24:8
|
24 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: requires value
11 | #[rhai_mod(name)]
| ^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_missing_value.rs:24:8
|
24 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -10,8 +10,8 @@ error: duplicated function 'test_fn'
12 | pub fn test_fn(input: Point) -> bool {
| ^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_name_collisions.rs:26:8
|
26 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: expecting attribute name
11 | #[rhai_mod(rhai::name = "thing")]
| ^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_path_attr.rs:24:8
|
24 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -4,8 +4,8 @@ error: unknown attribute 'return_raw'
11 | #[rhai_mod(return_raw = "yes")]
| ^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared type or module `test_module`
error[E0433]: failed to resolve: use of undeclared crate or module `test_module`
--> $DIR/rhai_mod_return_raw.rs:24:8
|
24 | if test_module::test_fn(n) {
| ^^^^^^^^^^^ use of undeclared type or module `test_module`
| ^^^^^^^^^^^ use of undeclared crate or module `test_module`

View File

@ -15,7 +15,7 @@ help: consider importing one of these items
|
11 | use core::fmt::Pointer;
|
11 | use crate::mem::fmt::Pointer;
11 | use crate::new_vec::fmt::Pointer;
|
11 | use std::fmt::Pointer;
|

View File

@ -43,6 +43,9 @@ export x as answer; // the variable 'x' is exported under the alias 'answer'
}
```
[`private`] variables are used to initialize the module.
They cannot be used apart from this.
Functions
---------
@ -59,6 +62,9 @@ fn inc(x) { x + 1 } // script-defined function - default public
private fn foo() {} // private function - hidden
```
[`private`] functions are commonly called to initialize the module.
They cannot be called apart from this.
Sub-Modules
-----------

View File

@ -13,8 +13,8 @@ This Rust module can then either be loaded into an [`Engine`] as a normal [modul
registered as a [custom package]. This is done by using the `exported_module!` macro.
Using`#[export_module]` and `exported_module!`
---------------------------------------------
`#[export_module]` and `exported_module!`
----------------------------------------
Apply `#[export_module]` onto a Rust module to convert all `pub` functions into Rhai plugin
functions.
@ -92,6 +92,8 @@ With `#[rhai_fn(name = "...")]`, multiple functions may be registered under the
Operators (which require function names that are not valid for Rust) can also be registered this way.
Registering the same function name with the same parameter types will cause a parsing error.
```rust
use rhai::plugins::*; // a "prelude" import for macros
@ -155,6 +157,38 @@ mod my_module {
```
Multiple Registrations
----------------------
Parameters to the `#[rhai_fn(...)]` attribute can be applied multiple times.
This is especially useful for the `name = "..."`, `get = "..."` and `set = "..."` parameters
to give multiple alternative names to the same function.
```rust
use rhai::plugins::*; // a "prelude" import for macros
#[export_module]
mod my_module {
// This function can be called in five ways
#[rhai_fn(name = "get_prop_value", name = "prop", name = "+", set = "prop", index_get)]
pub fn prop_function(obj: &mut MyType, index: i64) -> i64 {
obj.prop[index]
}
}
```
The above function can be called in five ways:
| Parameter for `#[rhai_fn(...)]` | Type | Call style |
| ------------------------------- | :-------------: | --------------------------------------------- |
| `name = "get_prop_value"` | Method function | `get_prop_value(x, 0)`, `x.get_prop_value(0)` |
| `name = "prop"` | Method function | `prop(x, 0)`, `x.prop(0)` |
| `name = "+"` | Operator | `x + 42` |
| `set = "prop"` | Setter | `x.prop = 42` |
| `index_get` | Index getter | `x[0]` |
Fallible Functions
------------------

View File

@ -444,7 +444,7 @@ impl Engine {
//|| self.global_module.contains_fn(hash_script, pub_only)
|| self.global_module.contains_fn(hash_fn, pub_only)
// Then check packages
//|| self.packages.contains_fn(hash_script, pub_only)
|| self.packages.contains_fn(hash_script, pub_only)
|| self.packages.contains_fn(hash_fn, pub_only)
}
@ -477,7 +477,17 @@ impl Engine {
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
let arg_types = args.iter().map(|a| a.type_id());
let hash_fn = calc_fn_hash(empty(), fn_name, args.len(), arg_types);
let hash_fn = calc_fn_hash(
empty(),
fn_name,
if args.is_empty() {
// Distinguish between a script function and a native function with no parameters
usize::MAX
} else {
args.len()
},
arg_types,
);
match fn_name {
// type_of
@ -514,9 +524,15 @@ impl Engine {
// Normal script function call
#[cfg(not(feature = "no_function"))]
_ if hash_script > 0 && lib.contains_fn(hash_script, pub_only) => {
_ if lib.contains_fn(hash_script, pub_only)
|| self.packages.contains_fn(hash_script, pub_only) =>
{
// Get scripted function
let func = lib.get_fn(hash_script, pub_only).unwrap().get_fn_def();
let func = lib
.get_fn(hash_script, pub_only)
.or_else(|| self.packages.get_fn(hash_script, pub_only))
.unwrap()
.get_fn_def();
let scope = &mut Scope::new();
let mods = &mut Imports::new();
@ -559,6 +575,7 @@ impl Engine {
Ok((result, false))
}
// Normal native function call
_ => self.call_native_fn(
state, lib, fn_name, hash_fn, args, is_ref, pub_only, def_val,

View File

@ -93,7 +93,7 @@ pub use result::EvalAltResult;
pub use scope::Scope;
pub use syntax::{EvalContext, Expression};
pub use token::Position;
pub use utils::calc_fn_spec as calc_fn_hash;
pub use utils::calc_fn_hash;
pub use rhai_codegen::*;

View File

@ -247,9 +247,13 @@ impl Module {
&mut self,
hash_var: u64,
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
self.all_variables.get_mut(&hash_var).ok_or_else(|| {
EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into()
})
if hash_var == 0 {
Err(EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into())
} else {
self.all_variables.get_mut(&hash_var).ok_or_else(|| {
EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into()
})
}
}
/// Set a script-defined function into the module.
@ -354,7 +358,9 @@ impl Module {
/// assert!(module.contains_fn(hash, true));
/// ```
pub fn contains_fn(&self, hash_fn: u64, public_only: bool) -> bool {
if public_only {
if hash_fn == 0 {
false
} else if public_only {
self.functions
.get(&hash_fn)
.map(|(_, access, _, _)| match access {
@ -383,7 +389,14 @@ impl Module {
) -> u64 {
let name = name.into();
let hash_fn = calc_fn_hash(empty(), &name, arg_types.len(), arg_types.iter().cloned());
let args_len = if arg_types.is_empty() {
// Distinguish between a script function and a function with no parameters
usize::MAX
} else {
arg_types.len()
};
let hash_fn = calc_fn_hash(empty(), &name, args_len, arg_types.iter().cloned());
let params = arg_types.into_iter().cloned().collect();
@ -910,13 +923,17 @@ impl Module {
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
/// It is also returned by the `set_fn_XXX` calls.
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&Func> {
self.functions
.get(&hash_fn)
.and_then(|(_, access, _, f)| match access {
_ if !public_only => Some(f),
FnAccess::Public => Some(f),
FnAccess::Private => None,
})
if hash_fn == 0 {
None
} else {
self.functions
.get(&hash_fn)
.and_then(|(_, access, _, f)| match access {
_ if !public_only => Some(f),
FnAccess::Public => Some(f),
FnAccess::Private => None,
})
}
}
/// Get a modules-qualified function.

View File

@ -149,7 +149,7 @@ fn call_fn_with_constant_arguments(
fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
match stmt {
// if expr { Noop }
Stmt::IfThenElse(x) if matches!(x.1, Stmt::Noop(_)) => {
Stmt::IfThenElse(x) if matches!(x.1, Stmt::Noop(_)) && x.2.is_none() => {
state.set_dirty();
let pos = x.0.position();

View File

@ -1838,7 +1838,7 @@ fn parse_unary(
// Call negative function
expr => {
let op = "-";
let hash = calc_fn_hash(empty(), op, 2, empty());
let hash = calc_fn_hash(empty(), op, 1, empty());
let mut args = StaticVec::new();
args.push(expr);
@ -1865,7 +1865,7 @@ fn parse_unary(
args.push(expr);
let op = "!";
let hash = calc_fn_hash(empty(), op, 2, empty());
let hash = calc_fn_hash(empty(), op, 1, empty());
Ok(Expr::FnCall(Box::new((
(op.into(), true, false, pos),

View File

@ -1,28 +1,15 @@
//! Module defining plugins in Rhai. Is exported for use by plugin authors.
//! Module defining plugins in Rhai for use by plugin authors.
pub use crate::{
stdlib::any::TypeId,
stdlib::boxed::Box,
stdlib::format,
stdlib::string::ToString,
stdlib::vec::Vec,
stdlib::vec as new_vec,
stdlib::mem,
fn_native::CallableFunction,
Dynamic,
Engine,
EvalAltResult,
FnAccess,
ImmutableString,
Module,
Position,
RegisterResultFn,
fn_native::CallableFunction, stdlib::any::TypeId, stdlib::boxed::Box, stdlib::format,
stdlib::mem, stdlib::string::ToString, stdlib::vec as new_vec, stdlib::vec::Vec, Dynamic,
Engine, EvalAltResult, FnAccess, ImmutableString, Module, Position, RegisterResultFn,
};
#[cfg(features = "no_module")]
pub use rhai_codegen::{export_fn, register_exported_fn};
#[cfg(not(features = "no_module"))]
pub use rhai_codegen::*;
#[cfg(features = "no_module")]
pub use rhai_codegen::{export_fn, register_exported_fn};
#[cfg(features = "sync")]
/// Represents an externally-written plugin for the Rhai interpreter.

View File

@ -69,7 +69,7 @@ impl BuildHasher for StraightHasherBuilder {
/// # Note
///
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
pub fn calc_fn_spec<'a>(
pub fn calc_fn_hash<'a>(
modules: impl Iterator<Item = &'a str>,
fn_name: &str,
num: usize,

View File

@ -1,10 +1,10 @@
use rhai::{Engine, EvalAltResult, INT, Scope};
use rhai::packages::{Package, StandardPackage};
use rhai::{Engine, EvalAltResult, Module, Scope, INT};
#[test]
fn test_packages() -> Result<(), Box<EvalAltResult>> {
let e = Engine::new();
let ast = e.compile("x")?;
let engine = Engine::new();
let ast = engine.compile("x")?;
let std_pkg = StandardPackage::new();
let make_call = |x: INT| -> Result<INT, Box<EvalAltResult>> {
@ -24,10 +24,22 @@ fn test_packages() -> Result<(), Box<EvalAltResult>> {
engine.eval_ast_with_scope::<INT>(&mut scope, &ast)
};
// The following loop creates 10,000 Engine instances!
for x in 0..10_000 {
assert_eq!(make_call(x)?, x);
}
assert_eq!(make_call(42)?, 42);
Ok(())
}
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_module"))]
#[test]
fn test_packages_with_script() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
let ast = engine.compile("fn foo(x) { x + 1 }")?;
let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
engine.load_package(module);
assert_eq!(engine.eval::<INT>("foo(41)")?, 42);
Ok(())
}