packages feed

seihou-cli-0.16.0.0: src/Seihou/CLI/Update/Rebinding.hs

-- | Match invocation history before resolving candidate inputs. Exact identities
-- win; only a unique remaining pair may carry history across changed bindings.
module Seihou.CLI.Update.Rebinding (alignPriorInstances, carriedSavedValues) where

import Data.Generics.Labels ()
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Seihou.CLI.Update.Types
import Seihou.Composition.Instance (ModuleInstance (..))
import Seihou.Composition.Resolve (SavedInstanceValues)
import Seihou.Core.Types
import Seihou.Prelude

alignPriorInstances :: AppliedComposition -> [ModuleInstance] -> PriorAlignment
alignPriorInstances previous candidates = foldl' align (PriorAlignment exact [] []) names
  where
    recorded = Map.fromList [(ModuleInstance (s ^. #name) (s ^. #parentVars), s) | s <- previous ^. #instances]
    candidateSet = Set.fromList candidates
    exact = Map.restrictKeys recorded candidateSet
    old = Map.withoutKeys recorded candidateSet
    new = candidateSet `Set.difference` Map.keysSet recorded
    names = Set.toAscList (Set.map (^. #module_) new)
    align result name =
      case (filter ((== name) . (^. #module_)) (Set.toAscList new), filter ((== name) . (^. #module_) . fst) (Map.toAscList old)) of
        ([candidate], [(priorId, prior)]) ->
          result
            & #priors
            %~ Map.insert candidate prior
            & #rebindings
            %~ (<> [InstanceRebinding (previous ^. #applicationId) name (priorId ^. #parentVars) (candidate ^. #parentVars)])
        (cs@(_ : _), os@(_ : _)) ->
          result & #unpaired %~ (<> [UnpairedInstances (previous ^. #applicationId) name (map ((^. #parentVars) . fst) os) (map (^. #parentVars) cs)])
        _ -> result

carriedSavedValues :: PriorAlignment -> SavedInstanceValues
carriedSavedValues alignment = Map.mapWithKey carry (alignment ^. #priors)
  where
    carry candidate prior
      | candidate ^. #parentVars == prior ^. #parentVars = prior ^. #resolvedVars
      | otherwise =
          let ParentVars old = prior ^. #parentVars
              ParentVars new = candidate ^. #parentVars
           in Map.filterWithKey (\key value -> Map.notMember key new && Map.lookup key old /= Just value) (prior ^. #resolvedVars)