diff --git a/elm.json b/elm.json index 4c96579..1bbb1cf 100644 --- a/elm.json +++ b/elm.json @@ -9,11 +9,12 @@ ], "elm-version": "0.19.0 <= v < 0.20.0", "dependencies": { + "TSFoster/elm-bytes-extra": "1.3.0 <= v < 1.4.0", "elm/bytes": "1.0.8 <= v < 2.0.0", - "elm/core": "1.0.0 <= v < 1.0.5" + "elm/core": "1.0.0 <= v < 1.0.5", + "elm-community/list-extra": "8.7.0 <= v < 9.0.0" }, "test-dependencies": { - "TSFoster/elm-bytes-extra": "1.3.0 <= v < 1.4.0", "elm-explorations/test": "1.0.0 <= v < 2.0.0" } } diff --git a/src/BitWriter.elm b/src/BitWriter.elm index 69ba764..443a8c9 100644 --- a/src/BitWriter.elm +++ b/src/BitWriter.elm @@ -1,6 +1,11 @@ -module BitWriter exposing (..) +module BitWriter exposing + ( BitWriter + , bit + , bits + , empty + , run + ) -import BitParser as BP import Bitwise import Bytes exposing (Bytes) import Bytes.Encode as BE @@ -67,15 +72,12 @@ bits bs writer = --- PERF: don't go through BitParser to not hold all bits in memory - - -bytes : Bytes -> BitWriter -> BitWriter -bytes bite writer = - case BP.run (BP.rawBits (Bytes.width bite * 8)) bite of - -- this is bad, but shouldn't happen - Nothing -> - writer - - Just bs -> - bits bs writer +-- -- PERF: don't go through BitParser to not hold all bits in memory +-- bytes : Bytes -> BitWriter -> BitWriter +-- bytes bite writer = +-- case BP.run (BP.rawBits (Bytes.width bite * 8)) bite of +-- -- this is bad, but shouldn't happen +-- Nothing -> +-- writer +-- Just bs -> +-- bits bs writer diff --git a/src/Urbit.elm b/src/Urbit.elm index 34daa47..fdcd7b0 100644 --- a/src/Urbit.elm +++ b/src/Urbit.elm @@ -1,9 +1,11 @@ -module Urbit exposing (..) +module Urbit exposing (Noun(..), mat, rub) import BitParser as BP exposing (BitParser) +import BitWriter as BW exposing (BitWriter) +import Bitwise import Bytes exposing (Bytes) -import Bytes.Decode as BD -import Bytes.Encode as BE +import Bytes.Extra as Bytes +import List.Extra as List type Noun @@ -11,13 +13,39 @@ type Noun | Atom Bytes +isSig : Bytes -> Bool +isSig bytes = + Bytes.toByteValues bytes |> List.all (\x -> x == 0) + + +mat : Bytes -> BitWriter -> BitWriter +mat bytes writer = + if isSig bytes then + writer |> BW.bit 1 + + else + let + bits = + bytesToBits bytes |> List.dropWhileRight (\x -> x == 0) + + lengthBits = + bits |> List.length |> intToBits |> List.reverse |> List.drop 1 |> List.reverse + in + writer + |> BW.bit 0 + |> BW.bits (List.repeat (List.length lengthBits) 0) + |> BW.bit 1 + |> BW.bits lengthBits + |> BW.bits bits + + rub : BitParser Bytes rub = BP.bit |> BP.andThen (\zeroBit -> if zeroBit == 1 then - BP.succeed (BE.unsignedInt8 0 |> BE.encode) + BP.succeed Bytes.empty else let @@ -40,7 +68,7 @@ rub = (\preLengthRawBits -> let length = - BP.bitsToInt (1 :: preLengthRawBits) + BP.bitsToInt (preLengthRawBits ++ [ 1 ]) in BP.bits length ) @@ -48,7 +76,22 @@ rub = ) +bytesToBits : Bytes -> List Int +bytesToBits bytes = + case + BP.run (BP.rawBits (Bytes.width bytes * 8)) bytes + of + Nothing -> + [] --- met : BitParser Bytes --- met = --- 1 + Just bits -> + bits + + +intToBits : Int -> List Int +intToBits n = + if n <= 0 then + [] + + else + Bitwise.and 1 n :: intToBits (Bitwise.shiftRightBy 1 n) diff --git a/tests/Test/BitParser.elm b/tests/Test/Bit.elm similarity index 59% rename from tests/Test/BitParser.elm rename to tests/Test/Bit.elm index aa03fad..b8f61d6 100644 --- a/tests/Test/BitParser.elm +++ b/tests/Test/Bit.elm @@ -1,13 +1,11 @@ -module Test.BitParser exposing (tests) +module Test.Bit exposing (tests) import BitParser import BitWriter -import Bytes exposing (Bytes) -import Bytes.Encode as BE -import Bytes.Extra -import Expect exposing (Expectation) -import Fuzz exposing (Fuzzer) +import Bytes +import Expect import Test exposing (..) +import Test.Utils exposing (..) tests : Test @@ -37,19 +35,3 @@ tests = ) ] ] - - -bytes : Fuzzer Bytes -bytes = - (Fuzz.intRange 0 255 |> Fuzz.list) - |> Fuzz.map (\l -> l |> List.map BE.unsignedInt8 |> BE.sequence |> BE.encode) - - -bytesEq : Bytes -> Bytes -> Expectation -bytesEq a b = - Expect.equal (Bytes.Extra.toByteValues a) (Bytes.Extra.toByteValues b) - - -maybeBytesEq : Maybe Bytes -> Maybe Bytes -> Expectation -maybeBytesEq a b = - Expect.equal (Maybe.map Bytes.Extra.toByteValues a) (Maybe.map Bytes.Extra.toByteValues b) diff --git a/tests/Test/Urbit.elm b/tests/Test/Urbit.elm new file mode 100644 index 0000000..194fea7 --- /dev/null +++ b/tests/Test/Urbit.elm @@ -0,0 +1,40 @@ +module Test.Urbit exposing (tests) + +import BitParser +import BitWriter +import Bytes exposing (Bytes) +import Bytes.Extra as Bytes +import Fuzz exposing (Fuzzer) +import List.Extra as List +import Test exposing (..) +import Test.Utils exposing (..) +import Urbit exposing (..) + + +tests : Test +tests = + concat + [ fuzz atom + "mat <-> rub" + (\a -> + maybeBytesEq (Just a) (BitWriter.run (mat a BitWriter.empty) |> BitParser.run rub) + ) + ] + + +atom : Fuzzer Bytes +atom = + bytes + |> Fuzz.map + (\a -> a |> Bytes.toByteValues |> List.dropWhileRight (\x -> x == 0) |> Bytes.fromByteValues) + + +noun : Fuzzer Noun +noun = + (\() -> + Fuzz.oneOf + [ bytes |> Fuzz.map Atom + , Fuzz.map2 (\a b -> Cell ( a, b )) noun noun + ] + ) + () diff --git a/tests/Test/Utils.elm b/tests/Test/Utils.elm new file mode 100644 index 0000000..cf62c71 --- /dev/null +++ b/tests/Test/Utils.elm @@ -0,0 +1,24 @@ +module Test.Utils exposing (..) + +import Bytes exposing (Bytes) +import Bytes.Encode as BE +import Bytes.Extra +import Expect exposing (Expectation) +import Fuzz exposing (Fuzzer) +import Test exposing (..) + + +bytes : Fuzzer Bytes +bytes = + (Fuzz.intRange 0 255 |> Fuzz.list) + |> Fuzz.map (\l -> l |> List.map BE.unsignedInt8 |> BE.sequence |> BE.encode) + + +bytesEq : Bytes -> Bytes -> Expectation +bytesEq a b = + Expect.equal (Bytes.Extra.toByteValues a) (Bytes.Extra.toByteValues b) + + +maybeBytesEq : Maybe Bytes -> Maybe Bytes -> Expectation +maybeBytesEq a b = + Expect.equal (Maybe.map Bytes.Extra.toByteValues a) (Maybe.map Bytes.Extra.toByteValues b)