defprotocol Dsv.Empty do
@moduledoc """
A protocol to check if a provided value is empty.
This protocol is used by the `Dsv.NotEmpty` validator.
## Default Implementations
The protocol provides default implementations for the following data types:
- `List`: Checks if the list has a length of 0.
- `Map`: Checks if the map has no key-value pairs.
- `Tuple`: Checks if the tuple has no elements.
- `String`: Checks if the string has a length of 0.
- `Integer`: Always return :false, integer can not be empty.
- `Float`: Always return :false, float can not be empty.
- `Date`: Always return :false, date can not be empty.
- `DateTime`: Always return :false, date time can not be empty.
- `NaiveDateTime`: Always return :false, naive date time can not be empty.
- `Time`: Always return :false, time can not be empty.
- `Atom`: Checks if the atom is `:nil` or `:false`.
You can implement custom emptiness checks for other data types by providing specific protocol implementations.
## Example
defmodule MyStruct do
defstruct data: [:a, :b, :c]
end
defimpl Empty, for: MyStruct do
def empty?(%MyStruct{data: data}), do: length(data) == 0
end
"""
@doc """
Return `:true` if the value is empty. Otherwise, return `:false`.
For `List`, it will return `:true` only for the `[]` list. In other cases, it will return `:false`.
For `Map`, it will return `:true` only for the `%{}` map. In other cases, it will return `:false`.
For `Tuple`, it will return `:true` only for `{}` tuple. In other cases, it will return `:false`.
For `String`, it will return `:true` only for `\"\"` string. In other cases, it will return `:false`.
For `Integer`, `Float`, `Date`, `DateTime`, `NaiveDateTime`, and `Time`, it will always return `:false` as if value of this type exists, it cannot be empty.
For `Atom`, it will return `:true` for values `:false` and `nil`. In other cases, it will return `:false`.
## Example
iex> Dsv.Empty.empty?(:false)
:true
iex> Dsv.Empty.empty?("")
:true
iex> Dsv.Empty.empty?("not empty")
:false
iex> Dsv.Empty.empty?([])
:true
iex> Dsv.Empty.empty?(:true)
:false
iex> Dsv.Empty.empty?(1.1)
:false
iex> Dsv.Empty.empty?(~D[2000-01-01])
:false
iex> Dsv.Empty.empty?(~U[2000-01-01 11:11:11Z])
:false
iex> Dsv.Empty.empty?(~N[2000-01-01 11:11:11])
:false
iex> Dsv.Empty.empty?(~T[11:11:11])
:false
"""
@spec empty?(any()) :: boolean()
def empty?(data)
end
defimpl Dsv.Empty, for: List do
def empty?([]), do: true
def empty?([_]), do: false
end
defimpl Dsv.Empty, for: Map do
def empty?(data), do: map_size(data) == 0
end
defimpl Dsv.Empty, for: Tuple do
def empty?({}), do: true
def empty?(_), do: false
end
defimpl Dsv.Empty, for: BitString do
def empty?(""), do: true
def empty?(_), do: false
end
defimpl Dsv.Empty, for: [Integer, Float] do
def empty?(_), do: false
end
defimpl Dsv.Empty, for: [Date, DateTime, NaiveDateTime, Time] do
def empty?(_), do: false
end
defimpl Dsv.Empty, for: Atom do
def empty?(false), do: true
def empty?(nil), do: true
def empty?(_), do: false
end