1 module spasm.types; 2 3 nothrow: 4 5 public import optional; 6 public import spasm.sumtype; 7 import std.traits : hasMember, isCallable, isBasicType; 8 version (LDC) { 9 public import ldc.attributes : assumeUsed; 10 } else { 11 enum assumeUsed; 12 } 13 14 version (unittest) { 15 @safe: 16 Handle spasm_add__object() {return 0;} 17 void spasm_removeObject(Handle) {} 18 } else { 19 extern (C) { 20 @safe: 21 void doLog(uint val); 22 Handle spasm_add__bool(bool); 23 Handle spasm_add__int(int); 24 Handle spasm_add__uint(uint); 25 Handle spasm_add__long(long); 26 Handle spasm_add__ulong(ulong); 27 Handle spasm_add__short(short); 28 Handle spasm_add__ushort(ushort); 29 Handle spasm_add__float(float); 30 Handle spasm_add__double(double); 31 Handle spasm_add__byte(byte); 32 Handle spasm_add__ubyte(ubyte); 33 Handle spasm_add__string(scope ref string); 34 Handle spasm_add__object(); 35 void spasm_removeObject(Handle); 36 Handle spasm_get__field(Handle, string); 37 bool spasm_get__bool(Handle); 38 int spasm_get__int(Handle); 39 uint spasm_get__uint(Handle); 40 long spasm_get__long(Handle); 41 ulong spasm_get__ulong(Handle); 42 short spasm_get__short(Handle); 43 ushort spasm_get__ushort(Handle); 44 float spasm_get__float(Handle); 45 double spasm_get__double(Handle); 46 byte spasm_get__byte(Handle); 47 ubyte spasm_get__ubyte(Handle); 48 string spasm_get__string(Handle); 49 } 50 } 51 52 @trusted extern(C) export @assumeUsed ubyte* allocString(uint bytes) { 53 import spasm.rt.memory; 54 return allocator.make!(ubyte[])(bytes).ptr; 55 } 56 57 @safe: 58 59 alias Handle = uint; 60 struct JsHandle { 61 nothrow: 62 package Handle handle; 63 ~this() { 64 import spasm.types; 65 if (handle > 2) { 66 spasm_removeObject(handle); 67 } 68 } 69 void opAssign(Handle handle) { 70 this.handle = handle; 71 } 72 @disable this(this); 73 alias handle this; 74 } 75 76 auto ptr(return scope ref JsHandle handle) @system { 77 return &handle.handle; 78 } 79 80 enum JsHandle invalidHandle = JsHandle(0); 81 alias EventHandle = uint; 82 83 enum NodeType { 84 a = 0, 85 abbr = 1, 86 address = 2, 87 area = 3, 88 article = 4, 89 aside = 5, 90 audio = 6, 91 b = 7, 92 base = 8, 93 bdi = 9, 94 bdo = 10, 95 blockquote = 11, 96 body_ = 12, 97 br = 13, 98 button = 14, 99 canvas = 15, 100 caption = 16, 101 cite = 17, 102 code = 18, 103 col = 19, 104 colgroup = 20, 105 data = 21, 106 datalist = 22, 107 dd = 23, 108 del = 24, 109 dfn = 25, 110 div = 26, 111 dl = 27, 112 dt = 28, 113 em = 29, 114 embed = 30, 115 fieldset = 31, 116 figcaption = 32, 117 figure = 33, 118 footer = 34, 119 form = 35, 120 h1 = 36, 121 h2 = 37, 122 h3 = 38, 123 h4 = 39, 124 h5 = 40, 125 h6 = 41, 126 head = 42, 127 header = 43, 128 hr = 44, 129 html = 45, 130 i = 46, 131 iframe = 47, 132 img = 48, 133 input = 49, 134 ins = 50, 135 kbd = 51, 136 keygen = 52, 137 label = 53, 138 legend = 54, 139 li = 55, 140 link = 56, 141 main = 57, 142 map = 58, 143 mark = 59, 144 meta = 60, 145 meter = 61, 146 nav = 62, 147 noscript = 63, 148 object = 64, 149 ol = 65, 150 optgroup = 66, 151 option = 67, 152 output = 68, 153 p = 69, 154 param = 70, 155 pre = 71, 156 progress = 72, 157 q = 73, 158 rb = 74, 159 rp = 75, 160 rt = 76, 161 rtc = 77, 162 ruby = 78, 163 s = 79, 164 samp = 80, 165 script = 81, 166 section = 82, 167 select = 83, 168 small = 84, 169 source = 85, 170 span = 86, 171 strong = 87, 172 style = 88, 173 sub = 89, 174 sup = 90, 175 table = 91, 176 tbody = 92, 177 td = 93, 178 template_ = 94, 179 textarea = 95, 180 tfoot = 96, 181 th = 97, 182 thead = 98, 183 time = 99, 184 title = 100, 185 tr = 101, 186 track = 102, 187 u = 103, 188 ul = 104, 189 var = 105, 190 video = 106, 191 wbr = 107, 192 root = 1024 // Special element used in unittests 193 } 194 195 // deprecated("Use spasm.types.Child instead") enum child; 196 enum child; 197 enum prop; 198 enum callback; 199 enum attr; 200 struct connect(field...) {}; 201 struct visible(alias condition) {}; 202 203 template isTOrPointer(T, Target) { 204 enum isTOrPointer = is(T : Target) || is(T : Target*); 205 } 206 // TODO: implement others as well 207 enum ListenerType { 208 click = 0, 209 change = 1, 210 input = 2, 211 keydown = 3, 212 keyup = 4, 213 dblclick = 5, 214 blur = 6, 215 mousemove = 7, 216 mouseup = 8, 217 mousedown = 9, 218 keypress = 10, 219 focus = 11 220 } 221 222 enum EventType { 223 animation = 0, 224 audioProcessing = 1, 225 beforeUnload = 2, 226 blob = 3, 227 clipboard = 4, 228 close = 5, 229 composition = 6, 230 custom = 7, 231 deviceLight = 8, 232 deviceMotion = 9, 233 deviceOrientation = 10, 234 deviceProximity = 11, 235 drag = 12, 236 error = 13, 237 fetch = 14, 238 focus = 15, 239 gamepad = 16, 240 hashChange = 17, 241 idbVersionChange = 18, 242 input = 19, 243 keyboard = 20, 244 mediaStream = 21, 245 message = 22, 246 mouse = 23, 247 mutation = 24, 248 offlineAudioCompletion = 25, 249 pageTransition = 26, 250 paymentRequestUpdate = 27, 251 pointer = 28, 252 popState = 29, 253 progress = 30, 254 rtcDataChannel = 31, 255 rtcIdentityError = 32, 256 rtcIdentity = 33, 257 rtcPeerConnectionIce = 34, 258 storage = 35, 259 svg = 36, 260 time = 37, 261 touch = 38, 262 trackTransition = 39, 263 ui = 40, 264 userProximity = 41, 265 webGlContext = 42, 266 wheel = 43, 267 event = 44 268 } 269 270 @safe template as(Target) { 271 static if (isBasicType!Target || is(Target : string)) { 272 auto as(Source)(auto ref Source s) if (hasMember!(Source, "handle")){ 273 mixin("return spasm_get__" ~ Target.stringof ~ "(s.handle);"); 274 } 275 } else static if (__traits(compiles, "Target.init.handle")) { 276 @safe auto as(Source)(scope return ref Source s) { 277 return cast(Target*)&s; 278 } 279 @safe auto as(Source)(Source s) if (hasMember!(Source, "handle")){ 280 Handle h = s.handle; 281 s.handle = 0; 282 return Target(h); 283 } 284 } 285 } 286 287 auto toOpt(T)(return scope ref T item) @trusted { 288 return Optional!(T*)(&item); 289 } 290 291 auto frontRef(T)(return scope ref T t) @trusted { 292 static if(is(T : Optional!(Base*), Base)) 293 return t.front; 294 else 295 return &t.front(); 296 } 297 298 Handle getOrCreateHandle(T)(scope ref T data) { 299 static if (isBasicType!T || is(T : string)) { 300 mixin("return spasm_add__" ~ T.stringof~ "(data);"); 301 } else static if (is(T : Optional!U, U)) { 302 if (data.empty) 303 return 0; 304 return data.front; 305 } else 306 return data.handle; 307 } 308 309 auto dropHandle(T)(Handle data) { 310 import std.traits : isBasicType; 311 static if (isBasicType!T || is(T : string)) { 312 spasm_removeObject(data); 313 } 314 } 315 316 struct Any { 317 nothrow: 318 JsHandle handle; 319 alias handle this; 320 this(Handle h) { 321 this.handle = JsHandle(h); 322 } 323 } 324 325 template SpasmMangle(T) { 326 static if (hasMember!(T, "handle") || hasMember!(T, "_parent")) { 327 enum SpasmMangle = "handle"; 328 } else { 329 enum SpasmMangle = T.mangleof; 330 } 331 } 332 template BridgeType(T) { 333 static if (hasMember!(T, "handle") || hasMember!(T, "_parent")) { 334 alias BridgeType = JsHandle; 335 } else { 336 alias BridgeType = T; 337 } 338 } 339 340 mixin template ExternPromiseCallback(string funName, T, U) { 341 nothrow: 342 static if (is(T == void)) { 343 pragma(mangle, funName) 344 mixin("extern(C) Handle "~funName~"(Handle, U delegate() nothrow);"); 345 } else { 346 import spasm.bindings; 347 pragma(mangle, funName) 348 mixin("extern(C) Handle "~funName~"(Handle, U delegate("~T.stringof~") nothrow);"); 349 } 350 } 351 352 struct Promise(T, U = Any) { 353 nothrow: 354 JsHandle handle; 355 alias handle this; 356 this(Handle h) { 357 this.handle = JsHandle(h); 358 } 359 alias JoinedType = BridgeType!T; 360 enum ResultMangled = SpasmMangle!T; 361 static if (is(T == void)) { 362 alias FulfillCallback(P = void) = P delegate() nothrow; 363 alias JoinedCallback(P = void) = extern(C) P delegate() nothrow; 364 } else { 365 alias FulfillCallback(P) = P delegate(T) nothrow; 366 alias JoinedCallback(P) = extern(C) P delegate(JoinedType) nothrow; 367 } 368 alias RejectCallback = void delegate(U) nothrow; 369 // NOTE: right now we support no error callback 370 auto then(ResultType)(ResultType delegate(T) nothrow cb) @trusted { 371 enum TMangled = SpasmMangle!T; 372 enum ResultTypeMangled = SpasmMangle!ResultType; 373 enum funName = "promise_then_"~TMangled.length.stringof~TMangled~ResultTypeMangled; 374 mixin ExternPromiseCallback!(funName, JoinedType, BridgeType!ResultType); 375 mixin("return Promise!(ResultType, U)("~funName~"(handle, cast(JoinedCallback!(BridgeType!ResultType))cb));"); 376 } 377 } 378 struct Sequence(T) { 379 nothrow: 380 JsHandle handle; 381 alias handle this; 382 this(Handle h) { 383 this.handle = JsHandle(h); 384 } 385 } 386 struct TypedArray(T) { 387 nothrow: 388 JsHandle handle; 389 alias handle this; 390 this(Handle h) { 391 this.handle = JsHandle(h); 392 } 393 } 394 struct Int8Array { 395 nothrow: 396 TypedArray!(byte) _array; 397 alias _array this; 398 this(Handle h) { 399 _array = TypedArray!(byte)(h); 400 } 401 static auto create(const byte[] data) { 402 return Int8Array(Int8Array_Create(data)); 403 } 404 } 405 struct Int16Array { 406 nothrow: 407 TypedArray!(short) _array; 408 alias _array this; 409 this(Handle h) { 410 _array = TypedArray!(short)(h); 411 } 412 } 413 struct Int32Array { 414 nothrow: 415 TypedArray!(int) _array; 416 alias _array this; 417 this(Handle h) { 418 _array = TypedArray!(int)(h); 419 } 420 static auto create(const int[] data) { 421 return Int32Array(Int32Array_Create(data)); 422 } 423 } 424 struct Uint8Array { 425 nothrow: 426 TypedArray!(ubyte) _array; 427 alias _array this; 428 this(Handle h) { 429 _array = TypedArray!(ubyte)(h); 430 } 431 static auto create(const ubyte[] data) { 432 return Uint8Array(Uint8Array_Create(data)); 433 } 434 } 435 struct Uint16Array { 436 nothrow: 437 TypedArray!(ushort) _array; 438 alias _array this; 439 this(Handle h) { 440 _array = TypedArray!(ushort)(h); 441 } 442 } 443 struct Uint32Array { 444 nothrow: 445 TypedArray!(uint) _array; 446 alias _array this; 447 this(Handle h) { 448 _array = TypedArray!(uint)(h); 449 } 450 } 451 struct Float32Array { 452 nothrow: 453 TypedArray!(float) _array; 454 alias _array this; 455 this(Handle h) { 456 _array = TypedArray!(float)(h); 457 } 458 static auto create(const float[] data) { 459 return Float32Array(Float32Array_Create(data)); 460 } 461 } 462 struct Float64Array { 463 nothrow: 464 TypedArray!(double) _array; 465 alias _array this; 466 this(Handle h) { 467 _array = TypedArray!(double)(h); 468 } 469 } 470 struct Uint8ClampedArray { 471 nothrow: 472 JsHandle handle; 473 alias handle this; 474 this(Handle h) { 475 this.handle = JsHandle(h); 476 } 477 } 478 struct DataView { 479 nothrow: 480 JsHandle handle; 481 alias handle this; 482 this(Handle h) { 483 this.handle = JsHandle(h); 484 } 485 static auto create(const ubyte[] data) { 486 return DataView(DataView_Create(data)); 487 } 488 } 489 struct ArrayBuffer { 490 nothrow: 491 JsHandle handle; 492 alias handle this; 493 this(Handle h) { 494 this.handle = JsHandle(h); 495 } 496 } 497 struct FrozenArray(T) { 498 nothrow: 499 JsHandle handle; 500 alias handle this; 501 this(Handle h) { 502 this.handle = JsHandle(h); 503 } 504 } 505 // TODO: for now animation is defined here, but when accepted we can use the idl (or newer) at https://www.w3.org/TR/2018/WD-web-animations-1-20181011 506 struct Animation { 507 nothrow: 508 JsHandle handle; 509 alias handle this; 510 this(Handle h) { 511 this.handle = JsHandle(h); 512 } 513 } 514 struct Iterator(T) { 515 nothrow: 516 JsHandle handle; 517 alias handle this; 518 this(Handle h) { 519 this.handle = JsHandle(h); 520 } 521 } 522 struct Record(T...) { 523 nothrow: 524 JsHandle handle; 525 alias handle this; 526 this(Handle h) { 527 this.handle = JsHandle(h); 528 } 529 } 530 struct ArrayPair(T,U) { 531 nothrow: 532 JsHandle handle; 533 alias handle this; 534 this(Handle h) { 535 this.handle = JsHandle(h); 536 } 537 } 538 539 struct JsObject { 540 nothrow: 541 JsHandle handle; 542 alias handle this; 543 this(Handle h) { 544 this.handle = JsHandle(h); 545 } 546 auto opDispatch(string name)() { 547 return Any(spasm_get__field(this.handle, name)); 548 } 549 } 550 551 struct Json { 552 nothrow: 553 JsHandle handle; 554 alias handle this; 555 this(Handle h) { 556 this.handle = JsHandle(h); 557 } 558 auto opDispatch(string name)() { 559 return Json(spasm_get__field(this.handle, name)); 560 } 561 auto as(Target)() { 562 return .as!(Target)(this); 563 } 564 } 565 566 extern (C) { 567 Handle Int8Array_Create(const byte[]); 568 Handle Int32Array_Create(const int[]); 569 Handle Uint8Array_Create(const ubyte[]); 570 Handle Float32Array_Create(const float[]); 571 Handle DataView_Create(const ubyte[]); 572 }