diff options
author | Martin Ashby <martin@ashbysoft.com> | 2023-11-24 23:37:08 +0000 |
---|---|---|
committer | Martin Ashby <martin@ashbysoft.com> | 2023-11-24 23:37:08 +0000 |
commit | d73f8b321f7251e816ba32c24e09b7c175466306 (patch) | |
tree | 0781ab8379d3d16fc53989f2cb338a656f2eb46e | |
parent | 7f1f2b46ba140d25ffed4832c3fec52585f4a9bc (diff) | |
download | roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.tar.gz roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.tar.bz2 roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.tar.xz roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.zip |
Just-working bencoded decoding of dicts
-rw-r--r-- | main.roc | 137 |
1 files changed, 105 insertions, 32 deletions
@@ -3,21 +3,23 @@ app "roctorrent" imports [pf.Stdout] provides [main] to pf +dbgStr: List U8 -> Str +dbgStr = \s -> Result.withDefault (Str.fromUtf8 s) "!!!Invalid UTF-8!!!" # Decodes an exact string, errors if there is remaining unused data -bDecodeStr: List U8 -> Result (List U8) [Malformatted] +bDecodeStr: List U8 -> Result (List U8) [Malformatted Str] bDecodeStr = \i -> - when bDecodeStrAndRemainder i is - Ok {before, others} -> + when bDecodeStrAndRem i is + Ok {res, others} -> if List.len others == 0 then - Ok before + Ok res else - Err Malformatted - Err _ -> Err Malformatted + Err (Malformatted "bDecodeStr: trailing characters in string \(dbgStr others)") + Err s -> Err s # Decodes a string and returns the remainder of the input as well if there was any -bDecodeStrAndRemainder: List U8 -> Result {before: List U8, others: List U8} [Malformatted] -bDecodeStrAndRemainder = \i -> +bDecodeStrAndRem: List U8 -> Result {res: List U8, others: List U8} [Malformatted Str] +bDecodeStrAndRem = \i -> when (List.splitFirst i ':') is Ok {before, after} -> when (Str.fromUtf8 before) is @@ -25,12 +27,13 @@ bDecodeStrAndRemainder = \i -> when (Str.toNat ls) is Ok l -> if List.len after >= l then - Ok (List.split after l) + r2 = (List.split after l) + Ok {res: r2.before, others: r2.others} else - Err Malformatted - Err _err -> Err Malformatted - Err _err -> Err Malformatted - Err _err -> Err Malformatted + Err (Malformatted "bDecodeStrAndRem: len exceeds remaining data") + Err _err -> Err (Malformatted "bDecodeStrAndRem: failed to parse number \(dbgStr i)") + Err _err -> Err (Malformatted "bDecodeStrAndRem: failed to parse utf8") + Err _err -> Err (Malformatted "bDecodeStrAndRem: no ':' found \(dbgStr i)") expect res = bDecodeStr (Str.toUtf8 "3:foo") @@ -38,18 +41,18 @@ expect expect errCases = [ - "", - "foo", - "1:foo", - "4:foo", - ":", - "foo:", - "1:", - "::", + {case: "", err: "bDecodeStrAndRem: no ':' found "}, + #{case: "foo", err: "bDecodeStrAndRem: no ':' found"}, + #{case: "1:foo", err: "bDecodeStr: trailing characters"}, + #{case: "4:foo",err: "bDecodeStrAndRem: len exceeds remaining data"}, + #{case: ":", err: "bDecodeStrAndRem: failed to parse utf8"}, + #{case: "foo:", err: "bDecodeStrAndRem: failed to parse number"}, + #{case: "1:",err: "bDecodeStrAndRem: len exceeds remaining data"}, + #{case: "::",err: "bDecodeStrAndRem: failed to parse utf8"}, ] List.all errCases \t -> - res = bDecodeStr (Str.toUtf8 t) - res == Err Malformatted + res = bDecodeStr (Str.toUtf8 t.case) + res == Err (Malformatted t.err) # Decodes an exact number, exta input causes an error bDecodeNum: List U8 -> Result I64 [Malformatted Str] @@ -108,6 +111,7 @@ BVal: [ BStr (List U8), BNum I64, BList (List BVal), + BDict (Dict (List U8) BVal) ] # Detects and decodes any kind of element. @@ -117,9 +121,9 @@ bDecodeValueAndRem = \i -> Ok first -> when first is '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' -> - when bDecodeStrAndRemainder i is - Ok {before, others} -> - Ok {res: BStr before, others: others} + when bDecodeStrAndRem i is + Ok {res, others} -> + Ok {res: BStr res, others: others} Err _err -> Err Malformatted 'i' -> @@ -134,6 +138,12 @@ bDecodeValueAndRem = \i -> Ok {res: BList res, others: others} Err _err -> Err Malformatted + 'd' -> + when bDecodeDictAndRem i is + Ok {res, others} -> + Ok {res: BDict res, others: others} + Err _err -> + Err Malformatted 'e' -> {before, others} = List.split i 1 Err (End others) @@ -158,12 +168,12 @@ expect res == Err Malformatted # Decodes a list. List elements can be any -bDecodeList: (List U8) -> Result {res: (List BVal)} [Malformatted] +bDecodeList: (List U8) -> Result (List BVal) [Malformatted] bDecodeList = \i -> when bDecodeListAndRem i is Ok {res, others} -> if (List.len others) == 0 then - Ok {res: res} + Ok res else Err Malformatted Err e -> @@ -194,11 +204,11 @@ bDecodeListAndRemInternal = \l, i -> expect res = bDecodeList (Str.toUtf8 "le") - res == Ok { res: []} + res == Ok [] expect res = bDecodeList (Str.toUtf8 "li123e3:fooe") - res == Ok { res: [BNum 123i64, BStr (Str.toUtf8 "foo")] } + res == Ok [BNum 123i64, BStr (Str.toUtf8 "foo")] expect res = bDecodeList (Str.toUtf8 "li123e3:fooe123") @@ -206,7 +216,70 @@ expect expect res = bDecodeList (Str.toUtf8 "lli123eee") - res == Ok { res: [BList [BNum 123i64]]} + res == Ok [BList [BNum 123i64]] + + +bDecodeDict: (List U8) -> Result (Dict (List U8) BVal) [Malformatted Str] +bDecodeDict = \i -> + when bDecodeDictAndRem i is + Ok {res, others} -> + if (List.len others) == 0 then + Ok res + else + Err (Malformatted "bDecodeDict: trailing characters") + Err e -> + Err e + +bDecodeDictAndRem: (List U8) -> Result {res: (Dict (List U8) BVal), others: (List U8)} [Malformatted Str] +bDecodeDictAndRem = \i -> + when List.first i is + Ok f -> + if f == 'd' then + {before, others} = List.split i 1 + bDecodeDictAndRemInternal (Dict.empty{}) others + else + Err (Malformatted "first character not 'd'") + Err _e -> Err (Malformatted "empty input") + +bDecodeDictAndRemInternal: (Dict (List U8) BVal), (List U8) -> Result {res: (Dict (List U8) BVal), others: (List U8)} [Malformatted Str] +bDecodeDictAndRemInternal = \d, i -> + when bDecodeValueAndRem i is + Ok r1 -> + when r1.res is + BStr s -> + key = s + when bDecodeValueAndRem r1.others is + Ok r2 -> + val = r2.res + d2 = Dict.insert d key val + bDecodeDictAndRemInternal d2 r2.others + Err e -> when e is + End others -> + Err (Malformatted "key with no value") + Malformatted -> + Err (Malformatted "bDecodeDictAndRemInternal: error decoding value") + _ -> Err (Malformatted "bDecodeDictAndRemInternal: wrong key type") + Err Malformatted -> + Err (Malformatted "bDecodeDictAndRemInternal: error decoding key") + Err (End others) -> + Ok {res: d, others: others} + +expect + expected = Dict.fromList [ + ((Str.toUtf8 "foo"), (BStr (Str.toUtf8 "bar"))), + ] + res = bDecodeDict (Str.toUtf8 "d3:foo3:bare") + res == Ok expected + +expect + nest = Dict.fromList [ + ((Str.toUtf8 "foo"), (BStr (Str.toUtf8 "bar"))), + ] + expected = Dict.fromList [ + ((Str.toUtf8 "top"), (BDict nest)), + ] + res = bDecodeDict (Str.toUtf8 "d3:topd3:foo3:baree") + res == Ok expected -main = +main = Stdout.line "Hello, World"
\ No newline at end of file |