aboutsummaryrefslogtreecommitdiff
path: root/main.roc
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-11-24 23:37:08 +0000
committerMartin Ashby <martin@ashbysoft.com>2023-11-24 23:37:08 +0000
commitd73f8b321f7251e816ba32c24e09b7c175466306 (patch)
tree0781ab8379d3d16fc53989f2cb338a656f2eb46e /main.roc
parent7f1f2b46ba140d25ffed4832c3fec52585f4a9bc (diff)
downloadroctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.tar.gz
roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.tar.bz2
roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.tar.xz
roctorrent-d73f8b321f7251e816ba32c24e09b7c175466306.zip
Just-working bencoded decoding of dicts
Diffstat (limited to 'main.roc')
-rw-r--r--main.roc137
1 files changed, 105 insertions, 32 deletions
diff --git a/main.roc b/main.roc
index 3d48fcd..c0850f6 100644
--- a/main.roc
+++ b/main.roc
@@ -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