-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWhatIsNext.kt
116 lines (100 loc) · 4.7 KB
/
WhatIsNext.kt
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
package potfur.whatisnext
import dev.forkhandles.result4k.Result4k
import dev.forkhandles.result4k.Success
import dev.forkhandles.result4k.flatMap
import dev.forkhandles.result4k.map
import potfur.whatisnext.Specification.Type
interface WhatIsNext<ID, T : Type, S : Specification<out T>, R, F> {
fun whatIsNext(flowId: ID, requester: R): Result4k<List<S>, F>
fun isCompleted(flowId: ID, requester: R): Result4k<Boolean, F> =
whatIsNext(flowId, requester).map { spec: List<S> -> spec.all { it.isComplete() } }
}
typealias DataChunks<ID, T, S, R, F> = List<DataChunk<ID, out T, out S, R, out Any?, F>>
typealias GenericDataChunk<ID, R, F> = DataChunk<ID, out Type, out Specification<out Type>, R, out Any?, F>
fun interface ChunkAggregate<ID, T : Type, S : Specification<out T>, R, F> {
operator fun invoke(
chunks: List<GenericDataChunk<ID, R, F>>,
id: ID,
requester: R
): Result4k<DataChunks<ID, T, S, R, F>, F>
}
class ChunkAggregateWhatIsNext<ID, T : Type, S : Specification<out T>, R, F>(
private val chunks: List<ChunkAggregate<ID, T, S, R, F>>
) : WhatIsNext<ID, T, S, R, F> {
companion object {
operator fun <ID, T : Type, S : Specification<out T>, R, F> invoke(
vararg chunks: ChunkAggregate<ID, T, S, R, F>
) = ChunkAggregateWhatIsNext(chunks.toList())
operator fun <ID, T : Type, S : Specification<out T>, R, F> invoke(
vararg chunks: DataChunk<ID, out T, out S, R, out Any?, F>
) = ChunkAggregateWhatIsNext(chunks.map {
ChunkAggregate { _, _, _ -> Success(listOf(it)) }
})
}
override fun whatIsNext(flowId: ID, requester: R): Result4k<List<S>, F> =
chunks.fold(Success(emptyList())) { acc: Result4k<List<DataChunk<ID, out T, out S, R, out Any?, F>>, F>, c ->
acc.flatMap { a -> c(emptyList(), flowId, requester).map { a + it } }
}.flatMap {
it.fold(Success(emptyList())) { acc: Result4k<List<S>, F>, c ->
acc.flatMap { a -> c.spec(flowId, requester).map { s -> a + s } }
}
}
}
fun <ID, R, F> GenericDataChunk<ID, R, F>.on(
fn: (ID, R) -> Result4k<Boolean, F>
): ChunkAggregate<ID, out Type, out Specification<out Type>, R, F> =
ChunkAggregate { _, id, r ->
fn(id, r).map { if (it) listOf(this) else emptyList() }
}
fun <ID, R, F> GenericDataChunk<ID, R, F>.then(
vararg chunks: GenericDataChunk<ID, R, F>
): ChunkAggregate<ID, out Type, out Specification<out Type>, R, F> =
ChunkAggregate { _, id, r ->
spec(id, r)
.map { if (it.isComplete()) chunks.toList() else emptyList() }
.map { listOf(this) + it }
}
fun <ID, R, F> List<GenericDataChunk<ID, R, F>>.then(
vararg chunks: GenericDataChunk<ID, R, F>
): ChunkAggregate<ID, out Type, out Specification<out Type>, R, F> =
ChunkAggregate { _, id, r ->
fold(Success(true)) { acc: Result4k<Boolean, F>, c ->
acc.flatMap { a -> c.spec(id, r).map { a && it.isComplete() } }
}
.map { if (it) chunks.toList() else emptyList() }
.map { this + it }
}
fun <ID, R, F> GenericDataChunk<ID, R, F>.then(
vararg chunks: ChunkAggregate<ID, out Type, out Specification<out Type>, R, F>
): ChunkAggregate<ID, out Type, out Specification<out Type>, R, F> =
ChunkAggregate { _, id, r ->
spec(id, r)
.flatMap {
if (it.isComplete())
chunks.fold(Success(emptyList())) { acc: Result4k<List<GenericDataChunk<ID, R, F>>, F>, c ->
acc.flatMap { c(listOf(this), id, r) }
}
else Success(emptyList())
}
.map { listOf(this) + it }
}
fun <V, ID, R, F> branch(value: V, chunk: GenericDataChunk<ID, R, F>) =
value to ChunkAggregate { _, _, _ -> Success(listOf(chunk)) }
fun <V, ID, R, F> branch(value: V, vararg chunks: GenericDataChunk<ID, R, F>) =
value to ChunkAggregate { _, _, _ -> Success(chunks.toList()) }
fun <V, ID, R, F> branch(value: V, chunks: ChunkAggregate<ID, out Type, out Specification<out Type>, R, F>) =
value to chunks
fun <ID, T : Type, S : Specification<T>, R, D, F, V> DataChunk<ID, T, S, R, D, F>.thenOnValue(
vararg branches: Pair<V, ChunkAggregate<ID, out Type, out Specification<out Type>, R, F>>,
fn: (D?) -> V
): ChunkAggregate<ID, out Type, out Specification<out Type>, R, F> = ChunkAggregate { _, id, r ->
spec(id, r)
.flatMap {
if (!it.isComplete()) Success(emptyList())
else view(id, r).flatMap { v ->
branches.toMap()[fn(v)]?.let { it(listOf(this), id, r) }
?: Success(emptyList())
}
}
.map { listOf(this) + it }
}