Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an example for Encoding and Decoding abilities #166

Merged
merged 2 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ examples/RandomNumbers/main
examples/CommandLineArgs/main
examples/Tasks/main
examples/Tuples/main
examples/EncodeDecode/main
roc_nightly/

# macOS directory attributes
Expand Down
3 changes: 3 additions & 0 deletions ci_scripts/all_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ $ROC test ./examples/BasicDict/BasicDict.roc
$ROC build ./examples/MultipleRocFiles/main.roc
expect ci_scripts/expect_scripts/MultipleRocFiles.exp

$ROC build ./examples/EncodeDecode/main.roc
expect ci_scripts/expect_scripts/EncodeDecode.exp

$ROC build --lib ./examples/GoPlatform/main.roc --output examples/GoPlatform/platform/libapp.so
go build -C examples/GoPlatform/platform -buildmode=pie -o dynhost
$ROC preprocess-host ./examples/GoPlatform/main.roc
Expand Down
16 changes: 16 additions & 0 deletions ci_scripts/expect_scripts/EncodeDecode.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/expect

# uncomment line below for debugging
# exp_internal 1

set timeout 7

spawn ./examples/EncodeDecode/main

expect "(@ItemKind Text)\r\n(@ItemKind Method)\r\n(@ItemKind Function)\r\n(@ItemKind Constructor)\r\n(@ItemKind Field)\r\n(@ItemKind Variable)\r\n(@ItemKind Class)\r\n(@ItemKind Interface)\r\n(@ItemKind Module)\r\n" {
expect eof
exit 0
}

puts stderr "\nError: output was different from expected value."
exit 1
34 changes: 34 additions & 0 deletions examples/EncodeDecode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Encoding & Decoding Abilities

An example for how to implement the builtin `Encoding` and `Decoding` abilities for an opaque type.

Implementing these abilites for an opaque type like `ItemKind`, enables it to be used seamlessly within other data structures. This is useful when you would like to provide a custom mapping, such as in this example, between an integer and a tag union.

## Implementation
```roc
file:main.roc:snippet:impl
```

## Demo
```roc
file:main.roc:snippet:demo
```

## Output

Run this from the directory that has `main.roc` in it:

```
$ roc dev
(@ItemKind Text)
(@ItemKind Method)
(@ItemKind Function)
(@ItemKind Constructor)
(@ItemKind Field)
(@ItemKind Variable)
(@ItemKind Class)
(@ItemKind Interface)
(@ItemKind Module)
```

You can also use `roc test` to run the tests.
122 changes: 122 additions & 0 deletions examples/EncodeDecode/main.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
app "example"
packages {
pf: "https://github.com/roc-lang/basic-cli/releases/download/0.8.1/x8URkvfyi9I0QhmVG98roKBUs_AZRkLFwFJVJ3942YA.tar.br",
json: "https://github.com/lukewilliamboswell/roc-json/releases/download/0.6.3/_2Dh4Eju2v_tFtZeMq8aZ9qw2outG04NbkmKpFhXS_4.tar.br",
}
imports [
pf.Stdout.{ line },
json.Core.{ json },
Decode.{ Decoder, DecoderFormatting, DecodeResult, DecodeError },
Encode.{ Encoder, EncoderFormatting },
]
provides [main] to pf

### start snippet impl

ItemKind := [
Text,
Method,
Function,
Constructor,
Field,
Variable,
Class,
Interface,
Module,
lukewilliamboswell marked this conversation as resolved.
Show resolved Hide resolved
Property,
]
implements [
Decoding { decoder: decodeItems },
Encoding { toEncoder: encodeItems },
Inspect,
Eq,
]

tryMapResult : DecodeResult U32, (U32 -> Result ItemKind DecodeError) -> DecodeResult ItemKind
tryMapResult = \decoded, mapper ->
when decoded.result is
Err e -> { result: Err e, rest: decoded.rest }
Ok res -> { result: mapper res, rest: decoded.rest }

decodeItems : Decoder ItemKind fmt where fmt implements DecoderFormatting
decodeItems = Decode.custom \bytes, fmt ->
# Helper function to wrap our tag
ok = \tag -> Ok (@ItemKind tag)

bytes
|> Decode.fromBytesPartial fmt
|> tryMapResult \val ->
when val is
1 -> ok Text
2 -> ok Method
3 -> ok Function
4 -> ok Constructor
5 -> ok Field
6 -> ok Variable
7 -> ok Class
8 -> ok Interface
9 -> ok Module
10 -> ok Property
_ -> Err TooShort

encodeItems : ItemKind -> Encoder fmt where fmt implements EncoderFormatting
encodeItems = \@ItemKind val ->
num =
when val is
Text -> 1
Method -> 2
Function -> 3
Constructor -> 4
Field -> 5
Variable -> 6
Class -> 7
Interface -> 8
Module -> 9
Property -> 10
Encode.u32 num

### end snippet impl

### start snippet demo

# make a list of ItemKind's
originalList : List ItemKind
originalList = [
@ItemKind Text,
@ItemKind Method,
@ItemKind Function,
@ItemKind Constructor,
@ItemKind Field,
@ItemKind Variable,
@ItemKind Class,
@ItemKind Interface,
@ItemKind Module,
@ItemKind Property,
]

# encode them into JSON
encodedBytes : List U8
encodedBytes = Encode.toBytes originalList json

# test we have encoded correctly
expect encodedBytes == originalBytes

# take a JSON encoded list
originalBytes : List U8
originalBytes = "[1,2,3,4,5,6,7,8,9,10]" |> Str.toUtf8

# decode into a list of ItemKind's
decodedList : List ItemKind
decodedList = Decode.fromBytes originalBytes json |> Result.withDefault []

# test we have decoded correctly
expect decodedList == originalList

main =
# debug print decoded items to stdio
decodedList
|> List.map Inspect.toStr
|> Str.joinWith "\n"
|> Stdout.line

### end snippet demo
1 change: 1 addition & 0 deletions examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ You can find the source code for all of these at [github.com/roc-lang/examples](
- [Multi-line Comments](/MultiLineComments/README.html)
- [Go Platform](/GoPlatform/README.html)
- [.NET Platform](/DotNetPlatform/README.html)
- [Encoding & Decoding Abilities](/EncodeDecode/README.html)

## External examples

Expand Down
Loading