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 }