field() :: {name :: atom(), type :: module(), opts :: Keyword.t()}
decode([field()], map(), Keyword.t()) :: {:ok, %{required(atom()) => term()}} | {:error, reason :: atom()}
encode([field()], map(), Keyword.t()) :: {:ok, %{required(atom()) => term()}} | {:error, reason :: atom()}