1 module awebview.wrapper.jsvalue; 2 3 import std.conv; 4 import std.format; 5 import std.range; 6 import std.utf; 7 import std.traits; 8 9 import awebview.wrapper.cpp; 10 import awebview.wrapper.jsobject : JSObject; 11 import awebview.wrapper.jsarray : JSArray, JSArrayCpp; 12 import awebview.wrapper.jsarray; 13 import awebview.wrapper.jsobject; 14 import awebview.wrapper.webstring : WebString; 15 import awebview.wrapper.constants; 16 import awebview.wrapper.weakref; 17 18 import carbon.templates; 19 import carbon.nonametype; 20 21 22 struct JSValue 23 { 24 this(bool b) nothrow @nogc { JSValueMember.ctor(this.cppObj!false, b); } 25 this(int v) nothrow @nogc { JSValueMember.ctor(this.cppObj!false, v); } 26 this(double v) nothrow @nogc { JSValueMember.ctor(this.cppObj!false, v); } 27 28 this(const awebview.wrapper.cpp.WebString ws) nothrow @nogc 29 { 30 JSValueMember.ctor(this.cppObj!false, ws); 31 } 32 33 this()(auto ref const WebString ws) nothrow @nogc { this(ws.cppObj); } 34 35 this(Char)(in Char[] str) nothrow @nogc 36 if(isSomeChar!Char) { this(WebString(str)); } 37 38 this(const awebview.wrapper.cpp.JSObject jso) nothrow @nogc 39 { 40 JSValueMember.ctor(this.cppObj!false, jso); 41 } 42 43 this()(auto ref const JSObject jo) nothrow @nogc { this(jo.cppObj); } 44 45 this(const awebview.wrapper.cpp.JSArray jsarr) nothrow @nogc 46 { 47 JSValueMember.ctor(this.cppObj!false, jsarr); 48 } 49 50 this()(auto ref const JSArray ja) nothrow @nogc { this(ja.cppObj); } 51 52 this(const awebview.wrapper.cpp.JSValue v) nothrow @nogc 53 { 54 JSValueMember.ctor(this.cppObj!false, v); 55 } 56 57 this(const JSValue v) nothrow @nogc 58 { 59 this(v.cppObj); 60 } 61 62 63 ~this() nothrow @nogc 64 { 65 if(this._field.value_ !is null){ 66 JSValueMember.dtor(this.cppObj!false); 67 this._field.value_ = null; 68 } 69 } 70 71 72 this(this) nothrow @nogc 73 { 74 //import core.stdc.stdio; 75 //printf("on postblit %d\n", this._field.value_); 76 if(this._field.value_ !is null){ 77 auto copy = JSValue(this.cppObj!false); 78 //printf("on postblit %d : %d\n", this._field.value_, copy._field.value_); 79 //fflush(stdout); 80 this._field.value_ = copy._field.value_; 81 copy._field.value_ = null; 82 } 83 } 84 85 86 void opAssign(const JSValue rhs) nothrow @nogc 87 { 88 JSValueMember.opAssign(this.cppObj, rhs.cppObj); 89 } 90 91 92 void opAssign(ref const JSValue rhs) nothrow @nogc 93 { 94 JSValueMember.opAssign(this.cppObj, rhs.cppObj); 95 } 96 97 98 void opAssign(T)(auto ref const T v) 99 if(is(typeof(JSValue(v)))) 100 { 101 auto jv = JSValue(v); 102 this.opAssign(jv); 103 } 104 105 106 CppObj cppObj(bool withInitialize = true)() nothrow @trusted @property @nogc 107 { 108 CppObj ret = cast(CppObj)cast(void*)&_field; 109 110 static if(withInitialize) 111 if(_field.value_ is null) 112 JSValueMember.ctor(ret); 113 114 return ret; 115 } 116 117 118 inout(CppObj) cppObj() inout pure nothrow @trusted @property @nogc 119 { 120 if(_field.value_ is null) 121 return cast(inout(CppObj))cast(inout(void)*)&JSValueConsts._emptyInstance._field; 122 else 123 return cast(inout(CppObj))cast(inout(void)*)&_field; 124 } 125 126 127 bool getBooleanProperty(alias f)() const nothrow @nogc { return f(this.cppObj); } 128 alias isBoolean = getBooleanProperty!(JSValueMember.IsBoolean); 129 alias isInteger = getBooleanProperty!(JSValueMember.IsInteger); 130 alias isDouble = getBooleanProperty!(JSValueMember.IsDouble); 131 alias isNumber = getBooleanProperty!(JSValueMember.IsNumber); 132 alias isString = getBooleanProperty!(JSValueMember.IsString); 133 alias isArray = getBooleanProperty!(JSValueMember.IsArray); 134 alias isObject = getBooleanProperty!(JSValueMember.IsObject); 135 alias isNull = getBooleanProperty!(JSValueMember.IsNull); 136 alias isUndefined = getBooleanProperty!(JSValueMember.IsUndefined); 137 138 bool has(T : bool)() const nothrow @nogc @property { return this.isBoolean; } 139 bool has(T : int)() const nothrow @nogc @property { return this.isInteger; } 140 bool has(T : double)() const nothrow @nogc @property { return this.isDouble; } 141 bool has(T : string)() const nothrow @nogc @property { return this.isString; } 142 bool has(T : WebString)() const nothrow @nogc @property { return this.isString; } 143 bool has(T : JSArray)() const nothrow @nogc @property { return this.isArray; } 144 bool has(T : JSObject)() const nothrow @nogc @property { return this.isObject; } 145 bool has(T : typeof(null))() const nothrow @nogc @property { return this.isNull; } 146 147 148 T get(T : bool)(T defVal = T.init) const nothrow @nogc 149 { 150 if(this.isBoolean) 151 return JSValueMember.ToBoolean(this.cppObj); 152 else 153 return defVal; 154 } 155 156 157 T get(T : int)(T defVal = T.init) const nothrow @nogc 158 { 159 if(this.isInteger) 160 return JSValueMember.ToInteger(this.cppObj); 161 else 162 return defVal; 163 } 164 165 166 T get(T : double)(T defVal = T.init) const nothrow @nogc 167 { 168 if(this.isDouble){ 169 return to!double(to!string(this)); //JSValueMember.ToDouble(this.cppObj); 170 }else 171 return defVal; 172 } 173 174 175 T get(T : WebString)(T defVal = T.init) const nothrow @nogc 176 { 177 if(this.isString){ 178 WebString str; 179 JSValueMember.ToString(this.cppObj, str.cppObj); 180 return str; 181 }else 182 return defVal; 183 } 184 185 186 T get(T)(T defVal = T.init) const nothrow @nogc 187 if(is(T == JSObject)) 188 { 189 if(this.isObject) 190 return JSObject(JSValueMember.ToObject(this.cppObj)); 191 else 192 return defVal; 193 } 194 195 196 WeakRef!JSObject get(T)(WeakRef!JSObject defVal = refP!JSObject(null)) 197 if(is(T == WeakRef!JSObject)) 198 { 199 if(this.isObject) 200 return .weakRef!JSObject(JSValueMember.ToObject(this.cppObj)); 201 else 202 return defVal; 203 } 204 205 206 WeakRef!(const(JSObject)) get(T)(WeakRef!(const(JSObject)) defVal = refP!(const(JSObject))(null)) const 207 if(is(T == WeakRef!JSObject)) 208 { 209 if(this.isObject) 210 return .weakRef!JSObject(JSValueMember.ToObject(this.cppObj)); 211 else 212 return defVal; 213 } 214 215 216 T get(T)(T defVal = T.init) const nothrow @nogc 217 if(is(T == JSArray)) 218 { 219 if(this.isArray) 220 return JSArray(JSValueMember.ToArray(this.cppObj)); 221 else 222 return defVal; 223 } 224 225 226 WeakRef!(ApplySameTopQualifier!(This, JSArrayCpp)) 227 get(T : WeakRef!JSArrayCpp, this This) 228 (WeakRef!(ApplySameTopQualifier!(This, JSArrayCpp)) defVal = WeakRef!(ApplySameTopQualifier!(This, JSArrayCpp)).init) inout nothrow @nogc 229 { 230 static if(is(This == const) || is(This == immutable)) 231 { 232 if(this.isArray) 233 return .weakRef!JSArrayCpp(JSValueMember.ToArray(this.cppObj)); 234 else 235 return defVal; 236 } 237 else 238 { 239 if(this.isArray) 240 return .weakRef!JSArrayCpp(JSValueMember.ToArray(cast(CppObj)this.cppObj)); 241 else 242 return defVal; 243 } 244 } 245 246 247 void toString(scope void delegate(const(char)[]) sink) const 248 { 249 if(this.isArray) 250 { 251 auto ja = get!(WeakRef!JSArrayCpp); 252 ja.toString(sink); 253 } 254 else if(this.isObject) 255 { 256 auto jo = get!(WeakRef!JSObject); 257 jo.toString(sink); 258 } 259 else 260 { 261 WebString str; 262 JSValueMember.ToString(this.cppObj, str.cppObj); 263 foreach(char e; str.data.byChar) 264 put(sink, e); 265 } 266 } 267 268 269 static 270 ref immutable(JSValue) undefined() pure nothrow @safe @nogc @property 271 { 272 return *JSValueConsts._undefined; 273 } 274 275 276 static 277 ref immutable(JSValue) null_() pure nothrow @safe @nogc @property 278 { 279 return *JSValueConsts._null; 280 } 281 282 283 static 284 auto weakRef(H)(H jsv) 285 if(is(H : const(awebview.wrapper.cpp.JSValue))) 286 { 287 static if(is(H == awebview.wrapper.cpp.JSValue)) 288 JSValue* wsp = cast(JSValue*)cast(void*)jsv; 289 else static if(is(H == const(awebview.wrapper.cpp.JSValue))) 290 const(JSValue)* wsp = cast(const(JSValue)*)cast(const(void)*)jsv; 291 else 292 immutable(JSValue)* wsp = cast(immutable(JSValue)*)cast(immutable(void)*)jsv; 293 294 return refP(wsp); 295 } 296 297 298 private: 299 alias CppObj = awebview.wrapper.cpp.JSValue; 300 CppObj.Field _field; 301 } 302 303 unittest 304 { 305 JSValue v = true; 306 assert(v.isBoolean); 307 assert(v.get!bool); 308 309 v = false; 310 assert(v.isBoolean); 311 assert(!v.get!bool); 312 } 313 314 unittest 315 { 316 import std.conv; 317 318 JSValue v = 12; 319 assert(v.isInteger); 320 assert(v.isNumber); 321 assert(!v.isDouble); 322 assert(!v.isObject); 323 assert(!v.isBoolean); 324 assert(v.get!int == 12); 325 assert(to!string(v) == "12"); 326 327 JSValue v2 = 12.5; 328 assert(!v2.isInteger); 329 assert(v2.isDouble); 330 assert(!v2.isBoolean); 331 import std.stdio; 332 assert(to!string(v2) == "12.5"); 333 334 JSValue v3 = "foo"; 335 assert(v3.isString); 336 assert(to!string(v3) == "foo"); 337 338 JSArray ja = [1, 2, 3]; 339 JSValue v4 = ja; 340 assert(v4.isArray); 341 auto v4arr = v4.get!(WeakRef!JSArrayCpp); 342 assert(v4arr.length == 3); 343 344 const v5 = v4; 345 assert(v5.isArray); 346 auto v5arr = v5.get!(WeakRef!JSArrayCpp); 347 assert(v5arr.length == 3); 348 }