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