{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}

module Distribution.Types.Version
  ( -- * Package versions
    Version
  , mkVersion
  , mkVersion'
  , versionNumbers
  , nullVersion
  , alterVersion
  , version0

    -- * Internal
  , validVersion
  , versionDigitParser
  ) where

import Data.Bits (shiftL, shiftR, (.&.), (.|.))
import Distribution.Compat.Prelude
import Prelude ()

import Distribution.Parsec
import Distribution.Pretty

import qualified Data.Version as Base
import qualified Distribution.Compat.CharParsing as P
import qualified Text.PrettyPrint as Disp
import qualified Text.Read as Read

-- | A 'Version' represents the version of a software entity.
--
-- Instances of 'Eq' and 'Ord' are provided, which gives exact
-- equality and lexicographic ordering of the version number
-- components (i.e. 2.1 > 2.0, 1.2.3 > 1.2.2, etc.).
--
-- This type is opaque and distinct from the 'Base.Version' type in
-- "Data.Version" since @Cabal-2.0@. The difference extends to the
-- 'Binary' instance using a different (and more compact) encoding.
--
-- @since 2.0.0.2
data Version
  = PV0 {-# UNPACK #-} !Word64
  | PV1 !Int [Int]
  -- NOTE: If a version fits into the packed Word64
  -- representation (i.e. at most four version components
  -- which all fall into the [0..0xfffe] range), then PV0
  -- MUST be used. This is essential for the 'Eq' instance
  -- to work.
  deriving (Typeable Version
Typeable Version =>
(forall (c :: * -> *).
 (forall d b. Data d => c (d -> b) -> d -> c b)
 -> (forall g. g -> c g) -> Version -> c Version)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Version)
-> (Version -> Constr)
-> (Version -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Version))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Version))
-> ((forall b. Data b => b -> b) -> Version -> Version)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> Version -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> Version -> r)
-> (forall u. (forall d. Data d => d -> u) -> Version -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> Version -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Version -> m Version)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Version -> m Version)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Version -> m Version)
-> Data Version
Version -> Constr
Version -> DataType
(forall b. Data b => b -> b) -> Version -> Version
forall a.
Typeable a =>
(forall (c :: * -> *).
 (forall d b. Data d => c (d -> b) -> d -> c b)
 -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Version -> u
forall u. (forall d. Data d => d -> u) -> Version -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Version -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Version -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Version -> m Version
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Version -> m Version
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Version
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Version -> c Version
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Version)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Version)
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Version -> c Version
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Version -> c Version
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Version
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Version
$ctoConstr :: Version -> Constr
toConstr :: Version -> Constr
$cdataTypeOf :: Version -> DataType
dataTypeOf :: Version -> DataType
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Version)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Version)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Version)
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Version)
$cgmapT :: (forall b. Data b => b -> b) -> Version -> Version
gmapT :: (forall b. Data b => b -> b) -> Version -> Version
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Version -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Version -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Version -> r
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Version -> r
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Version -> [u]
gmapQ :: forall u. (forall d. Data d => d -> u) -> Version -> [u]
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Version -> u
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Version -> u
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Version -> m Version
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Version -> m Version
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Version -> m Version
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Version -> m Version
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Version -> m Version
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Version -> m Version
Data, Version -> Version -> Bool
(Version -> Version -> Bool)
-> (Version -> Version -> Bool) -> Eq Version
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Version -> Version -> Bool
== :: Version -> Version -> Bool
$c/= :: Version -> Version -> Bool
/= :: Version -> Version -> Bool
Eq, (forall x. Version -> Rep Version x)
-> (forall x. Rep Version x -> Version) -> Generic Version
forall x. Rep Version x -> Version
forall x. Version -> Rep Version x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Version -> Rep Version x
from :: forall x. Version -> Rep Version x
$cto :: forall x. Rep Version x -> Version
to :: forall x. Rep Version x -> Version
Generic, Typeable)

instance Ord Version where
  compare :: Version -> Version -> Ordering
compare (PV0 Word64
x) (PV0 Word64
y) = Word64 -> Word64 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Word64
x Word64
y
  compare (PV1 Int
x [Int]
xs) (PV1 Int
y [Int]
ys) = case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
x Int
y of
    Ordering
EQ -> [Int] -> [Int] -> Ordering
forall a. Ord a => a -> a -> Ordering
compare [Int]
xs [Int]
ys
    Ordering
c -> Ordering
c
  compare (PV0 Word64
w) (PV1 Int
y [Int]
ys) = case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
x Int
y of
    Ordering
EQ -> [Int] -> [Int] -> Ordering
forall a. Ord a => a -> a -> Ordering
compare [Int
x2, Int
x3, Int
x4] [Int]
ys
    Ordering
c -> Ordering
c
    where
      x :: Int
x = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
48) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
      x2 :: Int
x2 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
      x3 :: Int
x3 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
16) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
      x4 :: Int
x4 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
  compare (PV1 Int
x [Int]
xs) (PV0 Word64
w) = case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
x Int
y of
    Ordering
EQ -> [Int] -> [Int] -> Ordering
forall a. Ord a => a -> a -> Ordering
compare [Int]
xs [Int
y2, Int
y3, Int
y4]
    Ordering
c -> Ordering
c
    where
      y :: Int
y = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
48) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
      y2 :: Int
y2 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
      y3 :: Int
y3 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
16) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
      y4 :: Int
y4 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1

instance Show Version where
  showsPrec :: Int -> Version -> ShowS
showsPrec Int
d Version
v =
    Bool -> ShowS -> ShowS
showParen (Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
      String -> ShowS
showString String
"mkVersion "
        ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Int] -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 (Version -> [Int]
versionNumbers Version
v)

instance Read Version where
  readPrec :: ReadPrec Version
readPrec = ReadPrec Version -> ReadPrec Version
forall a. ReadPrec a -> ReadPrec a
Read.parens (ReadPrec Version -> ReadPrec Version)
-> ReadPrec Version -> ReadPrec Version
forall a b. (a -> b) -> a -> b
$ do
    Read.Ident String
"mkVersion" <- ReadPrec Lexeme
Read.lexP
    [Int]
v <- ReadPrec [Int] -> ReadPrec [Int]
forall a. ReadPrec a -> ReadPrec a
Read.step ReadPrec [Int]
forall a. Read a => ReadPrec a
Read.readPrec
    Version -> ReadPrec Version
forall a. a -> ReadPrec a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Int] -> Version
mkVersion [Int]
v)

instance Binary Version
instance Structured Version

instance NFData Version where
  rnf :: Version -> ()
rnf (PV0 Word64
_) = ()
  rnf (PV1 Int
_ [Int]
ns) = [Int] -> ()
forall a. NFData a => a -> ()
rnf [Int]
ns

instance Pretty Version where
  pretty :: Version -> Doc
pretty Version
ver =
    [Doc] -> Doc
Disp.hcat
      ( Doc -> [Doc] -> [Doc]
Disp.punctuate
          (Char -> Doc
Disp.char Char
'.')
          ((Int -> Doc) -> [Int] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Doc
Disp.int ([Int] -> [Doc]) -> [Int] -> [Doc]
forall a b. (a -> b) -> a -> b
$ Version -> [Int]
versionNumbers Version
ver)
      )

instance Parsec Version where
  parsec :: forall (m :: * -> *). CabalParsing m => m Version
parsec = [Int] -> Version
mkVersion ([Int] -> Version)
-> (NonEmpty Int -> [Int]) -> NonEmpty Int -> Version
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty Int -> [Int]
forall a. NonEmpty a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (NonEmpty Int -> Version) -> m (NonEmpty Int) -> m Version
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Int -> m Char -> m (NonEmpty Int)
forall (m :: * -> *) a sep.
Alternative m =>
m a -> m sep -> m (NonEmpty a)
P.sepByNonEmpty m Int
forall (m :: * -> *). CabalParsing m => m Int
versionDigitParser (Char -> m Char
forall (m :: * -> *). CharParsing m => Char -> m Char
P.char Char
'.') m Version -> m () -> m Version
forall a b. m a -> m b -> m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* m ()
tags
    where
      tags :: m ()
tags = do
        [String]
