defmodule HexSolver.Constraints.Version do @moduledoc false use HexSolver.Constraints.Impl, for: Version import Kernel, except: [match?: 2] alias HexSolver.Constraint alias HexSolver.Constraints.{Empty, Range, Union, Util} def any?(%Version{}), do: false def empty?(%Version{}), do: false def allows?(%Version{} = left, %Version{} = right), do: left == right def allows_any?(%Version{}, %Empty{}), do: true def allows_any?(%Version{} = left, right), do: Constraint.allows?(right, left) def allows_all?(%Version{}, %Empty{}) do true end def allows_all?(%Version{} = left, %Version{} = right) do left == right end def allows_all?(%Version{}, %Range{min: nil}) do false end def allows_all?(%Version{}, %Range{max: nil}) do false end def allows_all?(%Version{} = version, %Range{ min: min, max: max, include_min: true, include_max: true }) do version == min and version == max end def allows_all?(%Version{}, %Range{}) do false end def allows_all?(%Version{} = version, %Union{ranges: ranges}) do Enum.all?(ranges, &allows_all?(version, &1)) end def difference(%Version{} = version, constraint) do if Constraint.allows?(constraint, version), do: %Empty{}, else: version end def intersect(%Version{} = version, constraint) do if Constraint.allows?(constraint, version), do: version, else: %Empty{} end def union(%Version{} = version, constraint) do if Constraint.allows?(constraint, version) do constraint else case constraint do %Range{min: ^version} = range -> %{range | include_min: true} %Range{max: ^version} = range -> %{range | include_max: true} _ -> Util.union([version, constraint]) end end end def compare(%Version{} = left, %Version{} = right) do Version.compare(left, right) end def compare(%Version{} = version, %Range{min: min, include_min: include_min}) do if min == nil do :gt else case Version.compare(version, min) do :eq when include_min -> :eq :eq -> :lt :lt -> :lt :gt -> :gt end end end def compare(%Version{} = version, %Union{ranges: [range | _]}) do compare(version, range) end def min(left, right) do case compare(left, right) do :lt -> left :eq -> left :gt -> right end end def max(left, right) do case compare(left, right) do :lt -> right :eq -> left :gt -> left end end def to_range(%Version{} = version) do %Range{min: version, max: version, include_min: true, include_max: true} end def to_range(%Range{} = range) do range end def prioritize(%Version{} = left, %Version{} = right) do do_prioritize(left, right) == :gt end defp do_prioritize(left, right) do cond do left.pre != [] and right.pre == [] -> :lt left.pre == [] and right.pre != [] -> :gt true -> Version.compare(left, right) end end end