    module Distribution.Types.VersionRange (
        -- * Version ranges
        VersionRange,

        -- ** Constructing
        anyVersion, noVersion,
        thisVersion, notThisVersion,
        laterVersion, earlierVersion,
        orLaterVersion, orEarlierVersion,
        unionVersionRanges, intersectVersionRanges,
        withinVersion,
        majorBoundVersion,

        -- ** Inspection
        --
        -- See "Distribution.Version" for more utilities.
        withinRange,
        foldVersionRange,
        normaliseVersionRange,
        stripParensVersionRange,
        hasUpperBound,
        hasLowerBound,

        -- ** Cata & ana
        VersionRangeF (..),
        cataVersionRange,
        anaVersionRange,
        hyloVersionRange,
        projectVersionRange,
        embedVersionRange,

        -- ** Utilities
        isAnyVersion,
        isAnyVersionLight,
        wildcardUpperBound,
        majorUpperBound,
        isWildcardRange,
        versionRangeParser,
        ) where

    import Distribution.Compat.Prelude
    import Distribution.Types.Version
    import Distribution.Types.VersionInterval
    import Distribution.Types.VersionRange.Internal
    import Prelude ()

    -- | Fold over the basic syntactic structure of a 'VersionRange'.
    --
    -- This provides a syntactic view of the expression defining the version range.
    -- The syntactic sugar @\">= v\"@, @\"<= v\"@ and @\"== v.*\"@ is presented
    -- in terms of the other basic syntax.
    --
    -- For a semantic view use 'asVersionIntervals'.
    --
    foldVersionRange :: a                         -- ^ @\"-any\"@ version
                     -> (Version -> a)            -- ^ @\"== v\"@
                     -> (Version -> a)            -- ^ @\"> v\"@
                     -> (Version -> a)            -- ^ @\"< v\"@
                     -> (a -> a -> a)             -- ^ @\"_ || _\"@ union
                     -> (a -> a -> a)             -- ^ @\"_ && _\"@ intersection
                     -> VersionRange -> a
    foldVersionRange :: forall a.
    a
    -> (Version -> a)
    -> (Version -> a)
    -> (Version -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> VersionRange
    -> a
    foldVersionRange a
    _any Version -> a
    this Version -> a
    later Version -> a
    earlier a -> a -> a
    union a -> a -> a
    intersect = VersionRange -> a
    fold
      where
        fold :: VersionRange -> a
    fold = (VersionRangeF a -> a) -> VersionRange -> a
    forall a. (VersionRangeF a -> a) -> VersionRange -> a
    cataVersionRange VersionRangeF a -> a
    alg

        alg :: VersionRangeF a -> a
    alg (ThisVersionF Version
    v)                = Version -> a
    this Version
    v
        alg (LaterVersionF Version
    v)               = Version -> a
    later Version
    v
        alg (OrLaterVersionF Version
    v)             = a -> a -> a
    union (Version -> a
    this Version
    v) (Version -> a
    later Version
    v)
        alg (EarlierVersionF Version
    v)             = Version -> a
    earlier Version
    v
        alg (OrEarlierVersionF Version
    v)           = a -> a -> a
    union (Version -> a
    this Version
    v) (Version -> a
    earlier Version
    v)
        alg (MajorBoundVersionF Version
    v)          = VersionRange -> a
    fold (Version -> VersionRange
    majorBound Version
    v)
        alg (UnionVersionRangesF a
    v1 a
    v2)     = a -> a -> a
    union a
    v1 a
    v2
        alg (IntersectVersionRangesF a
    v1 a
    v2) = a -> a -> a
    intersect a
    v1 a
    v2

        majorBound :: Version -> VersionRange
    majorBound Version
    v = VersionRange -> VersionRange -> VersionRange
    intersectVersionRanges
                         (Version -> VersionRange
    orLaterVersion Version
    v)
                         (Version -> VersionRange
    earlierVersion (Version -> Version
    majorUpperBound Version
    v))

    -- | Normalise 'VersionRange'.
    --
    -- In particular collapse @(== v || > v)@ into @>= v@, and so on.
    normaliseVersionRange :: VersionRange -> VersionRange
    normaliseVersionRange :: VersionRange -> VersionRange
    normaliseVersionRange = (VersionRangeF VersionRange -> VersionRange)
    -> (VersionRange -> VersionRangeF VersionRange)
    -> VersionRange
    -> VersionRange
    hyloVersionRange VersionRangeF VersionRange -> VersionRange
    embed VersionRange -> VersionRangeF VersionRange
    projectVersionRange
      where
        -- == v || > v, > v || == v  ==>  >= v
        embed :: VersionRangeF VersionRange -> VersionRange
    embed (UnionVersionRangesF (ThisVersion Version
    v) (LaterVersion Version
    v')) | Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    v' =
            Version -> VersionRange
    orLaterVersion Version
    v
        embed (UnionVersionRangesF (LaterVersion Version
    v) (ThisVersion Version
    v')) | Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    v' =
            Version -> VersionRange
    orLaterVersion Version
    v

        -- == v || < v, < v || == v  ==>  <= v
        embed (UnionVersionRangesF (ThisVersion Version
    v) (EarlierVersion Version
    v')) | Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    v' =
            Version -> VersionRange
    orEarlierVersion Version
    v
        embed (UnionVersionRangesF (EarlierVersion Version
    v) (ThisVersion Version
    v')) | Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    v' =
            Version -> VersionRange
    orEarlierVersion Version
    v

        -- otherwise embed normally
        embed VersionRangeF VersionRange
    vr = VersionRangeF VersionRange -> VersionRange
    embedVersionRange VersionRangeF VersionRange
    vr

    -- |  Remove 'VersionRangeParens' constructors.
    --
    -- Since version 3.4 this function is 'id', there aren't 'VersionRangeParens' constructor in 'VersionRange' anymore.
    --
    -- @since 2.2
    stripParensVersionRange :: VersionRange -> VersionRange
    stripParensVersionRange :: VersionRange -> VersionRange
    stripParensVersionRange = VersionRange -> VersionRange
    forall a. a -> a
    id

    -- | Does this version fall within the given range?
    --
    -- This is the evaluation function for the 'VersionRange' type.
    --
    withinRange :: Version -> VersionRange -> Bool
    withinRange :: Version -> VersionRange -> Bool
    withinRange Version
    v = Bool
    -> (Version -> Bool)
    -> (Version -> Bool)
    -> (Version -> Bool)
    -> (Bool -> Bool -> Bool)
    -> (Bool -> Bool -> Bool)
    -> VersionRange
    -> Bool
    forall a.
    a
    -> (Version -> a)
    -> (Version -> a)
    -> (Version -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> VersionRange
    -> a
    foldVersionRange
                       Bool
    True
                       (\Version
    v'  -> Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    v')
                       (\Version
    v'  -> Version
    v Version -> Version -> Bool
    forall a. Ord a => a -> a -> Bool
    >  Version
    v')
                       (\Version
    v'  -> Version
    v Version -> Version -> Bool
    forall a. Ord a => a -> a -> Bool
    <  Version
    v')
                       Bool -> Bool -> Bool
    (||)
                       Bool -> Bool -> Bool
    (&&)

    -- | Does this 'VersionRange' place any restriction on the 'Version' or is it
    -- in fact equivalent to 'AnyVersion'.
    --
    -- Note this is a semantic check, not simply a syntactic check. So for example
    -- the following is @True@ (for all @v@).
    --
    -- > isAnyVersion (EarlierVersion v `UnionVersionRanges` orLaterVersion v)
    --
    isAnyVersion :: VersionRange -> Bool
    isAnyVersion :: VersionRange -> Bool
    isAnyVersion VersionRange
    vr = case VersionRange -> [VersionInterval]
    asVersionIntervals VersionRange
    vr of
        [VersionInterval (LowerBound Version
    v Bound
    InclusiveBound) UpperBound
    NoUpperBound] -> Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    version0
        [VersionInterval]
    _                                                            -> Bool
    False

    -- A fast and non-precise version of 'isAnyVersion',
    -- returns 'True' only for @>= 0@ 'VersionRange's.
    --
    -- /Do not use/. The "VersionIntervals don't destroy MajorBoundVersion"
    -- https://github.com/haskell/cabal/pull/6736 pull-request
    -- will change 'simplifyVersionRange' to properly preserve semantics.
    -- Then we can use it to normalise 'VersionRange's in tests.
    --
    isAnyVersionLight :: VersionRange -> Bool
    isAnyVersionLight :: VersionRange -> Bool
    isAnyVersionLight (OrLaterVersion Version
    v) = Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    version0
    isAnyVersionLight VersionRange
    _vr                = Bool
    False

    ----------------------------
    -- Wildcard range utilities
    --

    isWildcardRange :: Version -> Version -> Bool
    isWildcardRange :: Version -> Version -> Bool
    isWildcardRange Version
    ver1 Version
    ver2 = [Int] -> [Int] -> Bool
    forall {a}. (Eq a, Num a) => [a] -> [a] -> Bool
    check (Version -> [Int]
    versionNumbers Version
    ver1) (Version -> [Int]
    versionNumbers Version
    ver2)
      where check :: [a] -> [a] -> Bool
    check (a
    n:[]) (a
    m:[]) | a
    na -> a -> a
    forall a. Num a => a -> a -> a
    +a
    1 a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    m = Bool
    True
            check (a
    n:[a]
    ns) (a
    m:[a]
    ms) | a
    n   a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    m = [a] -> [a] -> Bool
    check [a]
    ns [a]
    ms
            check [a]
    _      [a]
    _                 = Bool
    False

    -- | Does the version range have an upper bound?
    --
    -- @since 1.24.0.0
    hasUpperBound :: VersionRange -> Bool
    hasUpperBound :: VersionRange -> Bool
    hasUpperBound = Bool
    -> (Version -> Bool)
    -> (Version -> Bool)
    -> (Version -> Bool)
    -> (Bool -> Bool -> Bool)
    -> (Bool -> Bool -> Bool)
    -> VersionRange
    -> Bool
    forall a.
    a
    -> (Version -> a)
    -> (Version -> a)
    -> (Version -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> VersionRange
    -> a
    foldVersionRange
                    Bool
    False
                    (Bool -> Version -> Bool
    forall a b. a -> b -> a
    const Bool
    True)
                    (Bool -> Version -> Bool
    forall a b. a -> b -> a
    const Bool
    False)
                    (Bool -> Version -> Bool
    forall a b. a -> b -> a
    const Bool
    True)
                    Bool -> Bool -> Bool
    (&&) Bool -> Bool -> Bool
    (||)

    -- | Does the version range have an explicit lower bound?
    --
    -- Note: this function only considers the user-specified lower bounds, but not
    -- the implicit >=0 lower bound.
    --
    -- @since 1.24.0.0
    hasLowerBound :: VersionRange -> Bool
    hasLowerBound :: VersionRange -> Bool
    hasLowerBound = Bool
    -> (Version -> Bool)
    -> (Version -> Bool)
    -> (Version -> Bool)
    -> (Bool -> Bool -> Bool)
    -> (Bool -> Bool -> Bool)
    -> VersionRange
    -> Bool
    forall a.
    a
    -> (Version -> a)
    -> (Version -> a)
    -> (Version -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> VersionRange
    -> a
    foldVersionRange
                    Bool
    False
                    (Bool -> Version -> Bool
    forall a b. a -> b -> a
    const Bool
    True)
                    (Bool -> Version -> Bool
    forall a b. a -> b -> a
    const Bool
    True)
                    (Bool -> Version -> Bool
    forall a b. a -> b -> a
    const Bool
    False)
                    Bool -> Bool -> Bool
    (&&) Bool -> Bool -> Bool
    (||)