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