1use crate::{BinOp, DynFn, RegistryAccess, Result, TypeInfo, UnOp};
2use std::borrow::Cow;
3
4pub trait EvalType: EvalTypeMethods + 'static {
5 type RefType<'a>;
6
7 fn type_info() -> TypeInfo;
8
9 fn to_ref_type<'a>(&'a self) -> Self::RefType<'a>;
10
11 fn register<Ctx: EvalType>(
12 registry: RegistryAccess<Ctx, Self>,
13 ) -> Result<()>;
14
15 fn make_dyn_fn<Ctx: EvalType>(
16 f: impl for<'a> Fn(&'a Ctx) -> Self::RefType<'a> + Clone + 'static,
17 ) -> DynFn {
18 DynFn::new::<Ctx, Self>(f)
19 }
20}
21
22pub trait EvalTypeMethods: Sized {
26 fn register_methods<Ctx: EvalType>(
27 registry: RegistryAccess<Ctx, Self>,
28 ) -> Result<()> {
29 _ = registry;
30 Ok(())
31 }
32}
33
34#[cfg(feature = "nightly")]
35impl<T: EvalType> EvalTypeMethods for T {
37 default fn register_methods<Ctx: EvalType>(
38 _registry: RegistryAccess<Ctx, Self>,
39 ) -> Result<()> {
40 Ok(())
41 }
42}
43
44#[cfg(not(feature = "nightly"))]
45impl EvalTypeMethods for () {}
46impl EvalType for () {
47 type RefType<'a> = ();
48
49 fn type_info() -> TypeInfo {
50 TypeInfo::new::<Self>("void")
51 }
52
53 fn to_ref_type<'a>(&'a self) -> Self::RefType<'a> {
54 *self
55 }
56
57 fn register<Ctx: EvalType>(
58 _registry: RegistryAccess<Ctx, Self>,
59 ) -> Result<()> {
60 Ok(())
61 }
62}
63
64#[cfg(not(feature = "nightly"))]
65impl EvalTypeMethods for i64 {}
66impl EvalType for i64 {
67 type RefType<'a> = i64;
68
69 fn type_info() -> TypeInfo {
70 TypeInfo::new::<Self>("i64")
71 }
72
73 fn to_ref_type<'a>(&'a self) -> Self::RefType<'a> {
74 *self
75 }
76
77 fn register<Ctx: EvalType>(
78 mut registry: RegistryAccess<Ctx, Self>,
79 ) -> Result<()> {
80 registry.register_cast::<f64>(|_: &Ctx, value: i64| value as f64)?;
81 registry.register_cast::<String>(|_: &Ctx, value: i64| {
82 format!("{value}").into()
83 })?;
84
85 registry
86 .register_bin_op(BinOp::Add, |_: &Ctx, lhs: i64, rhs: i64| {
87 lhs + rhs
88 })?;
89 registry
90 .register_bin_op(BinOp::Sub, |_: &Ctx, lhs: i64, rhs: i64| {
91 lhs - rhs
92 })?;
93 registry
94 .register_bin_op(BinOp::Mul, |_: &Ctx, lhs: i64, rhs: i64| {
95 lhs * rhs
96 })?;
97 registry
98 .register_bin_op(BinOp::Div, |_: &Ctx, lhs: i64, rhs: i64| {
99 lhs / rhs
100 })?;
101 registry.register_un_op(UnOp::Neg, |_: &Ctx, rhs: i64| -rhs)?;
102 registry.register_un_op(UnOp::Plus, |_: &Ctx, rhs: i64| rhs)?;
103 Ok(())
104 }
105}
106
107#[cfg(not(feature = "nightly"))]
108impl EvalTypeMethods for f64 {}
109impl EvalType for f64 {
110 type RefType<'a> = f64;
111
112 fn type_info() -> TypeInfo {
113 TypeInfo::new::<Self>("f64")
114 }
115
116 fn to_ref_type<'a>(&'a self) -> Self::RefType<'a> {
117 *self
118 }
119
120 fn register<Ctx: EvalType>(
121 mut registry: RegistryAccess<Ctx, Self>,
122 ) -> Result<()> {
123 registry.register_cast::<String>(|_: &Ctx, value: f64| {
124 format!("{value}").into()
125 })?;
126
127 registry
128 .register_bin_op(BinOp::Add, |_: &Ctx, lhs: f64, rhs: f64| {
129 lhs + rhs
130 })?;
131 registry
132 .register_bin_op(BinOp::Sub, |_: &Ctx, lhs: f64, rhs: f64| {
133 lhs - rhs
134 })?;
135 registry
136 .register_bin_op(BinOp::Mul, |_: &Ctx, lhs: f64, rhs: f64| {
137 lhs * rhs
138 })?;
139 registry
140 .register_bin_op(BinOp::Div, |_: &Ctx, lhs: f64, rhs: f64| {
141 lhs / rhs
142 })?;
143 registry.register_un_op(UnOp::Neg, |_: &Ctx, rhs: f64| -rhs)?;
144 registry.register_un_op(UnOp::Plus, |_: &Ctx, rhs: f64| rhs)?;
145 Ok(())
146 }
147}
148
149#[cfg(not(feature = "nightly"))]
150impl EvalTypeMethods for String {}
151impl EvalType for String {
152 type RefType<'a> = Cow<'a, str>;
153
154 fn type_info() -> TypeInfo {
155 TypeInfo::new::<Self>("String")
156 }
157
158 fn to_ref_type<'a>(&'a self) -> Self::RefType<'a> {
159 self.into()
160 }
161
162 fn register<Ctx: EvalType>(
163 mut registry: RegistryAccess<Ctx, Self>,
164 ) -> Result<()> {
165 registry.register_bin_op(
166 BinOp::Add,
167 |_: &Ctx, lhs: Self::RefType<'_>, rhs: Self::RefType<'_>| lhs + rhs,
168 )?;
169 Ok(())
170 }
171}
172
173macro_rules! impl_eval_type_for_tuples {
174 ( $( $name:ident ),+ ) => {
176 #[cfg(not(feature = "nightly"))]
177 impl< $( $name ),+ > EvalTypeMethods for ( $( $name ),+ ) {}
178
179 impl< $( $name ),+ > EvalType for ( $( $name ),+ )
180 where
181 $( $name: EvalType ),+
182 {
183 type RefType<'a> = &'a Self;
184
185 fn type_info() -> TypeInfo {
186 TypeInfo::new::<Self>(concat!("Tuple(", $(stringify!($name), ","),*, ")"))
187 }
188
189 fn to_ref_type<'a>(&'a self) -> Self::RefType<'a> {
190 self
191 }
192
193 fn register<Ctx: EvalType>(
194 _registry: RegistryAccess<Ctx, Self>,
195 ) -> Result<()> {
196 Ok(())
197 }
198 }
199 };
200}
201
202impl_eval_type_for_tuples!(T1, T2);
203impl_eval_type_for_tuples!(T1, T2, T3);
204impl_eval_type_for_tuples!(T1, T2, T3, T4);
205impl_eval_type_for_tuples!(T1, T2, T3, T4, T5);