use crate::func::SendSync;
use crate::module::FuncMetadata;
use crate::packages::string_basic::{FUNC_TO_DEBUG, FUNC_TO_STRING};
use crate::types::dynamic::Variant;
use crate::{Engine, FuncRegistration, Identifier, RhaiNativeFunc, StaticVec};
use std::marker::PhantomData;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
pub trait CustomType: Variant + Clone {
fn build(builder: TypeBuilder<Self>);
}
impl Engine {
#[inline]
pub fn build_type<T: CustomType>(&mut self) -> &mut Self {
T::build(TypeBuilder::new(self));
self
}
}
pub struct TypeBuilder<'a, T: Variant + Clone> {
engine: &'a mut Engine,
hashes: StaticVec<u64>,
_marker: PhantomData<T>,
}
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
#[inline(always)]
fn new(engine: &'a mut Engine) -> Self {
Self {
engine,
hashes: StaticVec::new_const(),
_marker: PhantomData,
}
}
}
impl<T: Variant + Clone> TypeBuilder<'_, T> {
#[inline(always)]
pub fn with_name(&mut self, name: &str) -> &mut Self {
self.engine.register_type_with_name::<T>(name);
self
}
#[cfg(feature = "metadata")]
#[inline(always)]
pub fn with_comments(&mut self, comments: &[&str]) -> &mut Self {
let namespace = self.engine.global_namespace_mut();
if let Some(name) = namespace
.get_custom_type_raw::<T>()
.map(|ty| ty.display_name.clone())
{
namespace.set_custom_type_with_comments::<T>(name.as_str(), comments);
}
self
}
#[inline(always)]
pub fn on_print(
&mut self,
on_print: impl Fn(&mut T) -> String + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new(FUNC_TO_STRING).register_into_engine(self.engine, on_print);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[inline(always)]
pub fn on_debug(
&mut self,
on_debug: impl Fn(&mut T) -> String + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new(FUNC_TO_DEBUG).register_into_engine(self.engine, on_debug);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[inline(always)]
pub fn with_fn<A: 'static, const N: usize, const X: bool, R: Variant + Clone, const F: bool>(
&mut self,
name: impl AsRef<str> + Into<Identifier>,
method: impl RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new(name).register_into_engine(self.engine, method);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[cfg(feature = "metadata")]
#[inline(always)]
pub fn and_comments(&mut self, comments: &[&str]) -> &mut Self {
let module = self.engine.global_namespace_mut();
for &hash in &self.hashes {
if let Some(f) = module.get_fn_metadata_mut(hash) {
f.comments = comments.iter().map(|&s| s.into()).collect();
}
}
self
}
}
impl<T> TypeBuilder<'_, T>
where
T: Variant + Clone + IntoIterator,
<T as IntoIterator>::Item: Variant + Clone,
{
#[inline(always)]
pub fn is_iterable(&mut self) -> &mut Self {
self.engine.register_iterator::<T>();
self
}
}
#[cfg(not(feature = "no_object"))]
impl<T: Variant + Clone> TypeBuilder<'_, T> {
#[inline(always)]
pub fn with_get<const X: bool, R: Variant + Clone, const F: bool>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X, R, F> + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new_getter(name).register_into_engine(self.engine, get_fn);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[inline(always)]
pub fn with_set<const X: bool, R: Variant + Clone, const F: bool>(
&mut self,
name: impl AsRef<str>,
set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X, (), F> + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new_setter(name).register_into_engine(self.engine, set_fn);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[inline(always)]
pub fn with_get_set<
const X1: bool,
const X2: bool,
R: Variant + Clone,
const F1: bool,
const F2: bool,
>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X1, R, F1> + SendSync + 'static,
set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X2, (), F2> + SendSync + 'static,
) -> &mut Self {
let hash_1 = FuncRegistration::new_getter(&name)
.register_into_engine(self.engine, get_fn)
.hash;
let hash_2 = FuncRegistration::new_setter(&name)
.register_into_engine(self.engine, set_fn)
.hash;
self.hashes.clear();
self.hashes.push(hash_1);
self.hashes.push(hash_2);
self
}
}
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
impl<T: Variant + Clone> TypeBuilder<'_, T> {
#[inline(always)]
pub fn with_indexer_get<
IDX: Variant + Clone,
const X: bool,
R: Variant + Clone,
const F: bool,
>(
&mut self,
get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X, R, F> + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new_index_getter().register_into_engine(self.engine, get_fn);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[inline(always)]
pub fn with_indexer_set<
IDX: Variant + Clone,
const X: bool,
R: Variant + Clone,
const F: bool,
>(
&mut self,
set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X, (), F> + SendSync + 'static,
) -> &mut Self {
let FuncMetadata { hash, .. } =
FuncRegistration::new_index_setter().register_into_engine(self.engine, set_fn);
self.hashes.clear();
self.hashes.push(*hash);
self
}
#[inline(always)]
pub fn with_indexer_get_set<
IDX: Variant + Clone,
const X1: bool,
const X2: bool,
R: Variant + Clone,
const F1: bool,
const F2: bool,
>(
&mut self,
get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X1, R, F1> + SendSync + 'static,
set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X2, (), F2> + SendSync + 'static,
) -> &mut Self {
let hash_1 = FuncRegistration::new_index_getter()
.register_into_engine(self.engine, get_fn)
.hash;
let hash_2 = FuncRegistration::new_index_setter()
.register_into_engine(self.engine, set_fn)
.hash;
self.hashes.clear();
self.hashes.push(hash_1);
self.hashes.push(hash_2);
self
}
}