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