diff --git a/jsvar.d b/jsvar.d index 28418b4..20948c7 100644 --- a/jsvar.d +++ b/jsvar.d @@ -82,6 +82,8 @@ +/ module arsd.jsvar; +import arsd.core; + version=new_std_json; static import std.array; @@ -545,9 +547,43 @@ private var _op(alias _this, alias this2, string op, T)(T t) if(op != "~") { assert(0); } +// a plain `compiles(T(var))` check can be triggered by an implicit cast +// which we don't want due to endless recursion so this more specific check +// are better than that anyway +private template hasVarConstructor(T) { + bool helper() { + static if(is(T == struct) || is(T == class)) + static if(__traits(hasMember, T, "__ctor")) + foreach(overload; __traits(getOverloads, T, "__ctor")) + static if(is(typeof(overload) Params == __parameters)) + static if(Params.length == 1) + static if(is(Params[0] == var)) + return true; + return false; + } + + enum bool hasVarConstructor = helper(); +} + +unittest { + assert(hasVarConstructor!string == false); + + static struct A { + this(var a) {} + } + + static struct B { + this(int a) {} + } + + assert(hasVarConstructor!A == true); + assert(hasVarConstructor!B == false); +} + /// struct var { + @implicit public this(T)(T t) { static if(is(T == var)) this = t; @@ -555,6 +591,10 @@ struct var { this.opAssign(t); } + T opImplicitCast(T)() { + return this.get!T; + } + // used by the script interpreter... does a .dup on array, new on class if possible, otherwise copies members. public var _copy_new() { if(payloadType() == Type.Object) { @@ -990,9 +1030,9 @@ struct var { return this; } else static if(__traits(compiles, T.fromJsVar(var.init))) { return T.fromJsVar(this); - } else static if(__traits(compiles, T(this))) { + } else static if(hasVarConstructor!T && __traits(compiles, T(this))) { return T(this); - } else static if(__traits(compiles, new T(this))) { + } else static if(hasVarConstructor!T && __traits(compiles, new T(this))) { return new T(this); } else static if(is(T == Nullable!N, N)) { if(payloadType == Type.Object && this._payload._object is null)