Skip to content

Commit 1f4342e

Browse files
committed
Implement JSON support
1 parent 5c63604 commit 1f4342e

File tree

6 files changed

+59
-13
lines changed

6 files changed

+59
-13
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Dev
44

5+
- Support the `JSON.Encode` protocol in Elixir 1.18+.
6+
57
## v0.7.3 (2024-12-12)
68

79
### Enhancements

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ All data structures offer:
102102
- well-documented APIs that are consistent with the standard library
103103
- implementation of `Inspect`, `Enumerable` and `Collectable` protocols
104104
- implementation of the `Access` behaviour
105+
- implementation of the `JSON.Encoder` protocol (on Elixir 1.18+)
105106
- (optional if `Jason` is installed) implemention of the `Jason.Encoder`
106107
protocol
107108

lib/ord_map.ex

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ defmodule Aja.OrdMap do
1515
`Aja.OrdMap`:
1616
- provides efficient (logarithmic) access: it is not a simple list of tuples
1717
- implements the `Access` behaviour, `Enum` / `Inspect` / `Collectable` protocols
18+
- implements the `JSON.Encoder` protocol (on Elixir 1.18+)
1819
- optionally implements the `Jason.Encoder` protocol if `Jason` is installed
1920
2021
## Examples
@@ -98,14 +99,16 @@ defmodule Aja.OrdMap do
9899
true
99100
100101
101-
## With `Jason`
102+
## JSON encoding
102103
103-
iex> Aja.OrdMap.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> Jason.encode!()
104+
Both `JSON.Encoder` and `Jason.Encoder` are supported.
105+
106+
iex> Aja.OrdMap.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> JSON.encode!()
104107
"{\"un\":1,\"deux\":2,\"trois\":3}"
105108
106109
JSON encoding preserves the insertion order. Comparing with a regular map:
107110
108-
iex> Map.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> Jason.encode!()
111+
iex> Map.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> JSON.encode!()
109112
"{\"deux\":2,\"trois\":3,\"un\":1}"
110113
111114
There is no way as of now to decode JSON using `Aja.OrdMap`.
@@ -1655,6 +1658,16 @@ defmodule Aja.OrdMap do
16551658
end
16561659
end
16571660

1661+
if Code.ensure_loaded?(JSON.Encoder) do
1662+
defimpl JSON.Encoder do
1663+
def encode(map, encoder) do
1664+
# FIXME we shouldn't rely on `:elixir_json`
1665+
# need to add it to Elixir
1666+
map |> Aja.OrdMap.to_list() |> :elixir_json.encode_key_value_list(encoder)
1667+
end
1668+
end
1669+
end
1670+
16581671
if Code.ensure_loaded?(Jason.Encoder) do
16591672
defimpl Jason.Encoder do
16601673
def encode(map, opts) do

lib/vector.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ defmodule Aja.Vector do
1919
- is heavily optimized and should offer higher performance in most use cases, especially "loops" like `map/2` / `to_list/1` / `foldl/3`
2020
- mirrors most of the `Enum` module API (together with `Aja.Enum`) with highly optimized versions for vectors (`Aja.Enum.join/1`, `Aja.Enum.sum/1`, `Aja.Enum.random/1`...)
2121
- supports negative indexing (e.g. `-1` corresponds to the last element)
22+
- implements the `JSON.Encoder` protocol (on Elixir 1.18+)
2223
- optionally implements the `Jason.Encoder` protocol if `Jason` is installed
2324
2425
Note: most of the design is inspired by
@@ -2039,6 +2040,14 @@ defmodule Aja.Vector do
20392040
end
20402041
end
20412042

2043+
if Code.ensure_loaded?(JSON.Encoder) do
2044+
defimpl JSON.Encoder do
2045+
def encode(vector, encoder) do
2046+
vector |> Aja.Vector.to_list() |> JSON.protocol_encode(encoder)
2047+
end
2048+
end
2049+
end
2050+
20422051
if Code.ensure_loaded?(Jason.Encoder) do
20432052
defimpl Jason.Encoder do
20442053
def encode(vector, opts) do

test/ord_map_test.exs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,15 @@ defmodule Aja.OrdMapTest do
8888
Aja.OrdMap.new([{:foo, :atom}, {5, :integer}]) |> inspect()
8989
end
9090

91-
if Version.compare(System.version(), "1.14.0") != :lt do
92-
test "from_struct/1" do
93-
ord_map = %User{name: "John", age: 44} |> Aja.OrdMap.from_struct()
94-
expected = Aja.OrdMap.new(name: "John", age: 44)
95-
assert ^expected = ord_map
96-
97-
ord_map = Aja.OrdMap.from_struct(User)
98-
expected = Aja.OrdMap.new(name: nil, age: nil)
99-
assert ^expected = ord_map
100-
end
91+
@tag skip: Version.compare(System.version(), "1.14.0") == :lt
92+
test "from_struct/1" do
93+
ord_map = %User{name: "John", age: 44} |> Aja.OrdMap.from_struct()
94+
expected = Aja.OrdMap.new(name: "John", age: 44)
95+
assert ^expected = ord_map
96+
97+
ord_map = Aja.OrdMap.from_struct(User)
98+
expected = Aja.OrdMap.new(name: nil, age: nil)
99+
assert ^expected = ord_map
101100
end
102101

103102
test "get_and_update/3" do
@@ -117,5 +116,16 @@ defmodule Aja.OrdMapTest do
117116
Aja.OrdMap.get_and_update!(ord_map, :b, fn value -> value end)
118117
end
119118
end
119+
120+
@tag skip: Version.compare(System.version(), "1.18.0-rc.0") == :lt
121+
test "JSON.encode!/1" do
122+
result = Aja.OrdMap.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> JSON.encode!()
123+
assert result == "{\"un\":1,\"deux\":2,\"trois\":3}"
124+
end
125+
126+
test "Jason.encode!/1" do
127+
result = Aja.OrdMap.new([{"un", 1}, {"deux", 2}, {"trois", 3}]) |> Jason.encode!()
128+
assert result == "{\"un\":1,\"deux\":2,\"trois\":3}"
129+
end
120130
end
121131
end

test/vector_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,5 +542,16 @@ defmodule Aja.VectorTest do
542542
assert [18, 19] == Aja.Vector.new(1..20) |> Enum.slice(-3, 2)
543543
assert Enum.to_list(2..99) == Aja.Vector.new(1..100) |> Enum.slice(1..98)
544544
end
545+
546+
@tag skip: Version.compare(System.version(), "1.18.0-rc.0") == :lt
547+
test "JSON.encode!/1" do
548+
result = Aja.Vector.new(["un", 2, :trois]) |> JSON.encode!()
549+
assert result == "[\"un\",2,\"trois\"]"
550+
end
551+
552+
test "Jason.encode!/1" do
553+
result = Aja.Vector.new(["un", 2, :trois]) |> Jason.encode!()
554+
assert result == "[\"un\",2,\"trois\"]"
555+
end
545556
end
546557
end

0 commit comments

Comments
 (0)