Skip to content

Commit

Permalink
feat: add ResizeArray support
Browse files Browse the repository at this point in the history
[core]

Fix #182
  • Loading branch information
MangelMaxime committed Jun 14, 2024
1 parent 3bf8492 commit 1fab3ff
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/Thoth.Json.Core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

* Add `resizeArray` support ([GH-182](https://github.com/thoth-org/Thoth.Json/issues/182))

### Changed

* Rework encoder API to not need a custom DU ([GH-188](https://github.com/thoth-org/Thoth.Json/pull/188/))
Expand Down
36 changes: 36 additions & 0 deletions packages/Thoth.Json.Core/Decode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,42 @@ module Decode =
("", BadPrimitive("a list", value)) |> Error
}

let resizeArray (decoder: Decoder<'value>) : Decoder<'value ResizeArray> =
{ new Decoder<'value ResizeArray> with
member _.Decode(helpers, value) =
if helpers.isArray value then
let tokens = helpers.asArray value
let mutable i = 0
let result = ResizeArray tokens.Length
let mutable error: DecoderError<_> option = None

while i < tokens.Length && error.IsNone do
let value = tokens.[i]

match decoder.Decode(helpers, value) with
| Ok value ->
// Setting the value via the index fails with a runtime error
// but because we iterate over the tokens in order, adding the value
// should keep the order
result.Add value
| Error er ->
error <-
Some(
er
|> Helpers.prependPath (
".[" + (i.ToString()) + "]"
)
)

i <- i + 1

if error.IsNone then
Ok(ResizeArray result)
else
Error error.Value
else
("", BadPrimitive("a ResizeArray", value)) |> Error
}

let seq (decoder: Decoder<'value>) : Decoder<'value seq> =
{ new Decoder<'value seq> with
Expand Down
8 changes: 8 additions & 0 deletions packages/Thoth.Json.Core/Encode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ module Encode =
|> helpers.encodeSeq
}

let resizeArray (values: IEncodable ResizeArray) =
{ new IEncodable with
member _.Encode(helpers) =
values
|> Seq.map (fun v -> v.Encode(helpers))
|> helpers.encodeSeq
}

let dict (values: Map<string, IEncodable>) : IEncodable =
values |> Map.toSeq |> object

Expand Down
57 changes: 57 additions & 0 deletions tests/Thoth.Json.Tests/Decoders.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,63 @@ Expecting an array but instead got: 1

runner.equal expected actual

runner.testCase "ResizeArray works"
<| fun _ ->
let expected =
[
1
2
3
]
|> ResizeArray

let actual =
runner.Decode.fromString
(Decode.resizeArray Decode.int)
"[1, 2, 3]"

// F# sequence are compared using reference equality
// so we need to convert them to arrays first
// See https://stackoverflow.com/questions/17101329/f-sequence-comparison
match actual with
| Ok actual ->
runner.equal
(expected |> Seq.toArray)
(actual |> Seq.toArray)
| Error error -> failwith error

runner.testCase "ResizeArray keeps the order"
<| fun _ ->
let actual =
runner.Decode.fromString
(Decode.resizeArray Decode.int)
"[1, 2, 3]"

// F# sequence are compared using reference equality
// so we need to convert them to arrays first
// See https://stackoverflow.com/questions/17101329/f-sequence-comparison
match actual with
| Ok actual ->
runner.equal 1 actual.[0]
runner.equal 2 actual.[1]
runner.equal 3 actual.[2]

| Error error -> failwith error

runner.testCase "an invalid ResizeArray output an error"
<| fun _ ->
let expected =
Error(
"Error at: `$`\nExpecting a ResizeArray but instead got: 1"
)

let actual =
runner.Decode.fromString
(Decode.resizeArray Decode.int)
"1"

runner.equal expected actual

runner.testCase "keys works"
<| fun _ ->
let expected =
Expand Down
30 changes: 30 additions & 0 deletions tests/Thoth.Json.Tests/Encoders.fs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,36 @@ let tests (runner: TestRunner<_, _>) =

runner.equal actual expected

runner.testCase "a seq works"
<| fun _ ->
let expected = """["maxime",2]"""

let actual =
Encode.seq
[
Encode.string "maxime"
Encode.int 2
]
|> runner.Encode.toString 0

runner.equal actual expected

runner.testCase "a resizeArray works"
<| fun _ ->
let expected = """["maxime",2]"""

let actual =
Encode.resizeArray (
ResizeArray
[
Encode.string "maxime"
Encode.int 2
]
)
|> runner.Encode.toString 0

runner.equal actual expected

runner.testCase "a bool works"
<| fun _ ->
let expected = "false"
Expand Down

0 comments on commit 1fab3ff

Please sign in to comment.