/
cmd.gleam
88 lines (77 loc) · 1.78 KB
/
cmd.gleam
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
import gleam/iterator
import gleam/result
import parse.{Day}
import snag.{Result, Snag}
import gleam/otp/task.{Task}
import gleam/erlang
import gleam/erlang/atom
import gleam/dynamic
import gleam/list
import gleam/result
import gleam/int
import gleam/function
import gleam
pub const input_dir = "input/"
pub const days_dir = "src/days/"
pub type Timing {
Endless
Ending(Timeout)
}
pub type Timeout =
Int
pub fn exec(
days: List(Day),
timing: Timing,
do: fn(Day) -> Result(a),
collect: fn(#(Result(a), Day)) -> String,
) -> List(String) {
days
|> task_map(do)
|> try_await_many(timing)
|> iterator.from_list()
|> iterator.map(result.flatten)
|> iterator.zip(iterator.from_list(days))
|> iterator.map(collect)
|> iterator.to_list()
}
fn now_ms() {
erlang.system_time(erlang.Millisecond)
}
fn task_map(over l: List(a), with f: fn(a) -> b) -> List(Task(b)) {
list.map(l, fn(x) { task.async(fn() { f(x) }) })
}
fn try_await_many(tasks: List(Task(a)), timing: Timing) -> List(Result(a)) {
let await = case timing {
// currently no await_forever so we'll use 10 mins
Endless -> fn(t) {
t
|> task.try_await(600_000)
|> result.map_error(snag_task_error)
}
Ending(timeout) -> {
let end = now_ms() + timeout
fn(t) {
end - now_ms()
|> int.clamp(min: 0, max: timeout)
|> task.try_await(t, _)
|> result.map_error(snag_task_error)
}
}
}
list.map(tasks, await)
}
type UndefRun {
Undef
Run
}
fn snag_task_error(err: task.AwaitError) -> Snag {
case err {
task.Timeout -> "task timed out"
task.Exit(dyn) ->
case dynamic.unsafe_coerce(dyn) {
#(Undef, [#(_, Run, _, _), ..]) -> "Run function missing"
_ -> "task exited for some reason"
}
}
|> snag.new()
}