ts <- m String -> m [String]
forall a. m a -> m [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many (m String -> m [String]) -> m String -> m [String]
forall a b. (a -> b) -> a -> b
$ Char -> m Char
forall (m :: * -> *). CharParsing m => Char -> m Char
P.char Char
'-' m Char -> m String -> m String
forall a b. m a -> m b -> m b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> m Char -> m String
forall a. m a -> m [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some ((Char -> Bool) -> m Char
forall (m :: * -> *). CharParsing m => (Char -> Bool) -> m Char
P.satisfy Char -> Bool
isAlphaNum)
        case [String]
ts of
          [] -> () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
          (String
_ : [String]
_) -> PWarnType -> String -> m ()
forall (m :: * -> *). CabalParsing m => PWarnType -> String -> m ()
parsecWarning PWarnType
PWTVersionTag String
"version with tags"

-- | An integral without leading zeroes.
--
-- @since 3.0
versionDigitParser :: CabalParsing m => m Int
versionDigitParser :: forall (m :: * -> *). CabalParsing m => m Int
versionDigitParser = (m Int -> m [Int]
forall a. m a -> m [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some m Int
forall (m :: * -> *). CharParsing m => m Int
d m [Int] -> ([Int] -> m Int) -> m Int
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [Int] -> m Int
forall (m :: * -> *). CabalParsing m => [Int] -> m Int
toNumber) m Int -> String -> m Int
forall a. m a -> String -> m a
forall (m :: * -> *) a. Parsing m => m a -> String -> m a
P.<?> String
"version digit (integral without leading zeroes)"
  where
    toNumber :: CabalParsing m => [Int] -> m Int
    toNumber :: forall (m :: * -> *). CabalParsing m => [Int] -> m Int
toNumber [Int
0] = Int -> m Int
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
0
    toNumber (Int
0 : [Int]
_) = String -> m Int
forall a. String -> m a
forall (m :: * -> *) a. Parsing m => String -> m a
P.unexpected String
"Version digit with leading zero"
    toNumber [Int]
xs
      -- 10^9 = 1000000000
      -- 2^30 = 1073741824
      --
      -- GHC Int is at least 32 bits, so 2^31-1 is the 'maxBound'.
      | [Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Int]
xs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
9 = String -> m Int
forall a. String -> m a
forall (m :: * -> *) a. Parsing m => String -> m a
P.unexpected String
"At most 9 numbers are allowed per version number part"
      | Bool
otherwise = Int -> m Int
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> m Int) -> Int -> m Int
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Int) -> Int -> [Int] -> Int
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Int
a Int
b -> Int
a Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
10 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
b) Int
0 [Int]
xs

    d :: P.CharParsing m => m Int
    d :: forall (m :: * -> *). CharParsing m => m Int
d = Char -> Int
f (Char -> Int) -> m Char -> m Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Char -> Char -> m Char
forall (m :: * -> *). CharParsing m => Char -> Char -> m Char
P.satisfyRange Char
'0' Char
'9'
    f :: Char -> Int
f Char
c = Char -> Int
ord Char
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Char -> Int
ord Char
'0'

-- | Construct 'Version' from list of version number components.
--
-- For instance, @mkVersion [3,2,1]@ constructs a 'Version'
-- representing the version @3.2.1@.
--
-- All version components must be non-negative. @mkVersion []@
-- currently represents the special /null/ version; see also 'nullVersion'.
--
-- @since 2.0.0.2
mkVersion :: [Int] -> Version
-- TODO: add validity check; disallow 'mkVersion []' (we have
-- 'nullVersion' for that)
mkVersion :: [Int] -> Version
mkVersion [] = Version
nullVersion
mkVersion (Int
v1 : [])
  | Int -> Bool
inWord16VerRep1 Int
v1 = Word64 -> Version
PV0 (Int -> Word64
mkWord64VerRep1 Int
v1)
  | Bool
otherwise = Int -> [Int] -> Version
PV1 Int
v1 []
  where
    inWord16VerRep1 :: Int -> Bool
inWord16VerRep1 Int
x1 = Int -> Bool
inWord16 (Int
x1 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))
    mkWord64VerRep1 :: Int -> Word64
