diff --git a/CHANGELOG.md b/CHANGELOG.md index d251279..da89a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Dev +- Stop using an opaque type for `Aja.Vector.t/1:t` to enable pattern-matching. + Rely on documentation instead, like `Aja.OrdMap.t/2:t`. Thanks @MegaRedHand! + ## v0.6.2 (2023-03-10) ### Enhancements diff --git a/lib/enum.ex b/lib/enum.ex index 3d9dc1b..706eedd 100644 --- a/lib/enum.ex +++ b/lib/enum.ex @@ -32,8 +32,6 @@ defmodule Aja.Enum do @compile :inline_list_funcs - @dialyzer :no_opaque - @type index :: integer @type value :: any @type t(value) :: Aja.Vector.t(value) | [value] | Enumerable.t() diff --git a/lib/helpers/enum_helper.ex b/lib/helpers/enum_helper.ex index 8d4f866..12a7ef7 100644 --- a/lib/helpers/enum_helper.ex +++ b/lib/helpers/enum_helper.ex @@ -5,8 +5,6 @@ defmodule Aja.EnumHelper do alias Aja.Vector.Raw, as: RawVector - @dialyzer :no_opaque - @compile {:inline, try_get_raw_vec_or_list: 1} def try_get_raw_vec_or_list(%Aja.Vector{__vector__: vector}), do: vector def try_get_raw_vec_or_list(list) when is_list(list), do: list diff --git a/lib/ord_map.ex b/lib/ord_map.ex index bc85fb8..a606bf9 100644 --- a/lib/ord_map.ex +++ b/lib/ord_map.ex @@ -171,8 +171,8 @@ defmodule Aja.OrdMap do iex> match?(%Aja.OrdMap{}, Aja.OrdMap.new()) true - Note, however, than `Aja.OrdMap` is an [opaque type](https://hexdocs.pm/elixir/typespecs.html#user-defined-types): - its struct internal fields must not be accessed directly. + Note, however, that `Aja.OrdMap` should be considered an opaque type: its struct internal fields + must not be accessed directly (even if not enforced by dialyzer because of pattern-matching). As discussed in the previous section, [`ord/1`](`Aja.ord/1`) and [`ord_size/1`](`Aja.ord_size/1`) makes it possible to pattern match on keys as well as check the type and size. @@ -195,8 +195,15 @@ defmodule Aja.OrdMap do __ord_map__: %{optional(key) => [index | value]}, __ord_vector__: RawVector.t({key, value}) } + + @typedoc """ + The type of an `Aja.OrdMap` with keys of the type `key` and values of the type `value`. + + It should be considered opaque even though it isn't enforced by dialyzer to enable pattern-matching. + """ @type t(key, value) :: internals(key, value) @type t :: t(key, value) + defstruct __ord_map__: %{}, __ord_vector__: RawVector.empty() @doc false diff --git a/lib/vector.ex b/lib/vector.ex index a3fb628..e34f24c 100644 --- a/lib/vector.ex +++ b/lib/vector.ex @@ -100,8 +100,8 @@ defmodule Aja.Vector do iex> match?(%Aja.Vector{}, Aja.Vector.new()) true - Note, however, than `Aja.Vector` is an [opaque type](https://hexdocs.pm/elixir/typespecs.html#user-defined-types): - its struct internal fields must not be accessed directly. + Note, however, that `Aja.Vector` should be considered an opaque type: its struct internal fields + must not be accessed directly (even if not enforced by dialyzer because of pattern-matching). As discussed in the previous section, [`vec/1`](`Aja.vec/1`) makes it possible to pattern match on size and elements as well as checking the type. @@ -302,12 +302,19 @@ defmodule Aja.Vector do @type index :: integer @type value :: term - @opaque t(value) :: %__MODULE__{__vector__: Raw.t(value)} - @enforce_keys [:__vector__] - defstruct [:__vector__] + @typep internals(value) :: %__MODULE__{__vector__: Raw.t(value)} + @typedoc """ + The type of an `Aja.Vector` with elements of the type `value`. + + It should be considered opaque even though it isn't enforced by dialyzer to enable pattern-matching. + """ + @type t(value) :: internals(value) @type t :: t(value) + @enforce_keys [:__vector__] + defstruct [:__vector__] + @empty_raw Raw.empty() defmacrop from_internal(internal) do