Hi all,
while we are on this, I’d like to share the `mapset/1 macro we use to simplify MapSet matching
@doc """
Mapsets in matches are matched the same way as maps, that said the following would be matched
```elixir
fn mapset() -> :ok end.(MapSet.new())
fn mapset() -> :ok end.(MapSet.new([1, 2]))
fn mapset([1]) -> :ok end.(MapSet.new([1, 2]))
```
and the following would not
```elixir
fn mapset([1]) -> :ok end.(MapSet.new())
fn mapset([2]) -> :ok end.(MapSet.new([1]))
```
"""
@doc guard: false
@spec mapset(list()) :: Macro.t()
defmacro mapset(list) do
case __CALLER__.context do
:guard ->
raise_opts = fn description ->
[
file: Path.relative_to_cwd(__CALLER__.file),
line: __CALLER__.line,
description: description
]
end
raise CompileError, raise_opts.("`mapset/1` macro cannot be used in guards")
:match ->
list_ast =
Enum.map(list, fn
{:^, meta, [{_, _, _} = elem]} -> {{:^, meta, [elem]}, []}
# to raise properly, we need the following line
{_var_name, meta, _} = var -> {{:var!, meta, [var]}, []}
elem -> {elem, []}
end)
map_ast = {:%{}, Macro.Env.location(__CALLER__), list_ast}
quote do: %MapSet{map: unquote(map_ast)}
nil ->
quote do: MapSet.new(unquote(list))
end
end
It could be a great addition to the guard, specifically in tests.