mkWord64VerRep1 Int
y1 = Int -> Int -> Int -> Int -> Word64
mkWord64VerRep (Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
0 Int
0 Int
0
mkVersion (Int
v1 : vs :: [Int]
vs@(Int
v2 : []))
  | Int -> Int -> Bool
inWord16VerRep2 Int
v1 Int
v2 = Word64 -> Version
PV0 (Int -> Int -> Word64
mkWord64VerRep2 Int
v1 Int
v2)
  | Bool
otherwise = Int -> [Int] -> Version
PV1 Int
v1 [Int]
vs
  where
    inWord16VerRep2 :: Int -> Int -> Bool
inWord16VerRep2 Int
x1 Int
x2 =
      Int -> Bool
inWord16
        ( Int
x1
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
x2
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
        )
    mkWord64VerRep2 :: Int -> Int -> Word64
mkWord64VerRep2 Int
y1 Int
y2 = Int -> Int -> Int -> Int -> Word64
mkWord64VerRep (Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
y2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
0 Int
0
mkVersion (Int
v1 : vs :: [Int]
vs@(Int
v2 : Int
v3 : []))
  | Int -> Int -> Int -> Bool
inWord16VerRep3 Int
v1 Int
v2 Int
v3 = Word64 -> Version
PV0 (Int -> Int -> Int -> Word64
mkWord64VerRep3 Int
v1 Int
v2 Int
v3)
  | Bool
otherwise = Int -> [Int] -> Version
PV1 Int
v1 [Int]
vs
  where
    inWord16VerRep3 :: Int -> Int -> Int -> Bool
inWord16VerRep3 Int
x1 Int
x2 Int
x3 =
      Int -> Bool
inWord16
        ( Int
x1
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
x2
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
x3
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x3 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
        )
    mkWord64VerRep3 :: Int -> Int -> Int -> Word64
mkWord64VerRep3 Int
y1 Int
y2 Int
y3 = Int -> Int -> Int -> Int -> Word64
mkWord64VerRep (Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
y2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
y3 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
0
mkVersion (Int
v1 : vs :: [Int]
vs@(Int
v2 : Int
v3 : Int
v4 : []))
  | Int -> Int -> Int -> Int -> Bool
inWord16VerRep4 Int
v1 Int
v2 Int
v3 Int
v4 = Word64 -> Version
PV0 (Int -> Int -> Int -> Int -> Word64
mkWord64VerRep4 Int
v1 Int
v2 Int
v3 Int
v4)
  | Bool
otherwise = Int -> [Int] -> Version
PV1 Int
v1 [Int]
vs
  where
    inWord16VerRep4 :: Int -> Int -> Int -> Int -> Bool
inWord16VerRep4 Int
x1 Int
x2 Int
x3 Int
x4 =
      Int -> Bool
inWord16
        ( Int
x1
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
x2
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
x3
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x3 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int
x4
            Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
x4 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
        )
    mkWord64VerRep4 :: Int -> Int -> Int -> Int -> Word64
mkWord64VerRep4 Int
y1 Int
y2 Int
y3 Int
y4 = Int -> Int -> Int -> Int -> Word64
mkWord64VerRep (Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
y2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
y3 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
y4 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
mkVersion (Int
v1 : [Int]
vs) = Int -> [Int] -> Version
PV1 Int
v1 [Int]
vs

-- | Version 0. A lower bound of 'Version'.
--
-- @since 2.2
version0 :: Version
version0 :: Version
version0 = [Int] -> Version
mkVersion [Int
0]

{-# INLINE mkWord64VerRep #-}
mkWord64VerRep :: Int -> Int -> Int -> Int -> Word64
mkWord64VerRep :: Int -> Int -> Int -> Int -> Word64
mkWord64VerRep Int
v1 Int
v2 Int
v3 Int
v4 =
  (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
48)
    Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
32)
    Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v3 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
16)
    Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v4

{-# INLINE inWord16 #-}
inWord16 :: Int -> Bool
inWord16 :: Int -> Bool
inWord16 Int
x = (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x :: Word) Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
<= Word
0xffff

-- | Variant of 'mkVersion' which converts a "Data.Version"
-- 'Base.Version' into Cabal's 'Version' type.
--
-- @since 2.0.0.2
mkVersion' :: Base.Version -> Version
mkVersion' :: Version -> Version
mkVersion' = [Int] -> Version
mkVersion ([Int] -> Version) -> (Version -> [Int]) -> Version -> Version
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> [Int]
Base.versionBranch

-- | Unpack 'Version' into list of version number components.
--
-- This is the inverse to 'mkVersion', so the following holds:
--
-- > (versionNumbers . mkVersion) vs == vs
--
-- @since 2.0.0.2
versionNumbers :: Version -> [Int]
versionNumbers :: Version -> [Int]
versionNumbers (PV1 Int
n [Int]
ns) = Int
n Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
ns
versionNumbers (PV0 Word64
w)
  | Int
v1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = []
  | Int
v2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = [Int
v1]
  | Int
v3 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = [Int
v1, Int
v2]
  | Int
v4 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = [Int
v1, Int
v2, Int
v3]
  | Bool
otherwise = [Int
v1, Int
v2, Int
v3, Int
v4]
  where
    v1 :: Int
v1 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
48) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
    v2 :: Int
v2 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
32) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
    v3 :: Int
v3 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Word64
w Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
16) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
    v4 :: Int
v4 = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xffff) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1

-- | Constant representing the special /null/ 'Version'
--
-- The 'nullVersion' compares (via 'Ord') as less than every proper
-- 'Version' value.
--
-- @since 2.0.0.2
nullVersion :: Version
-- TODO: at some point, 'mkVersion' may disallow creating /null/
-- 'Version's
nullVersion :: Version
nullVersion = Word64 -> Version
PV0 Word64
0

-- | Apply function to list of version number components
--
-- > alterVersion f == mkVersion . f . versionNumbers
--
-- @since 2.0.0.2
alterVersion :: ([Int] -> [Int]) -> Version -> Version
alterVersion :: ([Int] -> [Int]) -> Version -> Version
alterVersion [Int] -> [Int]
f = [Int] -> Version
mkVersion ([Int] -> Version) -> (Version -> [Int]) -> Version -> Version
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> [Int]
f ([Int] -> [Int]) -> (Version -> [Int]) -> Version -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Version -> [Int]
versionNumbers

-- internal helper
validVersion :: Version -> Bool
validVersion :: Version -> Bool
validVersion Version
v = Version
v Version -> Version -> Bool
forall a. Eq a => a -> a -> Bool
/= Version
nullVersion Bool -> Bool -> Bool
&& (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0) (Version -> [Int]
versionNumbers Version
v)