From b6937fd21d9142381466bdd48bfd7712a1567afd Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Mon, 8 Aug 2022 14:43:06 +0200 Subject: [PATCH 01/18] add RhaiCustomType trait and build_type method --- src/api/build_type.rs | 67 +++++++++++++++++++++++++++++++++++++++++++ src/api/mod.rs | 2 ++ src/lib.rs | 2 +- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/api/build_type.rs diff --git a/src/api/build_type.rs b/src/api/build_type.rs new file mode 100644 index 00000000..785034e1 --- /dev/null +++ b/src/api/build_type.rs @@ -0,0 +1,67 @@ +use crate::Engine; + +/// Trait to build a custom type for use with the [`Engine`]. +/// i.e. register the type, getters, setters, methods, etc... +/// +/// # Example +/// +/// ``` +/// use rhai::{Engine, RhaiCustomType}; +/// +/// #[derive(Debug, Clone, Eq, PartialEq)] +/// struct TestStruct { +/// field: i64 +/// } +/// +/// impl TestStruct { +/// fn new() -> Self { +/// Self { field: 1 } +/// } +/// fn update(&mut self, offset: i64) { +/// self.field += offset; +/// } +/// } +/// +/// impl RhaiCustomType for TestStruct { +/// fn build(engine: &mut Engine) { +/// engine +/// .register_type::() +/// .register_fn("new_ts", Self::new) +/// .register_fn("update", Self::update); +/// } +/// } +/// +/// # fn main() -> Result<(), Box> { +/// +/// let mut engine = Engine::new(); +/// +/// // Register API for the custom type. +/// engine.build_type::(); +/// +/// # #[cfg(not(feature = "no_object"))] +/// assert_eq!( +/// engine.eval::("let x = new_ts(); x.update(41); x")?, +/// TestStruct { field: 42 } +/// ); +/// # Ok(()) +/// # } +/// ``` +pub trait RhaiCustomType { + /// Builds the custom type for use with the [`Engine`]. + /// i.e. register the type, getters, setters, methods, etc... + fn build(engine: &mut Engine); +} + +impl Engine { + /// Build a custom type for use with the [`Engine`]. + /// i.e. register the type, getters, setters, methods, etc... + /// + /// See [`RhaiCustomType`]. + pub fn build_type(&mut self) -> &mut Self + where + T: RhaiCustomType, + { + T::build(self); + self + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index f24777c6..635082dd 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -28,6 +28,8 @@ pub mod custom_syntax; pub mod deprecated; +pub mod build_type; + #[cfg(feature = "metadata")] pub mod definitions; diff --git a/src/lib.rs b/src/lib.rs index 9ad7317f..0a19d5fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,7 +166,7 @@ type ExclusiveRange = std::ops::Range; /// An inclusive integer range. type InclusiveRange = std::ops::RangeInclusive; -pub use api::events::VarDefInfo; +pub use api::{build_type::RhaiCustomType, events::VarDefInfo}; pub use ast::{FnAccess, AST}; pub use engine::{Engine, OP_CONTAINS, OP_EQUALS}; pub use eval::EvalContext; From 1ccb5c0f26defdb31fcf0b47d1d536e1f63c84cf Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Mon, 8 Aug 2022 15:12:43 +0200 Subject: [PATCH 02/18] rename RhaiCustomType to CustomType --- src/api/build_type.rs | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 785034e1..13e05c4e 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -46,7 +46,7 @@ use crate::Engine; /// # Ok(()) /// # } /// ``` -pub trait RhaiCustomType { +pub trait CustomType { /// Builds the custom type for use with the [`Engine`]. /// i.e. register the type, getters, setters, methods, etc... fn build(engine: &mut Engine); @@ -59,7 +59,7 @@ impl Engine { /// See [`RhaiCustomType`]. pub fn build_type(&mut self) -> &mut Self where - T: RhaiCustomType, + T: CustomType, { T::build(self); self diff --git a/src/lib.rs b/src/lib.rs index 0a19d5fc..cf7d0a04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,7 +166,7 @@ type ExclusiveRange = std::ops::Range; /// An inclusive integer range. type InclusiveRange = std::ops::RangeInclusive; -pub use api::{build_type::RhaiCustomType, events::VarDefInfo}; +pub use api::{build_type::CustomType, events::VarDefInfo}; pub use ast::{FnAccess, AST}; pub use engine::{Engine, OP_CONTAINS, OP_EQUALS}; pub use eval::EvalContext; From 74c26a8c710ea8a39a0a2392f274e30bafc48454 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Mon, 8 Aug 2022 17:29:03 +0200 Subject: [PATCH 03/18] fix doc --- src/api/build_type.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 13e05c4e..b50612b1 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -6,7 +6,7 @@ use crate::Engine; /// # Example /// /// ``` -/// use rhai::{Engine, RhaiCustomType}; +/// use rhai::{Engine, CustomType}; /// /// #[derive(Debug, Clone, Eq, PartialEq)] /// struct TestStruct { @@ -22,7 +22,7 @@ use crate::Engine; /// } /// } /// -/// impl RhaiCustomType for TestStruct { +/// impl CustomType for TestStruct { /// fn build(engine: &mut Engine) { /// engine /// .register_type::() From efee24beeeb9d8dd9cb66498ddd055eef6bcd2e8 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Mon, 8 Aug 2022 17:30:00 +0200 Subject: [PATCH 04/18] actually fix doc --- src/api/build_type.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index b50612b1..30190032 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -56,7 +56,7 @@ impl Engine { /// Build a custom type for use with the [`Engine`]. /// i.e. register the type, getters, setters, methods, etc... /// - /// See [`RhaiCustomType`]. + /// See [`CustomType`]. pub fn build_type(&mut self) -> &mut Self where T: CustomType, From 4432d5063a44c082d1f20c4c4889865b927ed7d9 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Mon, 8 Aug 2022 17:39:15 +0200 Subject: [PATCH 05/18] impl TypeBuilder --- src/api/build_type.rs | 192 +++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 5 +- tests/build_type.rs | 118 ++++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 12 deletions(-) create mode 100644 tests/build_type.rs diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 13e05c4e..dc84f80d 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -1,4 +1,9 @@ -use crate::Engine; +use core::marker::PhantomData; + +use crate::{ + func::SendSync, types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction, + RhaiResultOf, +}; /// Trait to build a custom type for use with the [`Engine`]. /// i.e. register the type, getters, setters, methods, etc... @@ -6,7 +11,7 @@ use crate::Engine; /// # Example /// /// ``` -/// use rhai::{Engine, RhaiCustomType}; +/// use rhai::{CustomType, TypeBuilder, Engine}; /// /// #[derive(Debug, Clone, Eq, PartialEq)] /// struct TestStruct { @@ -20,14 +25,21 @@ use crate::Engine; /// fn update(&mut self, offset: i64) { /// self.field += offset; /// } +/// fn get_value(&mut self) -> i64 { +/// self.field +/// } +/// fn set_value(&mut self, value: i64) { +/// self.field = value; +/// } /// } /// -/// impl RhaiCustomType for TestStruct { -/// fn build(engine: &mut Engine) { -/// engine -/// .register_type::() -/// .register_fn("new_ts", Self::new) -/// .register_fn("update", Self::update); +/// impl CustomType for TestStruct { +/// fn build(mut builder: TypeBuilder) { +/// builder +/// .with_name("TestStruct") +/// .with_fn("new_ts", Self::new) +/// .with_fn("update", Self::update) +/// .with_get_set("value", Self::get_value, Self::set_value); /// } /// } /// @@ -38,18 +50,25 @@ use crate::Engine; /// // Register API for the custom type. /// engine.build_type::(); /// +/// /// # #[cfg(not(feature = "no_object"))] /// assert_eq!( /// engine.eval::("let x = new_ts(); x.update(41); x")?, /// TestStruct { field: 42 } /// ); +/// +/// # #[cfg(not(feature = "no_object"))] +/// assert_eq!( +/// engine.eval::("let x = new_ts(); x.value = 5 + x.value; x")?, +/// TestStruct { field: 6 } +/// ); /// # Ok(()) /// # } /// ``` -pub trait CustomType { +pub trait CustomType: Variant + Clone { /// Builds the custom type for use with the [`Engine`]. /// i.e. register the type, getters, setters, methods, etc... - fn build(engine: &mut Engine); + fn build(builder: TypeBuilder); } impl Engine { @@ -61,7 +80,158 @@ impl Engine { where T: CustomType, { - T::build(self); + T::build(TypeBuilder::new(self)); self } } + +#[allow(missing_docs)] // TODO: add docs +pub struct TypeBuilder<'a, T> +where + T: Variant + Clone, +{ + engine: &'a mut Engine, + name: Option<&'static str>, + _marker: PhantomData, +} + +#[allow(missing_docs)] // TODO: add docs +impl<'a, T> TypeBuilder<'a, T> +where + T: Variant + Clone, +{ + pub(crate) fn new(engine: &'a mut Engine) -> Self { + Self { + engine, + name: None, + _marker: PhantomData::default(), + } + } + + pub fn build(self) { + /* empty */ + } + + pub fn with_name(&mut self, name: &'static str) -> &mut Self { + self.name = Some(name); + self + } + + pub fn with_fn(&mut self, name: N, method: F) -> &mut Self + where + N: AsRef + Into, + F: RegisterNativeFunction, + { + self.engine.register_fn(name, method); + self + } + + pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self + where + N: AsRef + Into, + F: RegisterNativeFunction>, + { + self.engine.register_result_fn(name, method); + self + } + + pub fn with_get( + &mut self, + name: impl AsRef, + get_fn: impl Fn(&mut T) -> V + SendSync + 'static, + ) -> &mut Self { + self.engine.register_get(name, get_fn); + self + } + + pub fn with_get_result( + &mut self, + name: impl AsRef, + get_fn: impl Fn(&mut T) -> RhaiResultOf + SendSync + 'static, + ) -> &mut Self { + self.engine.register_get_result(name, get_fn); + self + } + + pub fn with_set( + &mut self, + name: impl AsRef, + set_fn: impl Fn(&mut T, V) + SendSync + 'static, + ) -> &mut Self { + self.engine.register_set(name, set_fn); + self + } + + pub fn with_set_result( + &mut self, + name: impl AsRef, + set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + SendSync + 'static, + ) -> &mut Self { + self.engine.register_set_result(name, set_fn); + self + } + + pub fn with_get_set( + &mut self, + name: impl AsRef, + get_fn: impl Fn(&mut T) -> V + SendSync + 'static, + set_fn: impl Fn(&mut T, V) + SendSync + 'static, + ) -> &mut Self { + self.engine.register_get_set(name, get_fn, set_fn); + self + } + + pub fn with_indexer_get( + &mut self, + get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, + ) -> &mut Self { + self.engine.register_indexer_get(get_fn); + self + } + + pub fn with_indexer_get_result( + &mut self, + get_fn: impl Fn(&mut T, X) -> RhaiResultOf + SendSync + 'static, + ) -> &mut Self { + self.engine.register_indexer_get_result(get_fn); + self + } + + pub fn with_indexer_set( + &mut self, + set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, + ) -> &mut Self { + self.engine.register_indexer_set(set_fn); + self + } + + pub fn with_indexer_set_result( + &mut self, + set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static, + ) -> &mut Self { + self.engine.register_indexer_set_result(set_fn); + self + } + + pub fn with_indexer_get_set( + &mut self, + get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, + set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, + ) -> &mut Self { + self.engine.register_indexer_get_set(get_fn, set_fn); + self + } +} + +impl<'a, T> Drop for TypeBuilder<'a, T> +where + T: Variant + Clone, +{ + fn drop(&mut self) { + if let Some(name) = self.name { + self.engine.register_type_with_name::(name); + } else { + self.engine.register_type::(); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index cf7d0a04..875e1cad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,7 +166,10 @@ type ExclusiveRange = std::ops::Range; /// An inclusive integer range. type InclusiveRange = std::ops::RangeInclusive; -pub use api::{build_type::CustomType, events::VarDefInfo}; +pub use api::{ + build_type::{CustomType, TypeBuilder}, + events::VarDefInfo, +}; pub use ast::{FnAccess, AST}; pub use engine::{Engine, OP_CONTAINS, OP_EQUALS}; pub use eval::EvalContext; diff --git a/tests/build_type.rs b/tests/build_type.rs new file mode 100644 index 00000000..76d1bcac --- /dev/null +++ b/tests/build_type.rs @@ -0,0 +1,118 @@ +use rhai::{CustomType, Engine, EvalAltResult, Position, TypeBuilder}; + +#[test] +fn build_type() -> Result<(), Box> { + #[derive(Debug, Clone, PartialEq)] + struct Vec3 { + x: i64, + y: i64, + z: i64, + } + + impl Vec3 { + fn new(x: i64, y: i64, z: i64) -> Self { + Self { x, y, z } + } + fn get_x(&mut self) -> i64 { + self.x + } + fn set_x(&mut self, x: i64) { + self.x = x + } + fn get_y(&mut self) -> i64 { + self.y + } + fn set_y(&mut self, y: i64) { + self.y = y + } + fn get_z(&mut self) -> i64 { + self.z + } + fn set_z(&mut self, z: i64) { + self.z = z + } + fn get_component(&mut self, idx: i64) -> Result> { + match idx { + 0 => Ok(self.x), + 1 => Ok(self.y), + 2 => Ok(self.z), + _ => Err(Box::new(EvalAltResult::ErrorIndexNotFound( + idx.into(), + Position::NONE, + ))), + } + } + } + + impl CustomType for Vec3 { + fn build(mut builder: TypeBuilder) { + builder + .with_name("Vec3") + .with_fn("vec3", Self::new) + .with_get_set("x", Self::get_x, Self::set_x) + .with_get_set("y", Self::get_y, Self::set_y) + .with_get_set("z", Self::get_z, Self::set_z) + .with_indexer_get_result(Self::get_component); + } + } + + let mut engine = Engine::new(); + engine.build_type::(); + + assert_eq!( + engine.eval::( + r#" + let v = vec3(1, 2, 3); + v +"#, + )?, + Vec3::new(1, 2, 3), + ); + assert_eq!( + engine.eval::( + r#" + let v = vec3(1, 2, 3); + v.x +"#, + )?, + 1, + ); + assert_eq!( + engine.eval::( + r#" + let v = vec3(1, 2, 3); + v.y +"#, + )?, + 2, + ); + assert_eq!( + engine.eval::( + r#" + let v = vec3(1, 2, 3); + v.z +"#, + )?, + 3, + ); + assert!(engine.eval::( + r#" + let v = vec3(1, 2, 3); + v.x == v[0] && v.y == v[1] && v.z == v[2] +"#, + )?); + assert_eq!( + engine.eval::( + r#" + let v = vec3(1, 2, 3); + v.x = 5; + v.y = 6; + v.z = 7; + v +"#, + )?, + Vec3::new(5, 6, 7), + ); + + Ok(()) +} From acbda7f66c644ec9dfe06688f3fa179431d56c47 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 09:43:12 +0200 Subject: [PATCH 06/18] fix doc typo --- src/api/build_type.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index dc84f80d..a7e5dc30 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -75,7 +75,7 @@ impl Engine { /// Build a custom type for use with the [`Engine`]. /// i.e. register the type, getters, setters, methods, etc... /// - /// See [`RhaiCustomType`]. + /// See [`CustomType`]. pub fn build_type(&mut self) -> &mut Self where T: CustomType, From 87baed717f1b4a45676f9774a513edb1944c9be4 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 09:44:01 +0200 Subject: [PATCH 07/18] make TypeBuilder::new private --- src/api/build_type.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index a7e5dc30..7bc8d52a 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -100,7 +100,7 @@ impl<'a, T> TypeBuilder<'a, T> where T: Variant + Clone, { - pub(crate) fn new(engine: &'a mut Engine) -> Self { + fn new(engine: &'a mut Engine) -> Self { Self { engine, name: None, From 6b2d9d2cdd75c00c450e2e53e1d4fa3a61e6b537 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 09:44:16 +0200 Subject: [PATCH 08/18] rm TypeBuilder::build --- src/api/build_type.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 7bc8d52a..d22d1142 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -108,10 +108,6 @@ where } } - pub fn build(self) { - /* empty */ - } - pub fn with_name(&mut self, name: &'static str) -> &mut Self { self.name = Some(name); self From de7efa18a56ce7f963d0ae2e02e0ef09f54da467 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 09:48:46 +0200 Subject: [PATCH 09/18] add volatile api notes --- src/api/build_type.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index d22d1142..ce192367 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -76,6 +76,7 @@ impl Engine { /// i.e. register the type, getters, setters, methods, etc... /// /// See [`CustomType`]. + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn build_type(&mut self) -> &mut Self where T: CustomType, @@ -108,11 +109,13 @@ where } } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_name(&mut self, name: &'static str) -> &mut Self { self.name = Some(name); self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, @@ -122,6 +125,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, @@ -131,6 +135,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_get( &mut self, name: impl AsRef, @@ -140,6 +145,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_get_result( &mut self, name: impl AsRef, @@ -149,6 +155,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_set( &mut self, name: impl AsRef, @@ -158,6 +165,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_set_result( &mut self, name: impl AsRef, @@ -167,6 +175,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_get_set( &mut self, name: impl AsRef, @@ -177,6 +186,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_get( &mut self, get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, @@ -185,6 +195,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_get_result( &mut self, get_fn: impl Fn(&mut T, X) -> RhaiResultOf + SendSync + 'static, @@ -193,6 +204,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_set( &mut self, set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, @@ -201,6 +213,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_set_result( &mut self, set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static, @@ -209,6 +222,7 @@ where self } + #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_get_set( &mut self, get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, From addefec17c46ff53d5b3da9ea54caa7dba2f146b Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 09:49:55 +0200 Subject: [PATCH 10/18] TypeBuilder : split pub/private api impl block --- src/api/build_type.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index ce192367..484aa95a 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -96,7 +96,6 @@ where _marker: PhantomData, } -#[allow(missing_docs)] // TODO: add docs impl<'a, T> TypeBuilder<'a, T> where T: Variant + Clone, @@ -108,7 +107,13 @@ where _marker: PhantomData::default(), } } +} +#[allow(missing_docs)] // TODO: add docs +impl<'a, T> TypeBuilder<'a, T> +where + T: Variant + Clone, +{ #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_name(&mut self, name: &'static str) -> &mut Self { self.name = Some(name); From 19dc368cfd9b150f04007e141dedfe545b4a7c12 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:08:56 +0200 Subject: [PATCH 11/18] add docs --- src/api/build_type.rs | 57 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 484aa95a..3385b187 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -6,7 +6,7 @@ use crate::{ }; /// Trait to build a custom type for use with the [`Engine`]. -/// i.e. register the type, getters, setters, methods, etc... +/// i.e. register the type and its getters, setters, methods, etc... /// /// # Example /// @@ -73,7 +73,7 @@ pub trait CustomType: Variant + Clone { impl Engine { /// Build a custom type for use with the [`Engine`]. - /// i.e. register the type, getters, setters, methods, etc... + /// i.e. register the type and its getters, setters, methods, etc... /// /// See [`CustomType`]. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] @@ -86,7 +86,14 @@ impl Engine { } } -#[allow(missing_docs)] // TODO: add docs +/// Builder to build a custom type i.e. register this type and its getters, setters, methods, etc... +/// +/// The type is automatically registered when this builder is dropped. +/// +/// ## Pretty name +/// By default the type is registered with [`Engine::register_type`] i.e. without a pretty name. +/// +/// To define a pretty name call `.with_name`, in this case [`Engine::register_type_with_name`] will be used. pub struct TypeBuilder<'a, T> where T: Variant + Clone, @@ -109,17 +116,18 @@ where } } -#[allow(missing_docs)] // TODO: add docs impl<'a, T> TypeBuilder<'a, T> where T: Variant + Clone, { + /// Sets a pretty-print name for the `type_of` function. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_name(&mut self, name: &'static str) -> &mut Self { self.name = Some(name); self } + /// Register a custom function. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_fn(&mut self, name: N, method: F) -> &mut Self where @@ -130,6 +138,7 @@ where self } + /// Register a custom fallible function. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self where @@ -140,6 +149,11 @@ where self } + /// Register a getter function. + /// + /// The function signature must start with `&mut self` and not `&self`. + /// + /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_get( &mut self, @@ -150,6 +164,11 @@ where self } + /// Register a fallible getter function. + /// + /// The function signature must start with `&mut self` and not `&self`. + /// + /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_get_result( &mut self, @@ -160,6 +179,9 @@ where self } + /// Register a setter function. + /// + /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_set( &mut self, @@ -170,6 +192,9 @@ where self } + /// Register a fallible setter function. + /// + /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_set_result( &mut self, @@ -180,6 +205,11 @@ where self } + /// Short-hand for registering both getter and setter functions. + /// + /// All function signatures must start with `&mut self` and not `&self`. + /// + /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_get_set( &mut self, @@ -191,6 +221,11 @@ where self } + /// Register an index getter. + /// + /// The function signature must start with `&mut self` and not `&self`. + /// + /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_get( &mut self, @@ -200,6 +235,11 @@ where self } + /// Register an index getter. + /// + /// The function signature must start with `&mut self` and not `&self`. + /// + /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_get_result( &mut self, @@ -209,6 +249,9 @@ where self } + /// Register an index setter. + /// + /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_set( &mut self, @@ -218,6 +261,9 @@ where self } + /// Register an index setter. + /// + /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_set_result( &mut self, @@ -227,6 +273,9 @@ where self } + /// Short-hand for registering both index getter and setter functions. + /// + /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] pub fn with_indexer_get_set( &mut self, From e4e315fb2a0d26941e137dcc93181a3ac1660a15 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:14:18 +0200 Subject: [PATCH 12/18] add cfg --- src/api/build_type.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 3385b187..c93da739 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -148,7 +148,13 @@ where self.engine.register_result_fn(name, method); self } +} +#[cfg(not(feature = "no_object"))] +impl<'a, T> TypeBuilder<'a, T> +where + T: Variant + Clone, +{ /// Register a getter function. /// /// The function signature must start with `&mut self` and not `&self`. @@ -220,7 +226,13 @@ where self.engine.register_get_set(name, get_fn, set_fn); self } +} +#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] +impl<'a, T> TypeBuilder<'a, T> +where + T: Variant + Clone, +{ /// Register an index getter. /// /// The function signature must start with `&mut self` and not `&self`. From 5370031068f188563183d02189caf38a4c6b2f3b Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:15:49 +0200 Subject: [PATCH 13/18] inline methods --- src/api/build_type.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index c93da739..8f8cc497 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -77,6 +77,7 @@ impl Engine { /// /// See [`CustomType`]. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn build_type(&mut self) -> &mut Self where T: CustomType, @@ -107,6 +108,7 @@ impl<'a, T> TypeBuilder<'a, T> where T: Variant + Clone, { + #[inline] fn new(engine: &'a mut Engine) -> Self { Self { engine, @@ -161,6 +163,7 @@ where /// /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_get( &mut self, name: impl AsRef, @@ -176,6 +179,7 @@ where /// /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_get_result( &mut self, name: impl AsRef, @@ -189,6 +193,7 @@ where /// /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_set( &mut self, name: impl AsRef, @@ -202,6 +207,7 @@ where /// /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_set_result( &mut self, name: impl AsRef, @@ -217,6 +223,7 @@ where /// /// Not available under `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_get_set( &mut self, name: impl AsRef, @@ -239,6 +246,7 @@ where /// /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_indexer_get( &mut self, get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, @@ -253,6 +261,7 @@ where /// /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_indexer_get_result( &mut self, get_fn: impl Fn(&mut T, X) -> RhaiResultOf + SendSync + 'static, @@ -265,6 +274,7 @@ where /// /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_indexer_set( &mut self, set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, @@ -277,6 +287,7 @@ where /// /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_indexer_set_result( &mut self, set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static, @@ -289,6 +300,7 @@ where /// /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_indexer_get_set( &mut self, get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, @@ -303,6 +315,7 @@ impl<'a, T> Drop for TypeBuilder<'a, T> where T: Variant + Clone, { + #[inline] fn drop(&mut self) { if let Some(name) = self.name { self.engine.register_type_with_name::(name); From 6d400b747a180e965f3e9e5f92b3e4104d861d49 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:16:34 +0200 Subject: [PATCH 14/18] fix doc --- src/api/build_type.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 8f8cc497..2ac83b3f 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -255,7 +255,7 @@ where self } - /// Register an index getter. + /// Register an fallible index getter. /// /// The function signature must start with `&mut self` and not `&self`. /// @@ -283,7 +283,7 @@ where self } - /// Register an index setter. + /// Register an fallible index setter. /// /// Not available under both `no_index` and `no_object`. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] From c29d3c35a3281fcc2b4a6d8a7de9273a7fc4b3c1 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:19:15 +0200 Subject: [PATCH 15/18] add missing inlines --- src/api/build_type.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 2ac83b3f..98cc8645 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -124,6 +124,7 @@ where { /// Sets a pretty-print name for the `type_of` function. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_name(&mut self, name: &'static str) -> &mut Self { self.name = Some(name); self @@ -131,6 +132,7 @@ where /// Register a custom function. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, @@ -142,6 +144,7 @@ where /// Register a custom fallible function. #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] + #[inline] pub fn with_result_fn(&mut self, name: N, method: F) -> &mut Self where N: AsRef + Into, From 5eaa2a3d7eebef1699bced02564233cda4ebec94 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:36:33 +0200 Subject: [PATCH 16/18] add example --- examples/README.md | 15 +++----- examples/custom_types.rs | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 examples/custom_types.rs diff --git a/examples/README.md b/examples/README.md index 17c379fe..1a9aa392 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,14 +1,13 @@ -Sample Applications -=================== +# Sample Applications -Standard Examples ------------------ +## Standard Examples | Example | Description | | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | [`arrays_and_structs`](arrays_and_structs.rs) | shows how to register a Rust type and using it with arrays | | [`callback`](callback.rs) | shows how to store a Rhai closure and call it later within Rust | | [`custom_types_and_methods`](custom_types_and_methods.rs) | shows how to register a Rust type and methods/getters/setters for it | +| [`custom_types`](custom_types.rs) | shows how to register a Rust type and methods/getters/setters using the `CustomType` trait. | | [`definitions`](./definitions) | shows how to generate definition files for use with the [Rhai Language Server](https://github.com/rhaiscript/lsp) (requires the `metadata` feature) | | [`hello`](hello.rs) | simple example that evaluates an expression and prints the result | | [`reuse_scope`](reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common `Scope` | @@ -17,9 +16,7 @@ Standard Examples | [`strings`](strings.rs) | shows different ways to register Rust functions taking string arguments | | [`threading`](threading.rs) | shows how to communicate with an `Engine` running in a separate thread via an MPSC channel | - -Scriptable Event Handler With State Examples -------------------------------------------- +## Scriptable Event Handler With State Examples Because of its popularity, included are sample implementations for the pattern [_Scriptable Event Handler With State_](https://rhai.rs/book/patterns/events.html) in different styles. @@ -30,9 +27,7 @@ Because of its popularity, included are sample implementations for the pattern | [`event_handler_js`](event_handler_js) | [`event_handler_js/script.rhai`](event_handler_js/script.rhai) | [_JS Style_](https://rhai.rs/book/patterns/events-2.html) | | [`event_handler_map`](event_handler_map) | [`event_handler_map/script.rhai`](event_handler_map/script.rhai) | [_Map Style_](https://rhai.rs/book/patterns/events-3.html) | - -Running Examples ----------------- +## Running Examples Examples can be run with the following command: diff --git a/examples/custom_types.rs b/examples/custom_types.rs new file mode 100644 index 00000000..86888c8f --- /dev/null +++ b/examples/custom_types.rs @@ -0,0 +1,75 @@ +//! An example showing how to register a Rust type and methods/getters/setters using the `CustomType` trait. + +#[cfg(feature = "no_object")] +fn main() { + panic!("This example does not run under 'no_object'."); +} + +use rhai::{CustomType, Engine, EvalAltResult, TypeBuilder}; + +#[cfg(not(feature = "no_object"))] +fn main() -> Result<(), Box> { + #[derive(Debug, Clone)] + struct TestStruct { + x: i64, + } + + impl TestStruct { + pub fn new() -> Self { + Self { x: 1 } + } + pub fn update(&mut self) { + self.x += 1000; + } + pub fn calculate(&mut self, data: i64) -> i64 { + self.x * data + } + pub fn get_x(&mut self) -> i64 { + self.x + } + pub fn set_x(&mut self, value: i64) { + self.x = value; + } + } + + impl CustomType for TestStruct { + fn build(mut builder: TypeBuilder) { + #[allow(deprecated)] // The TypeBuilder api is volatile. + builder + .with_name("TestStruct") + .with_fn("new_ts", Self::new) + .with_fn("update", Self::update) + .with_fn("calc", Self::calculate) + .with_get_set("x", Self::get_x, Self::set_x); + } + } + + let mut engine = Engine::new(); + + engine.build_type::(); + + #[cfg(feature = "metadata")] + { + println!("Functions registered:"); + + engine + .gen_fn_signatures(false) + .into_iter() + .for_each(|func| println!("{}", func)); + + println!(); + } + + let result = engine.eval::( + " + let x = new_ts(); + x.x = 42; + x.update(); + x.calc(x.x) + ", + )?; + + println!("result: {}", result); // prints 1085764 + + Ok(()) +} From 217ca799305bdd0df023485e25509a3ea938a634 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:36:58 +0200 Subject: [PATCH 17/18] rm volatile note on Engine::build_type --- src/api/build_type.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index 98cc8645..f442af56 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -76,7 +76,6 @@ impl Engine { /// i.e. register the type and its getters, setters, methods, etc... /// /// See [`CustomType`]. - #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."] #[inline] pub fn build_type(&mut self) -> &mut Self where From 35c2caab07e6dda3e2b7ea8443036e8b50ec7b15 Mon Sep 17 00:00:00 2001 From: Tristan Guichaoua Date: Tue, 9 Aug 2022 10:47:53 +0200 Subject: [PATCH 18/18] fix doc --- src/api/build_type.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/api/build_type.rs b/src/api/build_type.rs index f442af56..cf44e51e 100644 --- a/src/api/build_type.rs +++ b/src/api/build_type.rs @@ -38,8 +38,7 @@ use crate::{ /// builder /// .with_name("TestStruct") /// .with_fn("new_ts", Self::new) -/// .with_fn("update", Self::update) -/// .with_get_set("value", Self::get_value, Self::set_value); +/// .with_fn("update", Self::update); /// } /// } /// @@ -57,11 +56,6 @@ use crate::{ /// TestStruct { field: 42 } /// ); /// -/// # #[cfg(not(feature = "no_object"))] -/// assert_eq!( -/// engine.eval::("let x = new_ts(); x.value = 5 + x.value; x")?, -/// TestStruct { field: 6 } -/// ); /// # Ok(()) /// # } /// ```