Add type alias support for plugin modules.
This commit is contained in:
parent
6546eae95f
commit
fefa633cf0
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rhai_codegen"
|
name = "rhai_codegen"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["jhwgh1968", "Stephen Chung"]
|
authors = ["jhwgh1968", "Stephen Chung"]
|
||||||
description = "Procedural macros support package for Rhai, a scripting language and engine for Rust"
|
description = "Procedural macros support package for Rhai, a scripting language and engine for Rust"
|
||||||
|
@ -10,7 +10,7 @@ use std::borrow::Cow;
|
|||||||
|
|
||||||
use crate::attrs::{AttrItem, ExportInfo, ExportScope, ExportedParams};
|
use crate::attrs::{AttrItem, ExportInfo, ExportScope, ExportedParams};
|
||||||
use crate::function::ExportedFn;
|
use crate::function::ExportedFn;
|
||||||
use crate::rhai_module::ExportedConst;
|
use crate::rhai_module::{ExportedConst, ExportedType};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
||||||
pub struct ExportedModParams {
|
pub struct ExportedModParams {
|
||||||
@ -89,8 +89,9 @@ impl ExportedParams for ExportedModParams {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
mod_all: syn::ItemMod,
|
mod_all: syn::ItemMod,
|
||||||
fns: Vec<ExportedFn>,
|
|
||||||
consts: Vec<ExportedConst>,
|
consts: Vec<ExportedConst>,
|
||||||
|
custom_types: Vec<ExportedType>,
|
||||||
|
fns: Vec<ExportedFn>,
|
||||||
sub_modules: Vec<Module>,
|
sub_modules: Vec<Module>,
|
||||||
params: ExportedModParams,
|
params: ExportedModParams,
|
||||||
}
|
}
|
||||||
@ -107,6 +108,7 @@ impl Parse for Module {
|
|||||||
let mut mod_all: syn::ItemMod = input.parse()?;
|
let mut mod_all: syn::ItemMod = input.parse()?;
|
||||||
let fns: Vec<_>;
|
let fns: Vec<_>;
|
||||||
let mut consts = Vec::new();
|
let mut consts = Vec::new();
|
||||||
|
let mut custom_types = Vec::new();
|
||||||
let mut sub_modules = Vec::new();
|
let mut sub_modules = Vec::new();
|
||||||
|
|
||||||
if let Some((.., ref mut content)) = mod_all.content {
|
if let Some((.., ref mut content)) = mod_all.content {
|
||||||
@ -155,6 +157,25 @@ impl Parse for Module {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Gather and parse type definitions.
|
||||||
|
for item in content.iter() {
|
||||||
|
match item {
|
||||||
|
syn::Item::Type(syn::ItemType {
|
||||||
|
vis,
|
||||||
|
ident,
|
||||||
|
attrs,
|
||||||
|
ty,
|
||||||
|
..
|
||||||
|
}) if matches!(vis, syn::Visibility::Public(..)) => {
|
||||||
|
custom_types.push(ExportedType {
|
||||||
|
name: ident.to_string(),
|
||||||
|
typ: ty.clone(),
|
||||||
|
cfg_attrs: crate::attrs::collect_cfg_attr(&attrs),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Gather and parse sub-module definitions.
|
// Gather and parse sub-module definitions.
|
||||||
//
|
//
|
||||||
// They are actually removed from the module's body, because they will need
|
// They are actually removed from the module's body, because they will need
|
||||||
@ -188,6 +209,7 @@ impl Parse for Module {
|
|||||||
mod_all,
|
mod_all,
|
||||||
fns,
|
fns,
|
||||||
consts,
|
consts,
|
||||||
|
custom_types,
|
||||||
sub_modules,
|
sub_modules,
|
||||||
params: ExportedModParams::default(),
|
params: ExportedModParams::default(),
|
||||||
})
|
})
|
||||||
@ -241,6 +263,7 @@ impl Module {
|
|||||||
mut mod_all,
|
mut mod_all,
|
||||||
mut fns,
|
mut fns,
|
||||||
consts,
|
consts,
|
||||||
|
custom_types,
|
||||||
mut sub_modules,
|
mut sub_modules,
|
||||||
params,
|
params,
|
||||||
..
|
..
|
||||||
@ -257,6 +280,7 @@ impl Module {
|
|||||||
let mod_gen = crate::rhai_module::generate_body(
|
let mod_gen = crate::rhai_module::generate_body(
|
||||||
&mut fns,
|
&mut fns,
|
||||||
&consts,
|
&consts,
|
||||||
|
&custom_types,
|
||||||
&mut sub_modules,
|
&mut sub_modules,
|
||||||
¶ms.scope,
|
¶ms.scope,
|
||||||
);
|
);
|
||||||
@ -300,6 +324,11 @@ impl Module {
|
|||||||
&self.consts
|
&self.consts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn custom_types(&self) -> &[ExportedType] {
|
||||||
|
&self.custom_types
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn fns(&self) -> &[ExportedFn] {
|
pub fn fns(&self) -> &[ExportedFn] {
|
||||||
&self.fns
|
&self.fns
|
||||||
|
@ -18,9 +18,17 @@ pub struct ExportedConst {
|
|||||||
pub cfg_attrs: Vec<syn::Attribute>,
|
pub cfg_attrs: Vec<syn::Attribute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ExportedType {
|
||||||
|
pub name: String,
|
||||||
|
pub typ: Box<syn::Type>,
|
||||||
|
pub cfg_attrs: Vec<syn::Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_body(
|
pub fn generate_body(
|
||||||
fns: &mut [ExportedFn],
|
fns: &mut [ExportedFn],
|
||||||
consts: &[ExportedConst],
|
consts: &[ExportedConst],
|
||||||
|
custom_types: &[ExportedType],
|
||||||
sub_modules: &mut [Module],
|
sub_modules: &mut [Module],
|
||||||
parent_scope: &ExportScope,
|
parent_scope: &ExportScope,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
@ -54,6 +62,29 @@ pub fn generate_body(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ExportedType {
|
||||||
|
name,
|
||||||
|
typ,
|
||||||
|
cfg_attrs,
|
||||||
|
..
|
||||||
|
} in custom_types
|
||||||
|
{
|
||||||
|
let const_literal = syn::LitStr::new(&name, Span::call_site());
|
||||||
|
|
||||||
|
let cfg_attrs: Vec<_> = cfg_attrs
|
||||||
|
.iter()
|
||||||
|
.map(syn::Attribute::to_token_stream)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
set_const_statements.push(
|
||||||
|
syn::parse2::<syn::Stmt>(quote! {
|
||||||
|
#(#cfg_attrs)*
|
||||||
|
m.set_custom_type::<#typ>(#const_literal);
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for item_mod in sub_modules {
|
for item_mod in sub_modules {
|
||||||
item_mod.update_scope(&parent_scope);
|
item_mod.update_scope(&parent_scope);
|
||||||
if item_mod.skipped() {
|
if item_mod.skipped() {
|
||||||
|
@ -37,6 +37,31 @@ mod module_tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_factory_fn_with_custom_type_module() {
|
||||||
|
let input_tokens: TokenStream = quote! {
|
||||||
|
pub mod one_fn {
|
||||||
|
pub type Hello = ();
|
||||||
|
|
||||||
|
pub fn get_mystic_number() -> INT {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let item_mod = syn::parse2::<Module>(input_tokens).unwrap();
|
||||||
|
assert!(item_mod.consts().is_empty());
|
||||||
|
assert_eq!(item_mod.custom_types().len(), 1);
|
||||||
|
assert_eq!(item_mod.custom_types()[0].name.to_string(), "Hello");
|
||||||
|
assert_eq!(item_mod.fns().len(), 1);
|
||||||
|
assert_eq!(item_mod.fns()[0].name().to_string(), "get_mystic_number");
|
||||||
|
assert_eq!(item_mod.fns()[0].arg_count(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
item_mod.fns()[0].return_type().unwrap(),
|
||||||
|
&syn::parse2::<syn::Type>(quote! { INT }).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
fn one_factory_fn_with_comments_module() {
|
fn one_factory_fn_with_comments_module() {
|
||||||
@ -753,7 +778,13 @@ mod generate_tests {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Foo(pub INT);
|
pub struct Foo(pub INT);
|
||||||
|
|
||||||
|
pub type Hello = Foo;
|
||||||
|
|
||||||
pub const MYSTIC_NUMBER: Foo = Foo(42);
|
pub const MYSTIC_NUMBER: Foo = Foo(42);
|
||||||
|
|
||||||
|
pub fn get_mystic_number(x: &mut Hello) -> INT {
|
||||||
|
x.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -762,7 +793,13 @@ mod generate_tests {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Foo(pub INT);
|
pub struct Foo(pub INT);
|
||||||
|
|
||||||
|
pub type Hello = Foo;
|
||||||
|
|
||||||
pub const MYSTIC_NUMBER: Foo = Foo(42);
|
pub const MYSTIC_NUMBER: Foo = Foo(42);
|
||||||
|
|
||||||
|
pub fn get_mystic_number(x: &mut Hello) -> INT {
|
||||||
|
x.0
|
||||||
|
}
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -774,9 +811,32 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) {
|
||||||
|
m.set_fn("get_mystic_number", FnNamespace::Internal, FnAccess::Public,
|
||||||
|
Some(get_mystic_number_token::PARAM_NAMES), &[TypeId::of::<Hello>()],
|
||||||
|
get_mystic_number_token().into());
|
||||||
m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER);
|
m.set_var("MYSTIC_NUMBER", MYSTIC_NUMBER);
|
||||||
|
m.set_custom_type::<Foo>("Hello");
|
||||||
if flatten {} else {}
|
if flatten {} else {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct get_mystic_number_token();
|
||||||
|
impl get_mystic_number_token {
|
||||||
|
pub const PARAM_NAMES: &'static [&'static str] = &["x: &mut Hello", "INT"];
|
||||||
|
#[inline(always)] pub fn param_types() -> [TypeId; 1usize] { [TypeId::of::<Hello>()] }
|
||||||
|
}
|
||||||
|
impl PluginFunction for get_mystic_number_token {
|
||||||
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
|
if args[0usize].is_read_only() {
|
||||||
|
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
||||||
|
}
|
||||||
|
let arg0 = &mut args[0usize].write_lock::<Hello>().unwrap();
|
||||||
|
Ok(Dynamic::from(get_mystic_number(arg0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use std::any::{type_name, TypeId};
|
|||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
/// Get the global namespace module (which is the last module in `global_modules`).
|
/// Get the global namespace module (which is the fist module in `global_modules`).
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn global_namespace(&self) -> &Module {
|
pub(crate) fn global_namespace(&self) -> &Module {
|
||||||
@ -273,7 +273,8 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
|
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
|
||||||
self.register_type_with_name_raw(type_name::<T>(), name)
|
self.custom_types.add_type::<T>(name);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
/// Register a custom type for use with the [`Engine`], with a pretty-print name
|
/// Register a custom type for use with the [`Engine`], with a pretty-print name
|
||||||
/// for the `type_of` function. The type must implement [`Clone`].
|
/// for the `type_of` function. The type must implement [`Clone`].
|
||||||
@ -288,8 +289,7 @@ impl Engine {
|
|||||||
name: impl Into<Identifier>,
|
name: impl Into<Identifier>,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
// Add the pretty-print type name into the map
|
// Add the pretty-print type name into the map
|
||||||
self.type_names
|
self.custom_types.add(fully_qualified_type_path, name);
|
||||||
.insert(fully_qualified_type_path.into(), name.into());
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// Register an type iterator for an iterable type with the [`Engine`].
|
/// Register an type iterator for an iterable type with the [`Engine`].
|
||||||
|
@ -85,9 +85,15 @@ impl Engine {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
||||||
self.type_names
|
self.global_modules
|
||||||
.get(name)
|
.iter()
|
||||||
.map(|s| s.as_str())
|
.find_map(|m| m.get_custom_type(name))
|
||||||
|
.or_else(|| {
|
||||||
|
self.global_sub_modules
|
||||||
|
.iter()
|
||||||
|
.find_map(|(_, m)| m.get_custom_type(name))
|
||||||
|
})
|
||||||
|
.or_else(|| self.custom_types.get(name))
|
||||||
.unwrap_or_else(|| map_std_type_name(name, true))
|
.unwrap_or_else(|| map_std_type_name(name, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,9 +115,8 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.type_names
|
self.custom_types
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|s| s.as_str())
|
|
||||||
.unwrap_or_else(|| match name {
|
.unwrap_or_else(|| match name {
|
||||||
"INT" => return type_name::<crate::INT>(),
|
"INT" => return type_name::<crate::INT>(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
@ -6,7 +6,7 @@ use crate::func::native::{
|
|||||||
};
|
};
|
||||||
use crate::packages::{Package, StandardPackage};
|
use crate::packages::{Package, StandardPackage};
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::{dynamic::Union, CustomTypesCollection};
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Identifier, ImmutableString, Module, OptimizationLevel, Position, RhaiResult, Shared,
|
Dynamic, Identifier, ImmutableString, Module, OptimizationLevel, Position, RhaiResult, Shared,
|
||||||
StaticVec,
|
StaticVec,
|
||||||
@ -105,7 +105,7 @@ pub struct Engine {
|
|||||||
pub(crate) module_resolver: Option<Box<dyn crate::ModuleResolver>>,
|
pub(crate) module_resolver: Option<Box<dyn crate::ModuleResolver>>,
|
||||||
|
|
||||||
/// A map mapping type names to pretty-print names.
|
/// A map mapping type names to pretty-print names.
|
||||||
pub(crate) type_names: BTreeMap<Identifier, Identifier>,
|
pub(crate) custom_types: CustomTypesCollection,
|
||||||
|
|
||||||
/// An empty [`ImmutableString`] for cloning purposes.
|
/// An empty [`ImmutableString`] for cloning purposes.
|
||||||
pub(crate) empty_string: ImmutableString,
|
pub(crate) empty_string: ImmutableString,
|
||||||
@ -160,7 +160,7 @@ impl fmt::Debug for Engine {
|
|||||||
f.field("global_sub_modules", &self.global_sub_modules)
|
f.field("global_sub_modules", &self.global_sub_modules)
|
||||||
.field("module_resolver", &self.module_resolver.is_some());
|
.field("module_resolver", &self.module_resolver.is_some());
|
||||||
|
|
||||||
f.field("type_names", &self.type_names)
|
f.field("type_names", &self.custom_types)
|
||||||
.field("disabled_symbols", &self.disabled_symbols)
|
.field("disabled_symbols", &self.disabled_symbols)
|
||||||
.field("custom_keywords", &self.custom_keywords)
|
.field("custom_keywords", &self.custom_keywords)
|
||||||
.field("custom_syntax", &(!self.custom_syntax.is_empty()))
|
.field("custom_syntax", &(!self.custom_syntax.is_empty()))
|
||||||
@ -271,7 +271,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: BTreeMap::new(),
|
custom_types: CustomTypesCollection::new(),
|
||||||
empty_string: ImmutableString::new(),
|
empty_string: ImmutableString::new(),
|
||||||
disabled_symbols: BTreeSet::new(),
|
disabled_symbols: BTreeSet::new(),
|
||||||
custom_keywords: BTreeMap::new(),
|
custom_keywords: BTreeMap::new(),
|
||||||
|
@ -5,7 +5,7 @@ use crate::func::{
|
|||||||
shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction,
|
shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction,
|
||||||
SendSync,
|
SendSync,
|
||||||
};
|
};
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::{dynamic::Variant, CustomTypesCollection};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier,
|
calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier,
|
||||||
ImmutableString, NativeCallContext, RhaiResultOf, Shared, StaticVec,
|
ImmutableString, NativeCallContext, RhaiResultOf, Shared, StaticVec,
|
||||||
@ -232,6 +232,8 @@ pub struct Module {
|
|||||||
pub(crate) internal: bool,
|
pub(crate) internal: bool,
|
||||||
/// Is this module part of a standard library?
|
/// Is this module part of a standard library?
|
||||||
pub(crate) standard: bool,
|
pub(crate) standard: bool,
|
||||||
|
/// Custom types.
|
||||||
|
custom_types: CustomTypesCollection,
|
||||||
/// Sub-modules.
|
/// Sub-modules.
|
||||||
modules: BTreeMap<Identifier, Shared<Module>>,
|
modules: BTreeMap<Identifier, Shared<Module>>,
|
||||||
/// [`Module`] variables.
|
/// [`Module`] variables.
|
||||||
@ -339,6 +341,7 @@ impl Module {
|
|||||||
id: Identifier::new_const(),
|
id: Identifier::new_const(),
|
||||||
internal: false,
|
internal: false,
|
||||||
standard: false,
|
standard: false,
|
||||||
|
custom_types: CustomTypesCollection::new(),
|
||||||
modules: BTreeMap::new(),
|
modules: BTreeMap::new(),
|
||||||
variables: BTreeMap::new(),
|
variables: BTreeMap::new(),
|
||||||
all_variables: BTreeMap::new(),
|
all_variables: BTreeMap::new(),
|
||||||
@ -413,6 +416,17 @@ impl Module {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map a custom type to a friendly display name.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_custom_type<T>(&mut self, name: &str) {
|
||||||
|
self.custom_types.add_type::<T>(name)
|
||||||
|
}
|
||||||
|
/// Get the display name of a registered custom type.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
|
||||||
|
self.custom_types.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
/// Is the [`Module`] empty?
|
/// Is the [`Module`] empty?
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
43
src/types/custom_types.rs
Normal file
43
src/types/custom_types.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//! Collection of custom types.
|
||||||
|
|
||||||
|
use crate::Identifier;
|
||||||
|
use std::{any::type_name, collections::BTreeMap, fmt};
|
||||||
|
|
||||||
|
/// _(internals)_ A custom type.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
pub type CustomType = Identifier;
|
||||||
|
|
||||||
|
/// _(internals)_ A collection of custom types.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
#[derive(Clone, Hash, Default)]
|
||||||
|
pub struct CustomTypesCollection(BTreeMap<Identifier, CustomType>);
|
||||||
|
|
||||||
|
impl fmt::Debug for CustomTypesCollection {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("CustomTypesCollection ")?;
|
||||||
|
f.debug_map().entries(self.0.iter()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomTypesCollection {
|
||||||
|
/// Create a new [`CustomTypesCollection`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(BTreeMap::new())
|
||||||
|
}
|
||||||
|
/// Register a custom type.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn add(&mut self, key: impl Into<Identifier>, name: impl Into<Identifier>) {
|
||||||
|
self.0.insert(key.into(), name.into());
|
||||||
|
}
|
||||||
|
/// Register a custom type.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn add_type<T>(&mut self, name: &str) {
|
||||||
|
self.0.insert(type_name::<T>().into(), name.into());
|
||||||
|
}
|
||||||
|
/// Find a custom type.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get(&self, key: &str) -> Option<&str> {
|
||||||
|
self.0.get(key).map(CustomType::as_str)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
//! Helper module which defines the [`Any`] trait to to allow dynamic value handling.
|
//! Helper module which defines the [`Dynamic`] data type and the
|
||||||
|
//! [`Any`] trait to to allow custom type handling.
|
||||||
|
|
||||||
use crate::func::native::SendSync;
|
use crate::func::native::SendSync;
|
||||||
use crate::{reify, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, INT};
|
use crate::{reify, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, INT};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Module defining Rhai data types.
|
//! Module defining Rhai data types.
|
||||||
|
|
||||||
|
pub mod custom_types;
|
||||||
pub mod dynamic;
|
pub mod dynamic;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod fn_ptr;
|
pub mod fn_ptr;
|
||||||
@ -8,6 +9,7 @@ pub mod interner;
|
|||||||
pub mod parse_error;
|
pub mod parse_error;
|
||||||
pub mod scope;
|
pub mod scope;
|
||||||
|
|
||||||
|
pub use custom_types::{CustomType, CustomTypesCollection};
|
||||||
pub use dynamic::Dynamic;
|
pub use dynamic::Dynamic;
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub use dynamic::Instant;
|
pub use dynamic::Instant;
|
||||||
|
@ -53,9 +53,13 @@ fn test_module_sub_module() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert_eq!(m2.get_var_value::<INT>("answer").unwrap(), 41);
|
assert_eq!(m2.get_var_value::<INT>("answer").unwrap(), 41);
|
||||||
|
|
||||||
|
module.set_custom_type::<()>("Don't Panic");
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
engine.register_static_module("question", module.into());
|
engine.register_static_module("question", module.into());
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<String>("type_of(())")?, "Don't Panic");
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("question::MYSTIC_NUMBER")?, 42);
|
assert_eq!(engine.eval::<INT>("question::MYSTIC_NUMBER")?, 42);
|
||||||
assert!(engine.eval::<INT>("MYSTIC_NUMBER").is_err());
|
assert!(engine.eval::<INT>("MYSTIC_NUMBER").is_err());
|
||||||
assert_eq!(engine.eval::<INT>("question::life::universe::answer")?, 41);
|
assert_eq!(engine.eval::<INT>("question::life::universe::answer")?, 41);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user