aboutsummaryrefslogtreecommitdiff
path: root/src/gleam_javascript_ffi.mjs
blob: fcf6ae6e0f283b7e5dfa6ded0012d37f62827225 (plain)
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
import { Ok, Error } from "./gleam.mjs";
import {
  UndefinedType,
  ObjectType,
  BooleanType,
  NumberType,
  BigIntType,
  StringType,
  SymbolType,
  FunctionType,
} from "./gleam/javascript.mjs";

export function toArray(list) {
  return list.toArray();
}

export function map(thing, fn) {
  return thing.map(fn);
}

export function length(thing) {
  return thing.length;
}

export function reduce(thing, acc, fn) {
  return thing.reduce(fn, acc);
}

export function reduceRight(thing, acc, fn) {
  return thing.reduceRight(fn, acc);
}

export function index(thing, index) {
  return index in thing ? new Ok(thing[index]) : new Error(undefined);
}

export function object_from_entries(entries) {
  return Object.fromEntries(entries);
}

export function type_of(value) {
  switch (typeof value) {
    case "undefined":
      return new UndefinedType();
    case "object":
      return new ObjectType();
    case "boolean":
      return new BooleanType();
    case "number":
      return new NumberType();
    case "bigint":
      return new BigIntType();
    case "string":
      return new StringType();
    case "symbol":
      return new SymbolType();
    case "function":
      return new FunctionType();
    default:
      throw new globalThis.Error(`Unexpected typeof ${typeof value}`);
  }
}

export function get_symbol(name) {
  return Symbol.for(name);
}

// A wrapper around a promise to prevent `Promise<Promise<T>>` collapsing into
// `Promise<T>`.
class PromiseLayer {
  constructor(promise) {
    this.promise = promise;
  }

  static wrap(value) {
    return value instanceof Promise ? new PromiseLayer(value) : value;
  }

  static unwrap(value) {
    return value instanceof PromiseLayer ? value.promise : value;
  }
}

export function newPromise(executor) {
  return new Promise((resolve) =>
    executor((value) => {
      resolve(PromiseLayer.wrap(value));
    })
  );
}

export function resolve(value) {
  return Promise.resolve(PromiseLayer.wrap(value));
}

export function then_await(promise, fn) {
  return promise.then((value) => fn(PromiseLayer.unwrap(value)));
}

export function map_promise(promise, fn) {
  return promise.then((value) =>
    PromiseLayer.wrap(fn(PromiseLayer.unwrap(value)))
  );
}

export function rescue(promise, fn) {
  return promise.catch((error) => fn(error));
}

class Reference {
  constructor(value) {
    this.value = value;
  }
}

export function dereference(reference) {
  return reference.value;
}

export function make_reference(value) {
  return new Reference(value);
}

export function set_reference(ref, value) {
  let previous = ref.value;
  ref.value = value;
  return previous;
}

export function reference_equal(a, b) {
  return a === b
}

export function all_promises(...promises) {
  if (promises.length === 1) {
    return Promise.all(promises[0]);
  } else {
    return Promise.all(promises);
  }
}

export function race_promises(...promises) {
  if (promises.length === 1) {
    return Promise.race(promises[0]);
  } else {
    return Promise.race(promises);
  }
}

export function map_new() {
  return new Map();
}

export function map_set(map, key, value) {
  return map.set(key, value);
}

export function map_get(map, key) {
  if (map.has(key)) {
    return new Ok(map.get(key));
  }
  return new Error(undefined);
}

export function map_size(map) {
  return map.size;
}