1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
open! Import
module Wrapped : sig
type +'a t
external wrap : 'a -> 'a t = "caml_jsoo_promise_wrap"
external unwrap : 'a t -> 'a = "caml_jsoo_promise_unwrap"
end = struct
type +'a t = Js.Unsafe.any
external wrap : 'a -> 'a t = "caml_jsoo_promise_wrap"
external unwrap : 'a t -> 'a = "caml_jsoo_promise_unwrap"
end
class type promise = object
method _then : 'a. ('a Wrapped.t -> promise Js.t) Js.callback -> promise Js.t Js.meth
method _then_map :
'a 'b. ('a Wrapped.t -> 'b Wrapped.t) Js.callback -> promise Js.t Js.meth
method _then_err :
'a.
('a Wrapped.t -> promise Js.t) Js.callback
-> (Js.Unsafe.any -> promise Js.t) Js.callback
-> promise Js.t Js.meth
method _catch : (Js.Unsafe.any -> promise Js.t) Js.callback -> promise Js.t Js.meth
method _finally : (unit -> unit) Js.callback -> promise Js.t Js.meth
end
type +'a t = promise Js.t
type error = Js.Unsafe.any
class type with_resolvers = object
method promise : promise Js.t Js.readonly_prop
method resolve : Js.Unsafe.any Js.readonly_prop
method reject : Js.Unsafe.any Js.readonly_prop
end
class type all_settled_entry = object
method status : Js.js_string Js.t Js.readonly_prop
method value : 'a. 'a Wrapped.t Js.readonly_prop
method reason : Js.Unsafe.any Js.readonly_prop
end
class type promise_static = object
method resolve : 'a. 'a Wrapped.t -> promise Js.t Js.meth
method reject : Js.Unsafe.any -> promise Js.t Js.meth
method all : promise Js.t Js.js_array Js.t -> promise Js.t Js.meth
method allSettled : promise Js.t Js.js_array Js.t -> promise Js.t Js.meth
method any : promise Js.t Js.js_array Js.t -> promise Js.t Js.meth
method race : promise Js.t Js.js_array Js.t -> promise Js.t Js.meth
method withResolvers : with_resolvers Js.t Js.meth
end
let promise_static : promise_static Js.t = Js.Unsafe.global##._Promise
let promise_constr :
((Js.Unsafe.any -> Js.Unsafe.any -> unit) Js.callback -> promise Js.t) Js.constr =
Js.Unsafe.global##._Promise
let is_supported () = Js.Optdef.test (Js.Unsafe.global##._Promise : _ Js.Optdef.t)
let resolve (x : 'a) : 'a t = promise_static##resolve (Wrapped.wrap x)
let reject (e : error) : 'a t = promise_static##reject e
let make (f : resolve:('a -> unit) -> reject:(error -> unit) -> unit) : 'a t =
let body =
Js.wrap_callback (fun resolve_js reject_js ->
let resolve x =
ignore
(Js.Unsafe.fun_call resolve_js [| Js.Unsafe.inject (Wrapped.wrap x) |]
: Js.Unsafe.any)
in
let reject e =
ignore (Js.Unsafe.fun_call reject_js [| Js.Unsafe.inject e |] : Js.Unsafe.any)
in
f ~resolve ~reject)
in
new%js promise_constr body
let with_resolvers () : 'a t * ('a -> unit) * (error -> unit) =
let r = promise_static##withResolvers in
let resolve x =
ignore
(Js.Unsafe.fun_call r##.resolve [| Js.Unsafe.inject (Wrapped.wrap x) |]
: Js.Unsafe.any)
in
let reject e =
ignore (Js.Unsafe.fun_call r##.reject [| Js.Unsafe.inject e |] : Js.Unsafe.any)
in
r##.promise, resolve, reject
let then_ ?on_error (f : 'a -> 'b t) (p : 'a t) : 'b t =
let cb = Js.wrap_callback (fun (w : 'a Wrapped.t) -> f (Wrapped.unwrap w)) in
match on_error with
| None -> p##_then cb
| Some g ->
let cb_err = Js.wrap_callback g in
p##_then_err cb cb_err
let catch (f : error -> 'a t) (p : 'a t) : 'a t = p##_catch (Js.wrap_callback f)
let finally (f : unit -> unit) (p : 'a t) : 'a t = p##_finally (Js.wrap_callback f)
let map (f : 'a -> 'b) (p : 'a t) : 'b t =
let cb =
Js.wrap_callback (fun (w : 'a Wrapped.t) -> Wrapped.wrap (f (Wrapped.unwrap w)))
in
p##_then_map cb
let bind f p = then_ f p
let all (ps : 'a t list) : 'a list t =
let arr = Js.array (Array.of_list ps) in
let raw = promise_static##all arr in
let cb =
Js.wrap_callback (fun (w : 'a Wrapped.t Js.js_array Js.t Wrapped.t) ->
let arr = Wrapped.unwrap w in
Wrapped.wrap (List.map Wrapped.unwrap (Array.to_list (Js.to_array arr))))
in
raw##_then_map cb
let all_settled (ps : 'a t list) : ('a, error) result list t =
let arr = Js.array (Array.of_list ps) in
let raw = promise_static##allSettled arr in
let cb =
Js.wrap_callback (fun (w : all_settled_entry Js.t Js.js_array Js.t Wrapped.t) ->
let arr = Wrapped.unwrap w in
let lst =
List.map
(fun (entry : all_settled_entry Js.t) ->
if String.equal (Js.to_string entry##.status) "fulfilled"
then Ok (Wrapped.unwrap entry##.value)
else Error (entry##.reason : error))
(Array.to_list (Js.to_array arr))
in
Wrapped.wrap lst)
in
raw##_then_map cb
let any (ps : 'a t list) : 'a t =
let arr = Js.array (Array.of_list ps) in
promise_static##any arr
let race (ps : 'a t list) : 'a t =
let arr = Js.array (Array.of_list ps) in
promise_static##race arr
let error_of_any (x : Js.Unsafe.any) : error = x
let error_to_any (e : error) : Js.Unsafe.any = e
let error_of_exn (e : exn) : error = Js.Unsafe.inject e
let to_any (p : 'a t) : Js.Unsafe.any = Js.Unsafe.coerce p
let of_any (x : Js.Unsafe.any) : 'a t = Js.Unsafe.coerce x