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

    module Distribution.Types.Mixin (
        Mixin(..),
        mkMixin,
        normaliseMixin,
    ) where

    import Distribution.Compat.Prelude
    import Prelude ()

    import Distribution.CabalSpecVersion
    import Distribution.Parsec
    import Distribution.Pretty
    import Distribution.Types.IncludeRenaming
    import Distribution.Types.LibraryName
    import Distribution.Types.PackageName
    import Distribution.Types.UnqualComponentName

    import qualified Distribution.Compat.CharParsing as P
    import qualified Text.PrettyPrint                as PP

    -- |
    --
    -- /Invariant:/ if 'mixinLibraryName' is 'LSubLibName', it's not
    -- the same as 'mixinPackageName'. In other words,
    -- the same invariant as 'Dependency' has.
    --
    data Mixin = Mixin { Mixin -> PackageName
    mixinPackageName :: PackageName
                       , Mixin -> LibraryName
    mixinLibraryName :: LibraryName
                       , Mixin -> IncludeRenaming
    mixinIncludeRenaming :: IncludeRenaming }
        deriving (Int -> Mixin -> ShowS
    [Mixin] -> ShowS
    Mixin -> String
    (Int -> Mixin -> ShowS)
    -> (Mixin -> String) -> ([Mixin] -> ShowS) -> Show Mixin
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Mixin -> ShowS
    showsPrec :: Int -> Mixin -> ShowS
    $cshow :: Mixin -> String
    show :: Mixin -> String
    $cshowList :: [Mixin] -> ShowS
    showList :: [Mixin] -> ShowS
    Show, ReadPrec [Mixin]
    ReadPrec Mixin
    Int -> ReadS Mixin
    ReadS [Mixin]
    (Int -> ReadS Mixin)
    -> ReadS [Mixin]
    -> ReadPrec Mixin
    -> ReadPrec [Mixin]
    -> Read Mixin
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS Mixin
    readsPrec :: Int -> ReadS Mixin
    $creadList :: ReadS [Mixin]
    readList :: ReadS [Mixin]
    $creadPrec :: ReadPrec Mixin
    readPrec :: ReadPrec Mixin
    $creadListPrec :: ReadPrec [Mixin]
    readListPrec :: ReadPrec [Mixin]
    Read, Mixin -> Mixin -> Bool
    (Mixin -> Mixin -> Bool) -> (Mixin -> Mixin -> Bool) -> Eq Mixin
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Mixin -> Mixin -> Bool
    == :: Mixin -> Mixin -> Bool
    $c/= :: Mixin -> Mixin -> Bool
    /= :: Mixin -> Mixin -> Bool
    Eq, Eq Mixin
    Eq Mixin
    -> (Mixin -> Mixin -> Ordering)
    -> (Mixin -> Mixin -> Bool)
    -> (Mixin -> Mixin -> Bool)
    -> (Mixin -> Mixin -> Bool)
    -> (Mixin -> Mixin -> Bool)
    -> (Mixin -> Mixin -> Mixin)
    -> (Mixin -> Mixin -> Mixin)
    -> Ord Mixin
    Mixin -> Mixin -> Bool
    Mixin -> Mixin -> Ordering
    Mixin -> Mixin -> Mixin
    forall a.
    Eq a
    -> (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Mixin -> Mixin -> Ordering
    compare :: Mixin -> Mixin -> Ordering
    $c< :: Mixin -> Mixin -> Bool
    < :: Mixin -> Mixin -> Bool
    $c<= :: Mixin -> Mixin -> Bool
    <= :: Mixin -> Mixin -> Bool
    $c> :: Mixin -> Mixin -> Bool
    > :: Mixin -> Mixin -> Bool
    $c>= :: Mixin -> Mixin -> Bool
    >= :: Mixin -> Mixin -> Bool
    $cmax :: Mixin -> Mixin -> Mixin
    max :: Mixin -> Mixin -> Mixin
    $cmin :: Mixin -> Mixin -> Mixin
    min :: Mixin -> Mixin -> Mixin
    Ord, Typeable, Typeable Mixin
    Typeable Mixin
    -> (forall (c :: * -> *).
        (forall d b. Data d => c (d -> b) -> d -> c b)
        -> (forall g. g -> c g) -> Mixin -> c Mixin)
    -> (forall (c :: * -> *).
        (forall b r. Data b => c (b -> r) -> c r)
        -> (forall r. r -> c r) -> Constr -> c Mixin)
    -> (Mixin -> Constr)
    -> (Mixin -> DataType)
    -> (forall (t :: * -> *) (c :: * -> *).
        Typeable t =>
        (forall d. Data d => c (t d)) -> Maybe (c Mixin))
    -> (forall (t :: * -> * -> *) (c :: * -> *).
        Typeable t =>
        (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Mixin))
    -> ((forall b. Data b => b -> b) -> Mixin -> Mixin)
    -> (forall r r'.
        (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r)
    -> (forall r r'.
        (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r)
    -> (forall u. (forall d. Data d => d -> u) -> Mixin -> [u])
    -> (forall u. Int -> (forall d. Data d => d -> u) -> Mixin -> u)
    -> (forall (m :: * -> *).
        Monad m =>
        (forall d. Data d => d -> m d) -> Mixin -> m Mixin)
    -> (forall (m :: * -> *).
        MonadPlus m =>
        (forall d. Data d => d -> m d) -> Mixin -> m Mixin)
    -> (forall (m :: * -> *).
        MonadPlus m =>
        (forall d. Data d => d -> m d) -> Mixin -> m Mixin)
    -> Data Mixin
    Mixin -> Constr
    Mixin -> DataType
    (forall b. Data b => b -> b) -> Mixin -> Mixin
    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) -> Mixin -> u
    forall u. (forall d. Data d => d -> u) -> Mixin -> [u]
    forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r
    forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r
    forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Mixin
    forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Mixin -> c Mixin
    forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Mixin)
    forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Mixin)
    $cgfoldl :: forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Mixin -> c Mixin
    gfoldl :: forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Mixin -> c Mixin
    $cgunfold :: forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Mixin
    gunfold :: forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Mixin
    $ctoConstr :: Mixin -> Constr
    toConstr :: Mixin -> Constr
    $cdataTypeOf :: Mixin -> DataType
    dataTypeOf :: Mixin -> DataType
    $cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Mixin)
    dataCast1 :: forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Mixin)
    $cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Mixin)
    dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Mixin)
    $cgmapT :: (forall b. Data b => b -> b) -> Mixin -> Mixin
    gmapT :: (forall b. Data b => b -> b) -> Mixin -> Mixin
    $cgmapQl :: forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r
    gmapQl :: forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r
    $cgmapQr :: forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r
    gmapQr :: forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Mixin -> r
    $cgmapQ :: forall u. (forall d. Data d => d -> u) -> Mixin -> [u]
    gmapQ :: forall u. (forall d. Data d => d -> u) -> Mixin -> [u]
    $cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Mixin -> u
    gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Mixin -> u
    $cgmapM :: forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    gmapM :: forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    $cgmapMp :: forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    gmapMp :: forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    $cgmapMo :: forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    gmapMo :: forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Mixin -> m Mixin
    Data, (forall x. Mixin -> Rep Mixin x)
    -> (forall x. Rep Mixin x -> Mixin) -> Generic Mixin
    forall x. Rep Mixin x -> Mixin
    forall x. Mixin -> Rep Mixin x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. Mixin -> Rep Mixin x
    from :: forall x. Mixin -> Rep Mixin x
    $cto :: forall x. Rep Mixin x -> Mixin
    to :: forall x. Rep Mixin x -> Mixin
    Generic)

    instance Binary Mixin
    instance Structured Mixin

    instance NFData Mixin where rnf :: Mixin -> ()
    rnf = Mixin -> ()
    forall a. (Generic a, GNFData (Rep a)) => a -> ()
    genericRnf

    instance Pretty Mixin where
        pretty :: Mixin -> Doc
    pretty (Mixin PackageName
    pn LibraryName
    LMainLibName IncludeRenaming
    incl)     = PackageName -> Doc
    forall a. Pretty a => a -> Doc
    pretty PackageName
    pn Doc -> Doc -> Doc
    <+> IncludeRenaming -> Doc
    forall a. Pretty a => a -> Doc
    pretty IncludeRenaming
    incl
        pretty (Mixin PackageName
    pn (LSubLibName UnqualComponentName
    ln) IncludeRenaming
    incl) = PackageName -> Doc
    forall a. Pretty a => a -> Doc
    pretty PackageName
    pn Doc -> Doc -> Doc
    <<>> Doc
    PP.colon Doc -> Doc -> Doc
    <<>> UnqualComponentName -> Doc
    forall a. Pretty a => a -> Doc
    pretty UnqualComponentName
    ln Doc -> Doc -> Doc
    <+> IncludeRenaming -> Doc
    forall a. Pretty a => a -> Doc
    pretty IncludeRenaming
    incl

    -- |
    --
    -- >>>  simpleParsec "mylib" :: Maybe Mixin
    -- Just (Mixin {mixinPackageName = PackageName "mylib", mixinLibraryName = LMainLibName, mixinIncludeRenaming = IncludeRenaming {includeProvidesRn = DefaultRenaming, includeRequiresRn = DefaultRenaming}})
    --
    -- >>>  simpleParsec "thatlib:sublib" :: Maybe Mixin
    -- Just (Mixin {mixinPackageName = PackageName "thatlib", mixinLibraryName = LSubLibName (UnqualComponentName "sublib"), mixinIncludeRenaming = IncludeRenaming {includeProvidesRn = DefaultRenaming, includeRequiresRn = DefaultRenaming}})
    --
    -- >>>  simpleParsec "thatlib:thatlib" :: Maybe Mixin
    -- Just (Mixin {mixinPackageName = PackageName "thatlib", mixinLibraryName = LMainLibName, mixinIncludeRenaming = IncludeRenaming {includeProvidesRn = DefaultRenaming, includeRequiresRn = DefaultRenaming}})
    --
    -- Sublibrary syntax is accepted since @cabal-version: 3.4@.
    --
    -- >>> map (`simpleParsec'` "mylib:sub") [CabalSpecV3_0, CabalSpecV3_4] :: [Maybe Mixin]
    -- [Nothing,Just (Mixin {mixinPackageName = PackageName "mylib", mixinLibraryName = LSubLibName (UnqualComponentName "sub"), mixinIncludeRenaming = IncludeRenaming {includeProvidesRn = DefaultRenaming, includeRequiresRn = DefaultRenaming}})]
    --
    instance Parsec Mixin where
        parsec :: forall (m :: * -> *). CabalParsing m => m Mixin
    parsec = do
            PackageName
    pn <- m PackageName
    forall a (m :: * -> *). (Parsec a, CabalParsing m) => m a
    forall (m :: * -> *). CabalParsing m => m PackageName
    parsec
            LibraryName
    ln <- LibraryName -> m LibraryName -> m LibraryName
    forall (m :: * -> *) a. Alternative m => a -> m a -> m a
    P.option LibraryName
    LMainLibName (m LibraryName -> m LibraryName) -> m LibraryName -> m LibraryName
    forall a b. (a -> b) -> a -> b
    $ do
                Char
    _ <- Char -> m Char
    forall (m :: * -> *). CharParsing m => Char -> m Char
    P.char Char
    ':'
                m ()
    forall (m :: * -> *). CabalParsing m => m ()
    versionGuardMultilibs
                PWarnType -> String -> m ()
    forall (m :: * -> *). CabalParsing m => PWarnType -> String -> m ()
    parsecWarning PWarnType
    PWTExperimental String
    "colon specifier is experimental feature (issue #5660)"
                UnqualComponentName -> LibraryName
    LSubLibName (UnqualComponentName -> LibraryName)
    -> m UnqualComponentName -> m LibraryName
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> m UnqualComponentName
    forall a (m :: * -> *). (Parsec a, CabalParsing m) => m a
    forall (m :: * -> *). CabalParsing m => m UnqualComponentName
    parsec
            m ()
    forall (m :: * -> *). CharParsing m => m ()
    P.spaces
            IncludeRenaming
    incl <- m IncludeRenaming
    forall a (m :: * -> *). (Parsec a, CabalParsing m) => m a
    forall (m :: * -> *). CabalParsing m => m IncludeRenaming
    parsec
            Mixin -> m Mixin
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (PackageName -> LibraryName -> IncludeRenaming -> Mixin
    mkMixin PackageName
    pn LibraryName
    ln IncludeRenaming
    incl)
          where

    versionGuardMultilibs :: CabalParsing m => m ()
    versionGuardMultilibs :: forall (m :: * -> *). CabalParsing m => m ()
    versionGuardMultilibs = do
      CabalSpecVersion
    csv <- m CabalSpecVersion
    forall (m :: * -> *). CabalParsing m => m CabalSpecVersion
    askCabalSpecVersion
      Bool -> m () -> m ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (CabalSpecVersion
    csv CabalSpecVersion -> CabalSpecVersion -> Bool
    forall a. Ord a => a -> a -> Bool
    < CabalSpecVersion
    CabalSpecV3_4) (m () -> m ()) -> m () -> m ()
    forall a b. (a -> b) -> a -> b
    $ String -> m ()
    forall a. String -> m a
    forall (m :: * -> *) a. MonadFail m => String -> m a
    fail (String -> m ()) -> String -> m ()
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unwords
        [ String
    "Sublibrary mixin syntax used."
        , String
    "To use this syntax the package needs to specify at least 'cabal-version: 3.4'."
        ]

    -- | Smart constructor of 'Mixin', enforces invariant.
    --
    -- @since 3.4.0.0
    mkMixin :: PackageName -> LibraryName -> IncludeRenaming -> Mixin
    mkMixin :: PackageName -> LibraryName -> IncludeRenaming -> Mixin
    mkMixin PackageName
    pn (LSubLibName UnqualComponentName
    uqn) IncludeRenaming
    incl
        | PackageName -> UnqualComponentName
    packageNameToUnqualComponentName PackageName
    pn UnqualComponentName -> UnqualComponentName -> Bool
    forall a. Eq a => a -> a -> Bool
    == UnqualComponentName
    uqn
        = PackageName -> LibraryName -> IncludeRenaming -> Mixin
    Mixin PackageName
    pn LibraryName
    LMainLibName IncludeRenaming
    incl
    mkMixin PackageName
    pn LibraryName
    ln IncludeRenaming
    incl
        = PackageName -> LibraryName -> IncludeRenaming -> Mixin
    Mixin PackageName
    pn LibraryName
    ln IncludeRenaming
    incl

    -- | Restore invariant
    normaliseMixin :: Mixin -> Mixin
    normaliseMixin :: Mixin -> Mixin
    normaliseMixin (Mixin PackageName
    pn LibraryName
    ln IncludeRenaming
    incl) = PackageName -> LibraryName -> IncludeRenaming -> Mixin
    mkMixin PackageName
    pn LibraryName
    ln IncludeRenaming
    incl