    -----------------------------------------------------------------------------

    -- |
    -- Module      :  Distribution.Version
    -- Copyright   :  Isaac Jones, Simon Marlow 2003-2004
    --                Duncan Coutts 2008
    -- License     :  BSD3
    --
    -- Maintainer  :  cabal-devel@haskell.org
    -- Portability :  portable
    --
    -- Exports the 'Version' type along with a parser and pretty printer. A version
    -- is something like @\"1.3.3\"@. It also defines the 'VersionRange' data
    -- types. Version ranges are like @\">= 1.2 && < 2\"@.
    module Distribution.Version
      ( -- * Package versions
        Version
      , version0
      , mkVersion
      , mkVersion'
      , versionNumbers
      , nullVersion
      , alterVersion

        -- * Version ranges
      , VersionRange

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

        -- ** Inspection
      , withinRange
      , isAnyVersion
      , isNoVersion
      , isSpecificVersion
      , simplifyVersionRange
      , foldVersionRange
      , normaliseVersionRange
      , stripParensVersionRange
      , hasUpperBound
      , hasLowerBound
      , hasLEUpperBound
      , hasTrailingZeroUpperBound
      , hasGTLowerBound

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

        -- ** Utilities
      , wildcardUpperBound
      , majorUpperBound

        -- ** Modification
      , removeUpperBound
      , removeLowerBound
      , transformCaret
      , transformCaretUpper
      , transformCaretLower

        -- * Version intervals view
      , asVersionIntervals
      , VersionInterval (..)
      , LowerBound (..)
      , UpperBound (..)
      , Bound (..)

        -- ** 'VersionIntervals' abstract type

        -- | The 'VersionIntervals' type and the accompanying functions are exposed
        -- primarily for completeness and testing purposes. In practice
        -- 'asVersionIntervals' is the main function to use to
        -- view a 'VersionRange' as a bunch of 'VersionInterval's.
      , VersionIntervals
      , toVersionIntervals
      , fromVersionIntervals
      , unVersionIntervals
      ) where

    import Distribution.Types.Version
    import Distribution.Types.VersionInterval
    import Distribution.Types.VersionRange

    -------------------------------------------------------------------------------
    -- Utilities on VersionRange requiring VersionInterval
    -------------------------------------------------------------------------------

    -- | This is the converse of 'isAnyVersion'. It check if the version range is
    -- empty, if there is no possible version that satisfies the version range.
    --
    -- For example this is @True@ (for all @v@):
    --
    -- > isNoVersion (EarlierVersion v `IntersectVersionRanges` LaterVersion v)
    isNoVersion :: VersionRange -> Bool
    isNoVersion :: VersionRange -> Bool
    isNoVersion VersionRange
    vr = case VersionRange -> [VersionInterval]
    asVersionIntervals VersionRange
    vr of
      [] -> Bool
    True
      [VersionInterval]
    _ -> Bool
    False

    -- | Is this version range in fact just a specific version?
    --
    -- For example the version range @\">= 3 && <= 3\"@ contains only the version
    -- @3@.
    isSpecificVersion :: VersionRange -> Maybe Version
    isSpecificVersion :: VersionRange -> Maybe Version
    isSpecificVersion VersionRange
    vr = case VersionRange -> [VersionInterval]
    asVersionIntervals VersionRange
    vr of
      [VersionInterval (LowerBound Version
    v Bound
    InclusiveBound) (UpperBound Version
    v' Bound
    InclusiveBound)]
        | Version
    v Version -> Version -> Bool
    forall a. Eq a => a -> a -> Bool
    == Version
    v' -> Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    v
      [VersionInterval]
    _ -> Maybe Version
    forall a. Maybe a
    Nothing

    -------------------------------------------------------------------------------
    -- Transformations
    -------------------------------------------------------------------------------

    -- | Simplify a 'VersionRange' expression. For non-empty version ranges
    -- this produces a canonical form. Empty or inconsistent version ranges
    -- are left as-is because that provides more information.
    --
    -- If you need a canonical form use
    -- @fromVersionIntervals . toVersionIntervals@
    --
    -- It satisfies the following properties:
    --
    -- > withinRange v (simplifyVersionRange r) = withinRange v r
    --
    -- >     withinRange v r = withinRange v r'
    -- > ==> simplifyVersionRange r = simplifyVersionRange r'
    -- >  || isNoVersion r
    -- >  || isNoVersion r'
    simplifyVersionRange :: VersionRange -> VersionRange
    simplifyVersionRange :: VersionRange -> VersionRange
    simplifyVersionRange VersionRange
    vr
      -- If the version range is inconsistent then we just return the
      -- original since that has more information than ">1 && < 1", which
      -- is the canonical inconsistent version range.
      | [VersionInterval] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (VersionIntervals -> [VersionInterval]
    unVersionIntervals VersionIntervals
    vi) = VersionRange
    vr
      | Bool
    otherwise = VersionIntervals -> VersionRange
    fromVersionIntervals VersionIntervals
    vi
      where
        vi :: VersionIntervals
    vi = VersionRange -> VersionIntervals
    toVersionIntervals VersionRange
    vr

    -- | Given a version range, remove the highest upper bound. Example: @(>= 1 && <
    -- 3) || (>= 4 && < 5)@ is converted to @(>= 1 && < 3) || (>= 4)@.
    removeUpperBound :: VersionRange -> VersionRange
    removeUpperBound :: VersionRange -> VersionRange
    removeUpperBound = VersionIntervals -> VersionRange
    fromVersionIntervals (VersionIntervals -> VersionRange)
    -> (VersionRange -> VersionIntervals)
    -> VersionRange
    -> VersionRange
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VersionIntervals -> VersionIntervals
    relaxLastInterval (VersionIntervals -> VersionIntervals)
    -> (VersionRange -> VersionIntervals)
    -> VersionRange
    -> VersionIntervals
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VersionRange -> VersionIntervals
    toVersionIntervals

    -- | Given a version range, remove the lowest lower bound.
    -- Example: @(>= 1 && < 3) || (>= 4 && < 5)@ is converted to
    -- @(>= 0 && < 3) || (>= 4 && < 5)@.
    removeLowerBound :: VersionRange -> VersionRange
    removeLowerBound :: VersionRange -> VersionRange
    removeLowerBound = VersionIntervals -> VersionRange
    fromVersionIntervals (VersionIntervals -> VersionRange)
    -> (VersionRange -> VersionIntervals)
    -> VersionRange
    -> VersionRange
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VersionIntervals -> VersionIntervals
    relaxHeadInterval (VersionIntervals -> VersionIntervals)
    -> (VersionRange -> VersionIntervals)
    -> VersionRange
    -> VersionIntervals
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VersionRange -> VersionIntervals
    toVersionIntervals

    -- | Rewrite @^>= x.y.z@ into @>= x.y.z && < x.(y+1)@
    --
    -- @since 3.6.0.0
    transformCaret :: VersionRange -> VersionRange
    transformCaret :: VersionRange -> VersionRange
    transformCaret = (VersionRangeF VersionRange -> VersionRange)
    -> (VersionRange -> VersionRangeF VersionRange)
    -> VersionRange
    -> VersionRange
    hyloVersionRange VersionRangeF VersionRange -> VersionRange
    embed VersionRange -> VersionRangeF VersionRange
    projectVersionRange
      where
        embed :: VersionRangeF VersionRange -> VersionRange
    embed (MajorBoundVersionF Version
    v) = Version -> VersionRange
    orLaterVersion Version
    v VersionRange -> VersionRange -> VersionRange
    `intersectVersionRanges` Version -> VersionRange
    earlierVersion (Version -> Version
    majorUpperBound Version
    v)
        embed VersionRangeF VersionRange
    vr = VersionRangeF VersionRange -> VersionRange
    embedVersionRange VersionRangeF VersionRange
    vr

    -- | Rewrite @^>= x.y.z@ into @>= x.y.z@
    --
    -- @since 3.6.0.0
    transformCaretUpper :: VersionRange -> VersionRange
    transformCaretUpper :: VersionRange -> VersionRange
    transformCaretUpper = (VersionRangeF VersionRange -> VersionRange)
    -> (VersionRange -> VersionRangeF VersionRange)
    -> VersionRange
    -> VersionRange
    hyloVersionRange VersionRangeF VersionRange -> VersionRange
    embed VersionRange -> VersionRangeF VersionRange
    projectVersionRange
      where
        embed :: VersionRangeF VersionRange -> VersionRange
    embed (MajorBoundVersionF Version
    v) = Version -> VersionRange
    orLaterVersion Version
    v
        embed VersionRangeF VersionRange
    vr = VersionRangeF VersionRange -> VersionRange
    embedVersionRange VersionRangeF VersionRange
    vr

    -- | Rewrite @^>= x.y.z@ into @<x.(y+1)@
    --
    -- @since 3.6.0.0
    transformCaretLower :: VersionRange -> VersionRange
    transformCaretLower :: VersionRange -> VersionRange
    transformCaretLower = (VersionRangeF VersionRange -> VersionRange)
    -> (VersionRange -> VersionRangeF VersionRange)
    -> VersionRange
    -> VersionRange
    hyloVersionRange VersionRangeF VersionRange -> VersionRange
    embed VersionRange -> VersionRangeF VersionRange
    projectVersionRange
      where
        embed :: VersionRangeF VersionRange -> VersionRange
    embed (MajorBoundVersionF Version
    v) = Version -> VersionRange
    earlierVersion (Version -> Version
    majorUpperBound Version
    v)
        embed VersionRangeF VersionRange
    vr = VersionRangeF VersionRange -> VersionRange
    embedVersionRange VersionRangeF VersionRange
    vr