haskell-nix / hnix-store

Haskell implementation of the Nix store
Apache License 2.0
87 stars 23 forks source link

Reintroduce typelevel root paths, turn current `StorePath` into `SomeStorePath` #148

Open sorki opened 3 years ago

sorki commented 3 years ago

While playing with safe-money library, I've realized that we don't need to commit on TypeLits and type level only StorePath and we can have both variants and couple of utility functions to turn one into other when/if needed.

I've quickly drafted the following (quite similar to Dense and SomeDense from safe-money + some questionable field duplication) and it looks plausible. After it compiled I went and checked prior implementation by @shlevy and it's quite similar, with the difference that this allows SomeStorePaths when we don't know/care about store root.

data StorePath = StorePath
  { -- | The 160-bit hash digest reflecting the "address" of the name.
    -- Currently, this is a truncated SHA256 hash.
    storePathHash :: !(Digest StorePathHashAlgo)
  , -- | The (typically human readable) name of the path. For packages
    -- this is typically the package name and version (e.g.
    -- hello-1.2.3).
    storePathName :: !StorePathName
  }
  deriving (Eq, Ord)

newtype SymbolicStorePath (root :: Symbol) = SymbolicStorePath StorePath
  deriving (Eq, Ord)

data SomeStorePath = SomeStorePath {
    someStorePathHash :: !(Digest StorePathHashAlgo)
  , -- | The (typically human readable) name of the path. For packages
    -- this is typically the package name and version (e.g.
    -- hello-1.2.3).
    someStorePathName :: !StorePathName
  , -- | Root of the store
    someStorePathRoot :: !FilePath
  } deriving (Eq, Ord)

fromSomePath
  :: forall root
  .  KnownSymbol root
  => SomeStorePath
  -> Maybe (SymbolicStorePath root)
fromSomePath SomeStorePath{..} =
  if (someStorePathRoot == symbolVal @root Proxy)
  then Just $ SymbolicStorePath $ StorePath { storePathHash = someStorePathHash, storePathName = someStorePathName }
  else Nothing

withSomePath
  :: SomeStorePath
  -> (forall root. KnownSymbol root => SymbolicStorePath root -> a)
  -> a