Skip to content

Commit

Permalink
add NonEmptyList.walkUntil
Browse files Browse the repository at this point in the history
  • Loading branch information
Giesch committed Nov 11, 2024
1 parent 97b4d94 commit 616a98d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 30 deletions.
29 changes: 29 additions & 0 deletions examples/rollback/NonEmptyList.roc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module [
updateNonLast,
sortWith,
fromList,
walkUntil,
]

## A List guaranteed to contain at least one item
Expand Down Expand Up @@ -115,3 +116,31 @@ sortWith = \nonEmpty, compare ->
Ok item -> item

@NonEmptyList { list: nonLast, last: lastItem }

Step state : [Break state, Continue state]

walkUntil : NonEmptyList item, (item -> Step state), (state, item -> Step state) -> state
walkUntil = \nonEmpty, fromFirst, step ->
list = toList nonEmpty

WrappedState s : [Empty, SeenOne s]

wrappedInitial : WrappedState state
wrappedInitial = Empty

walked =
List.walkUntil list wrappedInitial \wrappedState, item ->
when wrappedState is
Empty ->
when fromFirst item is
Break s -> Break (SeenOne s)
Continue s -> Continue (SeenOne s)

SeenOne state ->
when step state item is
Break s -> Break (SeenOne s)
Continue s -> Continue (SeenOne s)

when walked is
Empty -> crash "unreachable"
SeenOne state -> state
41 changes: 11 additions & 30 deletions examples/rollback/Rollback.roc
Original file line number Diff line number Diff line change
Expand Up @@ -310,25 +310,15 @@ updateRemoteInputs = \world, inbox ->

dropOldInputs : RecordedWorld -> RecordedWorld
dropOldInputs = \world ->
beforeLastGap =
initialState : [Empty, LastSeen U64]
initialState = Empty

walked =
world.receivedInputs
|> NonEmptyList.toList
|> List.walkUntil initialState \state, received ->
when state is
Empty -> Continue (LastSeen received.inputTick)
LastSeen lastSeen ->
if lastSeen + 1 == received.inputTick then
Continue (LastSeen received.inputTick)
else
Break (LastSeen lastSeen)

when walked is
Empty -> crash "unreachable"
LastSeen lastSeen -> lastSeen
beforeFirstGap =
world.receivedInputs
|> NonEmptyList.walkUntil
\firstReceived -> Continue firstReceived.inputTick
\lastSeen, received ->
if lastSeen + 1 == received.inputTick then
Continue received.inputTick
else
Break lastSeen

beforeMaxRollback =
(Num.toI64 world.tick - world.config.maxRollbackTicks)
Expand All @@ -340,12 +330,12 @@ dropOldInputs = \world ->
|> Num.max 0
|> Num.toU64

# avoid discarding received inputs newer than this minimum
# avoid discarding any inputs past than this minimum tick
dropThreshold =
[
world.syncTick,
world.remoteSyncTick,
beforeLastGap,
beforeFirstGap,
beforeMaxRollback,
beforeTickAdvantageLimit,
]
Expand All @@ -359,15 +349,10 @@ dropOldInputs = \world ->
NonEmptyList.dropNonLastIf world.snapshots \snap ->
snap.tick < dropThreshold

# TODO
{ world & receivedInputs, snapshots }

updateRemoteTicks : RecordedWorld, List PeerMessage -> RecordedWorld
updateRemoteTicks = \world, inbox ->
# TODO
# find the the temporally last message in the inbox
# if empty, or if older than meta, keep current remote meta

maybeLatest =
inbox
|> List.map .message
Expand Down Expand Up @@ -565,10 +550,6 @@ rollForwardFromSyncTick = \wrongFutureWorld, { rollForwardRange: (begin, end) }
Err NotFound -> wrongFutureSnap
Ok { input: remoteInput } -> { wrongFutureSnap & remoteInput }

# TODO is this necessary? or would it already be updated in the normal flow?
# remoteTick =
# lastReceived = NonEmptyList.last wrongFutureWorld.receivedInputs
# Num.toU64 lastReceived.inputTick
remoteTick = wrongFutureWorld.remoteTick
lastSnapshot = NonEmptyList.last snapshots
syncTick = Num.min wrongFutureWorld.remoteTick lastSnapshot.tick
Expand Down

0 comments on commit 616a98d

Please sign in to comment.