1 module awebview.wrapper.jsarray; 2 3 import std.algorithm; 4 import std.format; 5 6 import awebview.wrapper.cpp; 7 import awebview.wrapper.jsvalue : JSValue; 8 import awebview.wrapper.constants; 9 10 import carbon.nonametype; 11 import carbon.templates; 12 import carbon.memory; 13 14 15 struct JSArray 16 { 17 alias PayloadType(This) = typeof(this.init.payload); 18 19 20 @property 21 ref JSArrayCpp payload() nothrow @nogc 22 { 23 if(!_instance.refCountedStore.isInitialized) 24 __ctor(cast(CppObj)null); 25 26 return _instance.refCountedPayload; 27 } 28 29 30 @property 31 ref inout(JSArrayCpp) payload(this T)() inout nothrow @nogc 32 if(is(T == const) || is(T == immutable)) 33 { 34 if(_instance.refCountedStore.isInitialized) 35 return *cast(typeof(return)*)&(this._instance.refCountedPayload()); 36 else 37 return *cast(typeof(return)*)JSArrayConsts._emptyInstance; 38 } 39 40 41 this(size_t n) nothrow @nogc 42 in { 43 assert(n <= uint.max); 44 } 45 body { 46 _instance = Instance(RefCountedNoGC!JSArrayCpp(n)); 47 } 48 49 50 this(in awebview.wrapper.cpp.JSArray cppInst) nothrow @nogc 51 { 52 _instance = Instance(RefCountedNoGC!JSArrayCpp(cppInst)); 53 } 54 55 56 this(in awebview.wrapper.jsvalue.JSValue[] arr) nothrow @nogc 57 in { 58 assert(arr.length <= uint.max); 59 } 60 body { 61 _instance = Instance(RefCountedNoGC!JSArrayCpp(arr)); 62 } 63 64 65 this(E)(in E[] arr) nothrow @nogc 66 if(is(typeof(awebview.wrapper.jsvalue.JSValue(arr[0])))) 67 in { 68 assert(arr.length <= uint.max); 69 } 70 body { 71 _instance = Instance(RefCountedNoGC!JSArrayCpp(arr)); 72 } 73 74 75 JSArray dup() const nothrow @nogc 76 { 77 return JSArray(this.cppObj); 78 } 79 80 81 inout(CppObj) cppObj(this T)() inout nothrow @nogc @property 82 { 83 return cast(typeof(return))(cast(T*)&this).payload.cppObj; 84 } 85 86 87 uint length() const nothrow @nogc @property 88 { return payload.length; } 89 90 alias opDollar = length; 91 92 uint capacity() const nothrow @nogc @property 93 { 94 if(_instance.refCountedStore.refCount > 1) 95 return 0; 96 else 97 return payload.capacity; 98 } 99 100 auto ref opIndex(size_t idx) nothrow @nogc 101 in{ assert(idx < this.length); } 102 body { return payload[cast(uint)idx]; } 103 104 auto ref opIndex(size_t idx) const nothrow @nogc 105 in{ assert(idx < this.length); } 106 body { return payload[cast(uint)idx]; } 107 108 109 void pushBack()(auto ref const JSValue item) nothrow @nogc 110 { 111 if(!this._instance.refCountedStore.isInitialized) 112 this.payload.__ctor(cast(awebview.wrapper.cpp.JSArray)null); 113 114 if(this._instance.refCountedStore.refCount > 1) 115 this = this.dup; 116 117 this.payload.pushBack(item); 118 } 119 120 121 void opOpAssign(string op : "~")(auto ref const JSValue item) nothrow @nogc 122 { 123 pushBack(item); 124 } 125 126 127 void popBack() nothrow @nogc 128 { 129 if(!this._instance.refCountedStore.isInitialized) 130 this.payload.__ctor(cast(awebview.wrapper.cpp.JSArray)null); 131 132 if(this._instance.refCountedStore.refCount > 1) 133 this = this.dup; 134 135 this.payload.popBack(); 136 } 137 138 139 void insert()(auto ref const JSValue item, size_t idx) nothrow @nogc 140 in { assert(idx < this.length); } 141 body { 142 if(!this._instance.refCountedStore.isInitialized) 143 this.payload.__ctor(cast(awebview.wrapper.cpp.JSArray)null); 144 145 if(this._instance.refCountedStore.refCount > 1) 146 this = this.dup; 147 148 this.payload.insert(item, idx); 149 } 150 151 152 void removeAt(size_t idx) nothrow @nogc 153 in { assert(idx < this.length); } 154 body { 155 if(!this._instance.refCountedStore.isInitialized) 156 this.payload.__ctor(cast(awebview.wrapper.cpp.JSArray)null); 157 158 if(this._instance.refCountedStore.refCount > 1) 159 this = this.dup; 160 161 this.payload.removeAt(cast(uint)idx); 162 } 163 164 165 void clear() nothrow @nogc 166 { 167 callAllDtor(this.payload); 168 assert(!this._instance.refCountedStore.isInitialized); 169 } 170 171 172 int opApply(int delegate(ref size_t, ref awebview.wrapper.jsvalue.JSValue) dg) 173 { return payload.opApply(dg); } 174 175 int opApply(int delegate(ref size_t, ref const(awebview.wrapper.jsvalue.JSValue)) dg) const 176 { return payload.opApply(dg); } 177 178 int opApply(int delegate(ref awebview.wrapper.jsvalue.JSValue) dg) 179 { return payload.opApply(dg); } 180 181 int opApply(int delegate(ref const(awebview.wrapper.jsvalue.JSValue)) dg) const 182 { return payload.opApply(dg); } 183 184 185 void toString(scope void delegate(const(char)[]) sink) const 186 { 187 payload.toString(sink); 188 } 189 190 191 private: 192 Instance _instance; 193 194 static auto _dummyTypeCreate() 195 { 196 static struct Dummy 197 { 198 RefCountedNoGC!JSArrayCpp obj; 199 alias obj this; 200 } 201 202 return Dummy(); 203 } 204 205 alias Instance = typeof(_dummyTypeCreate()); 206 alias CppObj = awebview.wrapper.cpp.JSArray; 207 } 208 209 210 struct JSArrayCpp 211 { 212 this(size_t n) nothrow @nogc 213 in { assert(n <= uint.max); } 214 body { 215 JSArrayMember.ctor(this.cppObj!false, cast(uint)n); 216 } 217 218 219 this(in awebview.wrapper.cpp.JSArray cppInst) nothrow @nogc 220 { 221 if(cppInst) 222 JSArrayMember.ctor(this.cppObj!false, cppInst); 223 else 224 JSArrayMember.ctor(this.cppObj!false); 225 } 226 227 228 this(in awebview.wrapper.jsvalue.JSValue[] arr) nothrow @nogc 229 in { assert(arr.length <= uint.max); } 230 body { 231 this(arr.length); 232 233 foreach(i, ref e; arr) 234 this[i] = e; 235 } 236 237 238 this(E)(in E[] arr) nothrow @nogc 239 if(is(typeof(awebview.wrapper.jsvalue.JSValue(arr[0])))) 240 in { assert(arr.length <= uint.max); } 241 body { 242 this(arr.length); 243 244 foreach(i, const ref e; arr) 245 this[i] = awebview.wrapper.jsvalue.JSValue(e); 246 } 247 248 249 this(this) nothrow @nogc 250 { 251 if(this.isInitialized) 252 { 253 typeof(_field) f; 254 JSArrayCpp* p = cast(JSArrayCpp*)f.ptr; 255 JSArrayMember.ctor(p.cppObj!false, this.cppObj!false); 256 this._field = p._field; 257 } 258 } 259 260 261 ~this() nothrow @nogc 262 { 263 if(this.isInitialized) 264 JSArrayMember.dtor(this.cppObj!false); 265 } 266 267 268 private 269 ref inout(CppObj.Field) cppField() inout pure nothrow @trusted @property @nogc 270 { 271 return *cast(typeof(return)*)_field.ptr; 272 } 273 274 275 private 276 bool isInitialized() const pure nothrow @safe @nogc @property 277 { return cppField.vector_ !is null; } 278 279 280 CppObj cppObj(bool withInitialize = true)() nothrow @trusted @property @nogc 281 { 282 CppObj ret = cast(CppObj)cast(void*)&_field; 283 284 static if(withInitialize) 285 if(!this.isInitialized) 286 JSArrayMember.ctor(ret); 287 288 return ret; 289 } 290 291 292 inout(CppObj) cppObj() inout nothrow @trusted @property @nogc 293 { 294 if(!this.isInitialized) 295 return cast(inout(CppObj))cast(inout(void)*)&(JSArrayConsts._emptyInstance._field); 296 else 297 return cast(inout(CppObj))cast(inout(void)*)&_field; 298 } 299 300 301 uint length() const nothrow @nogc @property 302 { 303 return JSArrayMember.size(this.cppObj); 304 } 305 306 307 alias opDollar = length; 308 309 310 uint capacity() const nothrow @nogc @property 311 { 312 return JSArrayMember.capacity(this.cppObj); 313 } 314 315 316 ref awebview.wrapper.jsvalue.JSValue opIndex(size_t idx) nothrow @nogc 317 in{ assert(idx <= uint.max); } 318 body { 319 awebview.wrapper.cpp.JSValue obj = JSArrayMember.At(this.cppObj, cast(uint)idx); 320 return *cast(awebview.wrapper.jsvalue.JSValue*)cast(void*)obj; 321 } 322 323 324 ref const(awebview.wrapper.jsvalue.JSValue) opIndex(size_t idx) const nothrow @nogc 325 in { assert(idx <= uint.max); } 326 body { 327 const awebview.wrapper.cpp.JSValue obj = JSArrayMember.At(this.cppObj, cast(uint)idx); 328 return *cast(const(awebview.wrapper.jsvalue.JSValue)*)cast(const(void)*)obj; 329 } 330 331 332 void pushBack()(auto ref const awebview.wrapper.jsvalue.JSValue item) nothrow @nogc 333 { 334 JSArrayMember.Push(this.cppObj, item.cppObj); 335 } 336 337 338 void opOpAssign(string op : "~")(auto ref const awebview.wrapper.jsvalue.JSValue item) nothrow @nogc 339 { 340 pushBack(/*forward!*/item); 341 } 342 343 344 void popBack() nothrow @nogc 345 { 346 JSArrayMember.Pop(this.cppObj); 347 } 348 349 350 void insert()(auto ref const awebview.wrapper.jsvalue.JSValue item, uint idx) nothrow @nogc 351 { 352 JSArrayMember.Insert(this.cppObj, item.cppObj, idx); 353 } 354 355 356 void removeAt(uint idx) nothrow @nogc 357 { 358 JSArrayMember.Erase(this.cppObj, idx); 359 } 360 361 362 void clear() nothrow @nogc 363 { 364 JSArrayMember.Clear(this.cppObj); 365 } 366 367 368 int opApply(int delegate(ref size_t, ref awebview.wrapper.jsvalue.JSValue) dg) 369 { 370 int result; 371 372 foreach(ref size_t i; 0 .. this.length){ 373 result = dg(i, this[i]); 374 if(result) 375 break; 376 } 377 378 return result; 379 } 380 381 382 int opApply(int delegate(ref size_t, ref const(awebview.wrapper.jsvalue.JSValue)) dg) const 383 { 384 int result; 385 386 foreach(ref size_t i; 0 .. this.length){ 387 result = dg(i, this[i]); 388 if(result) 389 break; 390 } 391 392 return result; 393 } 394 395 396 int opApply(int delegate(ref awebview.wrapper.jsvalue.JSValue) dg) 397 { 398 int result; 399 400 foreach(size_t i; 0 .. this.length){ 401 result = dg(this[i]); 402 if(result) 403 break; 404 } 405 406 return result; 407 } 408 409 410 int opApply(int delegate(ref const(awebview.wrapper.jsvalue.JSValue)) dg) const 411 { 412 int result; 413 414 foreach(size_t i; 0 .. this.length){ 415 result = dg(this[i]); 416 if(result) 417 break; 418 } 419 420 return result; 421 } 422 423 424 @property 425 auto weakRef(this This)() inout nothrow @nogc 426 { 427 return JSArrayRange!This(cast(This*)&this, 0, this.length); 428 } 429 430 431 void toString(scope void delegate(const(char)[]) sink) const 432 { 433 sink("["); 434 foreach(i; 0 .. this.length){ 435 formattedWrite(sink, "%s", this[i]); 436 if(i != this.length - 1) 437 sink(", "); 438 } 439 sink("]"); 440 } 441 442 443 static 444 auto weakRef(HandleJSArray)(HandleJSArray ws) 445 if(is(HandleJSArray : const(awebview.wrapper.cpp.JSArray))) 446 { 447 static if(is(HandleJSArray == awebview.wrapper.cpp.JSArray)) 448 JSArrayCpp* wsp = cast(JSArrayCpp*)cast(void*)ws; 449 else static if(is(HandleJSArray == const(awebview.wrapper.cpp.JSArray))) 450 const(JSArrayCpp)* wsp = cast(const(JSArrayCpp)*)cast(const(void)*)ws; 451 else 452 immutable(JSArrayCpp)* wsp = cast(immutable(JSArrayCpp)*)cast(immutable(void)*)ws; 453 454 return refP(wsp); 455 } 456 457 458 private: 459 alias CppObj = awebview.wrapper.cpp.JSArray; 460 ubyte[CppObj.Field.sizeof] _field; 461 } 462 463 464 unittest 465 { 466 auto arr = JSArrayCpp(8); 467 assert(arr.length == 8); 468 469 foreach(ref awebview.wrapper.jsvalue.JSValue e; arr) 470 assert(e.isUndefined); 471 472 arr[0] = awebview.wrapper.jsvalue.JSValue(12); 473 assert(arr[0].get!int == 12); 474 475 arr ~= awebview.wrapper.jsvalue.JSValue(13); 476 assert(arr.length == 9); 477 assert(arr[$-1].get!int == 13); 478 479 foreach(ref const awebview.wrapper.jsvalue.JSValue e; arr) 480 assert(e.isUndefined || e.isNumber); 481 } 482 483 484 unittest 485 { 486 import std.range; 487 488 JSArrayCpp arr = ["foo", "bar", "hoge"]; 489 auto arrRef = arr.weakRef; 490 static assert(isInputRange!(typeof(arrRef))); 491 } 492 493 494 private struct JSArrayRange(WRJSArray) 495 { 496 @nogc: 497 nothrow: 498 @property 499 auto ref front() inout nothrow @nogc { return (*_arr)[_b]; } 500 501 void popFront() pure nothrow @nogc @safe { ++_b; } 502 503 @property 504 auto ref back() inout nothrow @nogc { return (*_arr)[_e-1]; } 505 506 void popBack() pure nothrow @nogc @safe { --_e; } 507 508 @property 509 bool empty() const nothrow @nogc @safe { return _b >= _e; } 510 511 @property 512 size_t length() const pure nothrow @nogc @safe { return _e - _b; } 513 514 alias opDollar = length; 515 516 auto ref opIndex(size_t i) inout nothrow @nogc 517 in{ assert(i < this.length); } 518 body{ return (*_arr)[_b + i]; } 519 520 typeof(this) opSlice() pure nothrow @safe @nogc { return this; } 521 522 typeof(this) opSlice(size_t a, size_t b) pure nothrow @safe @nogc 523 in{ 524 assert(a <= b); 525 assert(b <= this.length); 526 } 527 body{ 528 typeof(this) dst = this; 529 dst._b += a; 530 dst._e -= this.length - b; 531 return dst; 532 } 533 534 WRJSArray* _arr; 535 ref inout(WRJSArray) getArray() inout pure nothrow @safe @nogc @property 536 { return *_arr; } 537 538 alias getArray this; 539 540 private: 541 size_t _b; 542 size_t _e; 543 }