          do: :ok
   end
 
-  defp validate(:map, schema, value) do
+  defp validate(:map, schema, value, _opts) do
     with :ok <- size(schema, value),
          :ok <- keys(schema, value),
          :ok <- required(schema, value),

  @types [:boolean, :atom, :string, :integer, :float, :number, :list, :map, nil]

  @spec validate(Xema.t() | Xema.Schema.t(), any) :: result
  def validate(%{content: schema}, value) do
    validate(schema, value)
  end

  def validate(%{type: true}, _value), do: :ok

  def validate(%{type: false}, _value), do: {:error, %{type: false}}

  def validate(%{type: list} = schema, value) when is_list(list) do
    with {:ok, type} <- types(schema, value),
         :ok <- validate(%{schema | type: type}, value),
         do: :ok
  end

  def validate(%{type: :any} = schema, value) do
    with type <- get_type(value),
         :ok <- validate(:default, schema, value),
         :ok <- validate(type, schema, value),
         do: :ok
  end

  def validate(%{type: :string} = schema, value) do
    with :ok <- type(schema, value),
         :ok <- validate(:default, schema, value),
         :ok <- validate(:string, schema, value),
         do: :ok
  end

  def validate(%{type: :list} = schema, value) do
    with :ok <- type(schema, value),
         :ok <- validate(:list, schema, value),
         do: :ok
  end

  def validate(%{type: :map} = schema, value) do
    with :ok <- type(schema, value),
         :ok <- validate(:map, schema, value),
         do: :ok
  end

  def validate(%{type: nil} = schema, value), do: validate(nil, schema, value)

  def validate(%{type: :number} = schema, value),
    do: validate(:number, schema, value)

  def validate(%{type: :integer} = schema, value),
    do: validate(:number, schema, value)

  def validate(%{type: :float} = schema, value),
    do: validate(:number, schema, value)

  def validate(%{type: :boolean} = schema, value),
    do: validate(:boolean, schema, value)

  # private validate

  defp validate(:default, schema, value) do
    with :ok <- enum(schema, value),
         :ok <- do_not(schema, value),
         :ok <- all_of(schema, value),

         do: :ok
  end

  defp validate(:string, schema, value, _opts) do
    with length <- String.length(value),
         :ok <- min_length(schema, length, value),
         :ok <- max_length(schema, length, value),
