1 /// Templates for working with Godot's type system
2 module godot.d.type;
3 
4 import godot;
5 import godot.d.traits;
6 import godot.d.reference;
7 import godot.script, godot.object;
8 
9 import std.meta;
10 
11 import sumtype;
12 
13 /// 
14 struct BuiltInClass
15 {
16 	String name;
17 }
18 
19 /// 
20 alias TypeCategories = AliasSeq!(Variant.Type, BuiltInClass, Ref!Script);
21 
22 /++
23 A specific Godot type in one of these type categories:
24 * A built-in class derived from GodotObject
25 * A Script extending GodotObject (either in D or another Godot scripting language)
26 * A Godot core type from the `godot.core` modules or a primitive (represented as a Variant.Type)
27 
28 These are all the types that can be directly stored in a Godot Variant. D types
29 that are indirectly compatible with Variant are converted to one of these when
30 passed to Godot.
31 +/
32 alias GodotType = SumType!(TypeCategories);
33 
34 /// Returns: `type` as a `T` if it is actually in type category `T`,
35 /// otherwise `defaultValue`
36 @nogc nothrow
37 T get(T)(in GodotType type, T defaultValue = T.init)
38 {
39 	return type.match!((T t) => t, _ => defaultValue);
40 }
41 
42 /// Is `type` in type category `T`?
43 @nogc nothrow
44 bool isCategory(T)(in GodotType type)
45 {
46 	return type.match!((T t) => true, _ => false);
47 }
48 
49 /// FIXME: GodotType can't currently work with String or Ref!Script at compile
50 /// time, when they're not yet loaded from Godot. That also breaks DTypeOf
51 
52 /// GodotType of a compile-time D type.
53 /// If T is indirectly compatible with Godot, this returns the Godot type T would
54 /// be converted to when passed to Godot.
55 template GodotTypeOf(T)
56 {
57 	version(none)
58 	{
59 	static if(extendsGodotBaseClass!T) enum GodotTypeOf = GodotType(NativeScriptTemplate!T.as!Script);
60 	else static if(isGodotBaseClass!T) enum GodotTypeOf = GodotType(BuiltInClass(String(T._GODOT_internal_name)));
61 	}
62 	else enum GodotTypeOf = GodotType(Variant.variantTypeOf!T);
63 }
64 
65 static assert(GodotTypeOf!int == GodotType(Variant.Type.int_));
66 static assert(GodotTypeOf!(float[]) == GodotType(Variant.Type.array));
67 static assert(GodotTypeOf!(int[4]) == GodotType(Variant.Type.array));
68 
69 /// D type of a compile-time GodotType
70 template DTypeOf(GodotType t)
71 {
72 	static if(t.isCategory!(Variant.Type))
73 	{
74 		alias DTypeOf = Variant.DType[get!(Variant.Type)(t)];
75 	}
76 	else static assert(0, "Class types aren't known at compile time because the Godot API is not yet loaded");
77 }
78 static foreach(alias C; TypeCategories) alias DTypeOf(C t) = DTypeOf!(GodotType(t));
79 
80 static assert(is(DTypeOf!(Variant.Type.int_) == long));
81 static assert(is(DTypeOf!(Variant.Type.array) == Array));
82