-- | See <https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst>
module Distribution.Backpack.PreExistingComponent
  ( PreExistingComponent (..)
  , PromisedComponent (..)
  , ipiToPreExistingComponent
  ) where

import Distribution.Compat.Prelude
import Prelude ()

import Distribution.Backpack
import Distribution.Backpack.ModuleShape
import Distribution.Package
import Distribution.Types.ComponentName
import Distribution.Types.MungedPackageId

import qualified Data.Map as Map
import Distribution.InstalledPackageInfo (InstalledPackageInfo)
import qualified Distribution.InstalledPackageInfo as Installed
import Distribution.Types.AnnotatedId

-- | A /promised/ component.
--
-- These components are promised to @configure@ but are not yet built.
--
-- In other words this is 'PreExistingComponent' which doesn't yet exist.
data PromisedComponent = PromisedComponent
  { PromisedComponent -> PackageName
pr_pkgname :: PackageName
  , PromisedComponent -> AnnotatedId ComponentId
pr_cid :: AnnotatedId ComponentId
  }

instance Package PromisedComponent where
  packageId :: PromisedComponent -> PackageIdentifier
packageId = AnnotatedId ComponentId -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId (AnnotatedId ComponentId -> PackageIdentifier)
-> (PromisedComponent -> AnnotatedId ComponentId)
-> PromisedComponent
-> PackageIdentifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PromisedComponent -> AnnotatedId ComponentId
pr_cid

-- | Stripped down version of 'LinkedComponent' for things
-- we don't need to know how to build.
data PreExistingComponent = PreExistingComponent
  { PreExistingComponent -> PackageName
pc_pkgname :: PackageName
  -- ^ The actual name of the package. This may DISAGREE with 'pc_pkgid'
  -- for internal dependencies: e.g., an internal component @lib@ may be
  -- munged to @z-pkg-z-lib@, but we still want to use it when we see
  -- @lib@ in @build-depends@
  , PreExistingComponent -> ComponentName
pc_compname :: ComponentName
  -- ^ The actual name of the component.
  , PreExistingComponent -> MungedPackageId
pc_munged_id :: MungedPackageId
  , PreExistingComponent -> UnitId
pc_uid :: UnitId
  , PreExistingComponent -> ComponentId
pc_cid :: ComponentId
  , PreExistingComponent -> OpenUnitId
pc_open_uid :: OpenUnitId
  , PreExistingComponent -> ModuleShape
pc_shape :: ModuleShape
  }

-- | Convert an 'InstalledPackageInfo' into a 'PreExistingComponent',
-- which was brought into scope under the 'PackageName' (important for
-- a package qualified reference.)
ipiToPreExistingComponent :: InstalledPackageInfo -> PreExistingComponent
ipiToPreExistingComponent :: InstalledPackageInfo -> PreExistingComponent
ipiToPreExistingComponent InstalledPackageInfo
ipi =
  PreExistingComponent
    { pc_pkgname :: PackageName
pc_pkgname = InstalledPackageInfo -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName InstalledPackageInfo
ipi
    , pc_compname :: ComponentName
pc_compname = LibraryName -> ComponentName
CLibName (LibraryName -> ComponentName) -> LibraryName -> ComponentName
forall a b. (a -> b) -> a -> b
$ InstalledPackageInfo -> LibraryName
Installed.sourceLibName InstalledPackageInfo
ipi
    , pc_munged_id :: MungedPackageId
pc_munged_id = InstalledPackageInfo -> MungedPackageId
forall pkg. HasMungedPackageId pkg => pkg -> MungedPackageId
mungedId InstalledPackageInfo
ipi
    , pc_uid :: UnitId
pc_uid = InstalledPackageInfo -> UnitId
Installed.installedUnitId InstalledPackageInfo
ipi
    , pc_cid :: ComponentId
pc_cid = InstalledPackageInfo -> ComponentId
Installed.installedComponentId InstalledPackageInfo
ipi
    , pc_open_uid :: OpenUnitId
pc_open_uid =
        ComponentId -> OpenModuleSubst -> OpenUnitId
IndefFullUnitId
          (InstalledPackageInfo -> ComponentId
Installed.installedComponentId InstalledPackageInfo
ipi)
          ([(ModuleName, OpenModule)] -> OpenModuleSubst
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList (InstalledPackageInfo -> [(ModuleName, OpenModule)]
Installed.instantiatedWith InstalledPackageInfo
ipi))
    , pc_shape :: ModuleShape
pc_shape = InstalledPackageInfo -> ModuleShape
shapeInstalledPackage InstalledPackageInfo
ipi
    }

instance HasMungedPackageId PreExistingComponent where
  mungedId :: PreExistingComponent -> MungedPackageId
mungedId = PreExistingComponent -> MungedPackageId
pc_munged_id

instance Package PreExistingComponent where
  packageId :: PreExistingComponent -> PackageIdentifier
packageId PreExistingComponent
pec = PackageName -> Version -> PackageIdentifier
PackageIdentifier (PreExistingComponent -> PackageName
pc_pkgname PreExistingComponent
pec) Version
v
    where
      MungedPackageId MungedPackageName
_ Version
v = PreExistingComponent -> MungedPackageId
pc_munged_id PreExistingComponent
pec

instance HasUnitId PreExistingComponent where
  installedUnitId :: PreExistingComponent -> UnitId
installedUnitId = PreExistingComponent -> UnitId
pc_uid