1 module godot.d.reference; 2 3 import std.meta, std.traits, std.typecons; 4 import std.algorithm : swap; 5 6 import godot.core, godot.c; 7 import godot.reference, godot.object; 8 import godot.d.traits, godot.d.script; 9 10 /// Ref-counted container for Reference types 11 struct Ref(T) 12 { 13 static assert(extends!(T, Reference), "Ref may only be used with Reference-derived classes. Other Godot classes are not reference-counted."); 14 static assert(!is(T == const), "Ref cannot contain a const Reference"); 15 @nogc nothrow: 16 17 static if(isGodotBaseClass!T) 18 { 19 package(godot) T _reference; 20 alias _self = _reference; 21 } 22 else 23 { 24 package(godot) T _self; 25 pragma(inline, true) 26 package(godot) GodotClass!T _reference() 27 { 28 return (_self) ? _self.owner : GodotClass!T.init; 29 } 30 } 31 32 /++ 33 Returns the reference without allowing it to escape the calling scope. 34 35 TODO: dip1000 36 +/ 37 T refPayload() const 38 { 39 return cast()_self; 40 } 41 alias refPayload this; 42 43 ref Ref opAssign(T other) 44 { 45 if(_self.getGodotObject == other.getGodotObject) return this; 46 unref(); 47 _self = other; 48 if(_self) _reference.reference(); 49 return this; 50 } 51 ref Ref opAssign(R)(ref R other) if(is(R : Ref!U, U) && extends!(T, U)) 52 { 53 opAssign(other._self); 54 return this; 55 } 56 ref Ref opAssign(R)(R other) if(is(R : Ref!U, U) && extends!(T, U)) 57 { 58 swap(_self, other); 59 return this; 60 } 61 62 void unref() 63 { 64 if(_self && _reference.unreference()) 65 { 66 _godot_api.godot_object_destroy(_reference._godot_object); 67 } 68 _self = T.init; 69 } 70 71 Ref!U as(U)() if(isGodotClass!U && !is(U == GodotObject)) 72 { 73 // the only non-Reference this can possibly be is Object, so no need to account for non-Refs 74 static assert(extends!(U, T) || extends!(T, U), 75 U.stringof~" is not polymorphic to "~T.stringof); 76 Ref!U ret = _self.as!U; 77 return ret; 78 } 79 template as(R) if(is(R : Ref!U, U) && isGodotClass!(NonRef!R)) 80 { 81 alias as = as!(NonRef!R); 82 } 83 GodotObject as(R)() if(is(Unqual!R == GodotObject)) 84 { 85 return _reference; 86 } 87 template opCast(R) if(isGodotClass!(NonRef!R)) 88 { 89 alias opCast = as!R; 90 } 91 92 pragma(inline, true) 93 bool opEquals(R)(in auto ref R other) const 94 { 95 return _self.getGDNativeObject!T == other.getGDNativeObject!T; 96 } 97 98 pragma(inline, true) 99 bool isValid() const { return _self.getGodotObject != GodotClass!T.init; } 100 alias opCast(T : bool) = isValid; 101 pragma(inline, true) 102 bool isNull() const { return _self.getGodotObject == GodotClass!T.init; } 103 104 this(this) 105 { 106 if(_self) _reference.reference(); 107 } 108 109 /++ 110 Construct from other reference 111 +/ 112 this(T other) 113 { 114 _self = other; 115 if(_self) _reference.reference(); 116 } 117 this(R)(ref R other) if(is(R : Ref!U, U) && extends!(T, U)) 118 { 119 _self = other._self; 120 if(_self) _reference.reference(); 121 } 122 this(R)(R other) if(is(R : Ref!U, U) && extends!(T, U)) 123 { 124 swap(_self, other); 125 } 126 127 ~this() 128 { 129 unref(); 130 } 131 } 132 133 /++ 134 Create a Ref from a pointer without incrementing refcount. 135 +/ 136 package(godot) RefOrT!T refOrT(T)(T instance) 137 { 138 static if(extends!(T, Reference)) 139 { 140 Ref!T ret = void; 141 ret._self = instance; 142 return ret; 143 } 144 else return instance; 145 } 146 147 /++ 148 Create a Ref from a pointer and increment refcount. 149 +/ 150 package(godot) RefOrT!T refOrTInc(T)(T instance) 151 { 152 static if(extends!(T, Reference)) 153 { 154 Ref!T ret = void; 155 ret._self = instance; 156 if(ret._self) ret._reference.reference(); 157 return ret; 158 } 159 else return instance; 160 } 161 162