1mod function;
2pub mod generator;
3
4mod class;
5mod module;
6
7pub use class::{
8 TypedClassBuilder, TypedDataFields, TypedDataMethods, TypedUserData, WrappedBuilder,
9};
10pub use module::{TypedModule, TypedModuleBuilder, TypedModuleFields, TypedModuleMethods};
11
12use std::{
13 borrow::Cow,
14 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
15};
16
17use function::Return;
18pub use function::{Param, TypedFunction};
19
20use mlua::Variadic;
21
22pub trait Typed {
24 fn ty() -> Type;
26
27 fn as_param() -> Param {
29 Param {
30 doc: None,
31 name: None,
32 ty: Self::ty(),
33 }
34 }
35}
36
37macro_rules! impl_static_typed {
38 {
39 $(
40 $($target: ty)|*
41 => $name: literal),*
42 $(,)?
43 } => {
44 $(
45 $(
46 impl Typed for $target {
47 fn ty() -> Type {
48 Type::single($name)
49 }
50 }
51 )*
52 )*
53 };
54}
55
56macro_rules! impl_static_typed_generic {
57 {
58 $(
59 $(for<$($lt: lifetime),+> $target: ty)|*
60 => $name: literal),*
61 $(,)?
62 } => {
63 $(
64 $(
65 impl<$($lt,)+> Typed for $target {
66 fn ty() -> Type {
67 Type::single($name)
68 }
69 }
70 )*
71 )*
72 };
73}
74
75impl_static_typed! {
76 mlua::LightUserData => "lightuserdata",
77 mlua::Error => "error",
78 String | &str => "string",
79 u8 | u16 | u32 | u64 | usize | u128 | i8 | i16 | i32 | i64 | isize | i128 => "integer",
80 f32 | f64 => "number",
81 bool => "boolean",
82}
83
84impl_static_typed_generic! {
85 for<'a> Cow<'a, str> => "string",
86 for<'lua> mlua::Function<'lua> => "fun()",
87 for<'lua> mlua::AnyUserData<'lua> => "userdata",
88 for<'lua> mlua::String<'lua> => "string",
89 for<'lua> mlua::Thread<'lua> => "thread",
90}
91
92impl<T: Typed> Typed for Variadic<T> {
93 fn ty() -> Type {
95 Type::Variadic(T::ty().into())
96 }
97
98 fn as_param() -> Param {
100 Param {
101 doc: None,
102 name: Some("...".into()),
103 ty: T::ty(),
104 }
105 }
106}
107
108impl<T: Typed> Typed for Option<T> {
110 fn ty() -> Type {
111 Type::Union(vec![T::ty(), Type::Single("nil".into())])
112 }
113}
114
115impl From<&'static str> for Type {
116 fn from(value: &'static str) -> Self {
117 Type::Single(value.into())
118 }
119}
120
121impl From<Cow<'static, str>> for Type {
122 fn from(value: Cow<'static, str>) -> Self {
123 Type::Single(value.clone())
124 }
125}
126
127impl From<String> for Type {
128 fn from(value: String) -> Self {
129 Type::Single(value.into())
130 }
131}
132
133impl<I: Typed, const N: usize> Typed for [I; N] {
136 fn ty() -> Type {
137 Type::Array(I::ty().into())
138 }
139}
140impl<I: Typed> Typed for Vec<I> {
141 fn ty() -> Type {
142 Type::Array(I::ty().into())
143 }
144}
145impl<I: Typed> Typed for &[I] {
146 fn ty() -> Type {
147 Type::Array(I::ty().into())
148 }
149}
150impl<I: Typed> Typed for HashSet<I> {
151 fn ty() -> Type {
152 Type::Array(I::ty().into())
153 }
154}
155impl<I: Typed> Typed for BTreeSet<I> {
156 fn ty() -> Type {
157 Type::Array(I::ty().into())
158 }
159}
160
161impl<K, V> Typed for BTreeMap<K, V>
164where
165 K: Typed,
166 V: Typed,
167{
168 fn ty() -> Type {
169 Type::Map(K::ty().into(), V::ty().into())
170 }
171}
172impl<K, V> Typed for HashMap<K, V>
173where
174 K: Typed,
175 V: Typed,
176{
177 fn ty() -> Type {
178 Type::Map(K::ty().into(), V::ty().into())
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, strum::AsRefStr, PartialOrd, Eq, Ord)]
184pub enum Type {
185 Single(Cow<'static, str>),
192 Value(Box<Type>),
193 Alias(Box<Type>),
195 Enum(Cow<'static, str>, Vec<Type>),
198 Class(Box<TypedClassBuilder>),
201 Module(Box<TypedModuleBuilder>),
216 Tuple(Vec<Type>),
218 Struct(BTreeMap<&'static str, Type>),
219 Variadic(Box<Type>),
220 Union(Vec<Type>),
221 Array(Box<Type>),
222 Map(Box<Type>, Box<Type>),
223 Function {
224 params: Vec<Param>,
225 returns: Vec<Return>,
226 },
227}
228
229impl std::ops::BitOr for Type {
239 type Output = Self;
240
241 fn bitor(self, rhs: Self) -> Self::Output {
242 match (self, rhs) {
243 (Self::Union(mut types), Self::Union(other_types)) => {
244 for ty in other_types {
245 if !types.contains(&ty) {
246 types.push(ty);
247 }
248 }
249 Self::Union(types)
250 }
251 (Self::Union(mut types), other) => {
252 if !types.contains(&other) {
253 types.push(other)
254 }
255 Self::Union(types)
256 }
257 (current, other) => {
258 if current == other {
259 current
260 } else {
261 Self::Union(Vec::from([current, other]))
262 }
263 }
264 }
265 }
266}
267
268impl Type {
269 pub fn literal_string<T: std::fmt::Display>(value: T) -> Self {
271 Self::Single(format!("\"{value}\"").into())
272 }
273
274 pub fn literal<T: std::fmt::Display>(value: T) -> Self {
276 Self::Single(value.to_string().into())
277 }
278
279 pub fn single(value: impl Into<Cow<'static, str>>) -> Self {
281 Self::Single(value.into())
282 }
283
284 pub fn r#enum(
286 name: impl Into<Cow<'static, str>>,
287 types: impl IntoIterator<Item = Type>,
288 ) -> Self {
289 Self::Enum(name.into(), types.into_iter().collect())
290 }
291
292 pub fn alias(ty: Type) -> Self {
294 Self::Alias(Box::new(ty))
295 }
296
297 pub fn variadic(ty: Type) -> Self {
299 Self::Variadic(Box::new(ty))
300 }
301
302 pub fn array(ty: Type) -> Self {
304 Self::Array(Box::new(ty))
305 }
306
307 pub fn union(types: impl IntoIterator<Item = Type>) -> Self {
309 Self::Union(types.into_iter().collect())
310 }
311
312 pub fn tuple(types: impl IntoIterator<Item = Type>) -> Self {
314 Self::Tuple(types.into_iter().collect())
315 }
316
317 pub fn class(class: TypedClassBuilder) -> Self {
319 Self::Class(Box::new(class))
320 }
321
322 pub fn module(module: TypedModuleBuilder) -> Self {
324 Self::Module(Box::new(module))
325 }
326
327 pub fn function<Params: TypedMultiValue, Response: TypedMultiValue>() -> Self {
329 Self::Function {
330 params: Params::get_types_as_params(),
331 returns: Response::get_types()
332 .into_iter()
333 .map(|ty| Return { doc: None, ty })
334 .collect(),
335 }
336 }
337}
338
339#[macro_export]
350macro_rules! union {
351 ($($typ: expr),*) => {
352 $crate::typed::Type::Union(Vec::from([$(Type::from($typ),)*]))
353 };
354}
355
356pub trait TypedMultiValue {
358 fn get_types() -> Vec<Type> {
361 Self::get_types_as_params()
362 .into_iter()
363 .map(|v| v.ty)
364 .collect::<Vec<_>>()
365 }
366
367 fn get_types_as_returns() -> Vec<Return> {
368 Self::get_types_as_params()
369 .into_iter()
370 .map(|v| Return {
371 doc: None,
372 ty: v.ty,
373 })
374 .collect::<Vec<_>>()
375 }
376
377 fn get_types_as_params() -> Vec<Param>;
379}
380
381macro_rules! impl_typed_multi_value {
382 () => (
383 impl TypedMultiValue for () {
384 #[allow(unused_mut)]
385 #[allow(non_snake_case)]
386 fn get_types_as_params() -> Vec<Param> {
387 Vec::new()
388 }
389 }
390 );
391 ($($name:ident) +) => (
392 impl<$($name,)* > TypedMultiValue for ($($name,)*)
393 where $($name: Typed,)*
394 {
395 #[allow(unused_mut)]
396 #[allow(non_snake_case)]
397 fn get_types_as_params() -> Vec<Param> {
398 Vec::from([
399 $($name::as_param(),)*
400 ])
401 }
402 }
403 );
404}
405
406impl<A> TypedMultiValue for A
407where
408 A: Typed,
409{
410 fn get_types_as_params() -> Vec<Param> {
411 Vec::from([A::as_param()])
412 }
413}
414
415impl_typed_multi_value!(A B C D E F G H I J K L M N O P);
416impl_typed_multi_value!(A B C D E F G H I J K L M N O);
417impl_typed_multi_value!(A B C D E F G H I J K L M N);
418impl_typed_multi_value!(A B C D E F G H I J K L M);
419impl_typed_multi_value!(A B C D E F G H I J K L);
420impl_typed_multi_value!(A B C D E F G H I J K);
421impl_typed_multi_value!(A B C D E F G H I J);
422impl_typed_multi_value!(A B C D E F G H I);
423impl_typed_multi_value!(A B C D E F G H);
424impl_typed_multi_value!(A B C D E F G);
425impl_typed_multi_value!(A B C D E F);
426impl_typed_multi_value!(A B C D E);
427impl_typed_multi_value!(A B C D);
428impl_typed_multi_value!(A B C);
429impl_typed_multi_value!(A B);
430impl_typed_multi_value!(A);
431impl_typed_multi_value!();
432
433#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
435pub struct Field {
436 pub ty: Type,
437 pub doc: Option<Cow<'static, str>>,
438}
439
440#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
442pub struct Func {
443 pub params: Vec<Param>,
444 pub returns: Vec<Return>,
445 pub doc: Option<Cow<'static, str>>,
446}