File: util.ex

package info (click to toggle)
erlang-hex 2.0.6-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,204 kB
  • sloc: erlang: 2,950; sh: 203; makefile: 10
file content (81 lines) | stat: -rw-r--r-- 2,237 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually

defmodule Hex.Solver.Constraints.Util do
  @moduledoc false

  alias Hex.Solver.{Constraint, Util}
  alias Hex.Solver.Constraints.{Empty, Range, Union, Version}

  def any(), do: %Range{}

  def from_list([]), do: %Empty{}
  def from_list([single]), do: Range.normalize(single)
  def from_list(acc), do: %Union{ranges: Enum.map(acc, &Range.normalize/1)}

  def union(list) do
    list = flatten(list)

    cond do
      list == [] ->
        %Empty{}

      Enum.any?(list, &Constraint.any?/1) ->
        %Range{}

      true ->
        list
        |> Enum.sort(Util.compare(Constraint))
        |> Enum.reduce([], fn constraint, acc ->
          previous = List.first(acc)

          cond do
            acc == [] ->
              [constraint]

            not Constraint.allows_any?(previous, constraint) and
                not adjacent?(previous, constraint) ->
              [constraint | acc]

            true ->
              # Merge this constraint with previous, but only if they touch
              List.replace_at(acc, 0, Constraint.union(previous, constraint))
          end
        end)
        |> Enum.reverse()
        |> from_list()
    end
  end

  defp flatten(list) do
    Enum.flat_map(list, fn
      %Union{ranges: ranges} -> ranges
      %Empty{} -> []
      other -> [other]
    end)
  end

  @doc """
  Returns `true` if `left` is immediately next to, but not overlapping, `right`.

  Assumes `left` is lower than `right`.
  """
  def adjacent?(left, right) do
    left = Version.to_range(left)
    right = Version.to_range(right)

    left.max == right.min and
      ((left.include_max and not right.include_min) or
         (not left.include_max and right.include_min))
  end

  def from_bounds(%Elixir.Version{} = lower, %Elixir.Version{} = upper) do
    case Version.compare(lower, upper) do
      :eq -> lower
      :lt -> %Range{min: lower, max: upper, include_min: true, include_max: true}
    end
  end

  def from_bounds(%Elixir.Version{} = lower, nil), do: %Range{min: lower, include_min: true}
  def from_bounds(nil, %Elixir.Version{} = upper), do: %Range{max: upper, include_max: true}
  def from_bounds(nil, nil), do: %Range{}
end