Merge pull request #55 from jhwgh1968/getters_setters

Reorganize get/set/index code into FnSpecialAccess
This commit is contained in:
Stephen Chung 2020-09-13 17:37:28 +08:00 committed by GitHub
commit 5879f467d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1433 additions and 42 deletions

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

@ -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

@ -1,15 +1,15 @@
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: 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
|

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

@ -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`