interface Bytes.Decode exposes [ByteDecoder, decode, map, map2, u8, loop, Step, succeed, DecodeProblem, after, map3] imports [] State : { bytes : List U8, cursor : Nat } DecodeProblem : [OutOfBytes] ByteDecoder a := State -> [Good State a, Bad DecodeProblem] decode : List U8, ByteDecoder a -> Result a DecodeProblem decode = \bytes, @ByteDecoder decoder -> when decoder { bytes, cursor: 0 } is Good _ value -> Ok value Bad e -> Err e succeed : a -> ByteDecoder a succeed = \value -> @ByteDecoder \state -> Good state value map : ByteDecoder a, (a -> b) -> ByteDecoder b map = \@ByteDecoder decoder, transform -> @ByteDecoder \state -> when decoder state is Good state1 value -> Good state1 (transform value) Bad e -> Bad e map2 : ByteDecoder a, ByteDecoder b, (a, b -> c) -> ByteDecoder c map2 = \@ByteDecoder decoder1, @ByteDecoder decoder2, transform -> @ByteDecoder \state1 -> when decoder1 state1 is Good state2 a -> when decoder2 state2 is Good state3 b -> Good state3 (transform a b) Bad e -> Bad e Bad e -> Bad e map3 : ByteDecoder a, ByteDecoder b, ByteDecoder c, (a, b, c -> d) -> ByteDecoder d map3 = \@ByteDecoder decoder1, @ByteDecoder decoder2, @ByteDecoder decoder3, transform -> @ByteDecoder \state1 -> when decoder1 state1 is Good state2 a -> when decoder2 state2 is Good state3 b -> when decoder3 state3 is Good state4 c -> Good state4 (transform a b c) Bad e -> Bad e Bad e -> Bad e Bad e -> Bad e after : ByteDecoder a, (a -> ByteDecoder b) -> ByteDecoder b after = \@ByteDecoder decoder, transform -> @ByteDecoder \state -> when decoder state is Good state1 value -> (@ByteDecoder decoder1) = transform value decoder1 state1 Bad e -> Bad e u8 : ByteDecoder U8 u8 = @ByteDecoder \state -> when List.get state.bytes state.cursor is Ok b -> Good { state & cursor: state.cursor + 1 } b Err _ -> Bad OutOfBytes Step state b : [Loop state, Done b] loop : (state -> ByteDecoder (Step state a)), state -> ByteDecoder a loop = \stepper, initial -> @ByteDecoder \state -> loopHelp stepper initial state loopHelp = \stepper, accum, state -> (@ByteDecoder stepper1) = stepper accum when stepper1 state is Good newState (Done value) -> Good newState value Good newState (Loop newAccum) -> loopHelp stepper newAccum newState Bad e -> Bad e