Skip to content

Commit 6db1091

Browse files
committed
Recursive decoder
1 parent db1ee7c commit 6db1091

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/gleam/dynamic/decode.gleam

+31
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,34 @@ pub fn new_primitive_decoder(
981981
}
982982
})
983983
}
984+
985+
/// Create a decoder that can refer to itself, useful for decoding for deeply
986+
/// nested data.
987+
///
988+
/// Attempting to create a recursive decoder without this function could result
989+
/// in an infinite loop. If you are using `field` or other `use`able function
990+
/// then you may not need to use this function.
991+
///
992+
/// ```gleam
993+
/// import gleam/dynamic
994+
/// import decode/zero.{type Decoder}
995+
///
996+
/// type Nested {
997+
/// Nested(List(Nested))
998+
/// Value(String)
999+
/// }
1000+
///
1001+
/// fn nested_decoder() -> Decoder(Nested) {
1002+
/// use <- zero.recursive
1003+
/// zero.one_of(zero.string |> zero.map(Value), [
1004+
/// zero.list(nested_decoder()) |> zero.map(Nested),
1005+
/// ])
1006+
/// }
1007+
/// ```
1008+
///
1009+
pub fn recursive(inner: fn() -> Decoder(a)) -> Decoder(a) {
1010+
Decoder(function: fn(data) {
1011+
let decoder = inner()
1012+
decoder.function(data)
1013+
})
1014+
}

test/gleam/dynamic/decode_test.gleam

+26
Original file line numberDiff line numberDiff line change
@@ -927,3 +927,29 @@ pub fn js_map_test() {
927927
|> should.be_ok
928928
|> should.equal(dict.from_list([#("a", 10), #("b", 20), #("c", 30)]))
929929
}
930+
931+
type Nested {
932+
Nested(List(Nested))
933+
Value(String)
934+
}
935+
936+
fn recursive_decoder() -> decode.Decoder(Nested) {
937+
use <- decode.recursive()
938+
decode.one_of(decode.string |> decode.map(Value), [
939+
decode.list(recursive_decoder()) |> decode.map(Nested),
940+
])
941+
}
942+
943+
pub fn recursive_test() {
944+
let nested = [["one", "two"], ["three"], []]
945+
let expected =
946+
Nested([
947+
Nested([Value("one"), Value("two")]),
948+
Nested([Value("three")]),
949+
Nested([]),
950+
])
951+
952+
decode.run(dynamic.from(nested), recursive_decoder())
953+
|> should.be_ok
954+
|> should.equal(expected)
955+
}

0 commit comments

Comments
 (0)