1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
///The direction that the rust <-> lua conversion goes to.
///This is needed in case the FromLua and ToLua traits aren't perfect opposites of each other.

#[derive(Clone, Copy, Debug)]
pub enum Direction {
    ///Represents that the Rust type is being exposed to Lua
    FromLua,
    ///Represents that the Rust type is being constructed from Lua
    ToLua,
}

macro_rules! impl_type_name {
    ($teal_type:literal $current_type:ty) => {
        impl TypeName for $current_type {
            fn get_type_name(_ :Direction) -> Cow<'static, str> {
                Cow::from($teal_type)
            }
            fn is_external() -> bool {
                false
            }
        }
    };
    ($teal_type:literal $current_type:ty,$($types:ty),*) => {
        impl_type_name!($teal_type $current_type);
        impl_type_name!($teal_type $($types),+);
    };
}

///A trait to collect the required type information like the name of the type.
pub trait TypeName {
    ///returns the type name as how it should show up in the generated `.d.tl` file
    fn get_type_name(dir: Direction) -> Cow<'static, str>;
    ///This method tells the generator that the type will always be available
    ///This is pretty much only the case for native lua/teal types like `number`
    ///
    ///***DO NOT*** overwrite it unless you are ***ABSOLUTELY*** sure you need to.
    ///The default is correct for 99.999% of the cases.
    fn is_external() -> bool {
        true
    }
}

use std::{
    borrow::Cow,
    collections::{BTreeMap, HashMap},
};

use crate::TypeGenerator;

impl_type_name!("boolean" bool);
impl_type_name!("string" String,std::ffi::CString,bstr::BString ,&str,&std::ffi::CStr,&bstr::BStr);
impl_type_name!("number" f32,f64);
impl_type_name!("integer" i8,u8,u16,i16,u32,i32,u64,i64,u128,i128,isize,usize);

#[cfg(feature = "rlua")]
impl<'lua> TypeName for rlua::Value<'lua> {
    fn get_type_name(_: Direction) -> Cow<'static, str> {
        Cow::from("any")
    }
    fn is_external() -> bool {
        false
    }
}
#[cfg(feature = "rlua")]
impl<'lua> TypeName for rlua::Table<'lua> {
    fn get_type_name(_: Direction) -> Cow<'static, str> {
        Cow::from("{any:any}")
    }
    fn is_external() -> bool {
        false
    }
}
#[cfg(feature = "rlua")]
impl<'lua> TypeName for rlua::String<'lua> {
    fn get_type_name(_: Direction) -> Cow<'static, str> {
        Cow::from("string")
    }
    fn is_external() -> bool {
        false
    }
}
#[cfg(feature = "rlua")]
impl<'lua> TypeName for rlua::Function<'lua> {
    fn get_type_name(_: Direction) -> Cow<'static, str> {
        Cow::from("function(...:any):any...")
    }
    fn is_external() -> bool {
        false
    }
}

impl<T: TypeName> TypeName for Vec<T> {
    fn get_type_name(d: Direction) -> Cow<'static, str> {
        Cow::from(format!("{{{}}}", T::get_type_name(d)))
    }
    fn is_external() -> bool {
        false
    }
}

impl<T: TypeName> TypeName for Option<T> {
    fn get_type_name(d: Direction) -> Cow<'static, str> {
        T::get_type_name(d)
    }
    fn is_external() -> bool {
        false
    }
}

impl<K: TypeName, V: TypeName> TypeName for HashMap<K, V> {
    fn get_type_name(d: Direction) -> Cow<'static, str> {
        Cow::from(format!(
            "{{{}:{}}}",
            K::get_type_name(d),
            V::get_type_name(d)
        ))
    }
    fn is_external() -> bool {
        false
    }
}
impl<K: TypeName, V: TypeName> TypeName for BTreeMap<K, V> {
    fn get_type_name(d: Direction) -> Cow<'static, str> {
        Cow::from(format!(
            "{{{}:{}}}",
            K::get_type_name(d),
            V::get_type_name(d)
        ))
    }
    fn is_external() -> bool {
        false
    }
}
///Creates the body of the type, so the functions and fields it exposes.
pub trait TypeBody {
    ///Fills in the TypeGenerator so a .d.tl file can be constructed.
    fn get_type_body(dir: Direction, gen: &mut TypeGenerator);
}