module Hix.Managed.Diff where

import Hix.Class.Map (NMap, nAmend, nMap)
import Hix.Data.Version (Version)
import qualified Hix.Data.VersionBounds
import Hix.Data.VersionBounds (anyBounds, VersionBounds)
import Hix.Managed.Data.Diff (BoundsChange, BoundsDiffDetail (..), Change (..), Diff (..), VersionChange)
import Hix.Managed.Data.Mutable (MutableBounds, MutableDep, MutableDeps, MutableVersions)
import Hix.These (maybeThese)

diffOriginal :: Diff d a -> Maybe a
diffOriginal :: forall d a. Diff d a -> Maybe a
diffOriginal = \case
  DiffChanged a
original a
_ d
_ -> a -> Maybe a
forall a. a -> Maybe a
Just a
original
  Diff d a
_ -> Maybe a
forall a. Maybe a
Nothing

changeOriginal :: Change d a -> Maybe a
changeOriginal :: forall d a. Change d a -> Maybe a
changeOriginal = \case
  Unchanged Maybe a
original -> Maybe a
original
  Changed Diff d a
d -> Diff d a -> Maybe a
forall d a. Diff d a -> Maybe a
diffOriginal Diff d a
d

reifyChangeWith :: b -> (a -> b) -> Change d a -> b
reifyChangeWith :: forall b a d. b -> (a -> b) -> Change d a -> b
reifyChangeWith b
absent a -> b
f = \case
  Unchanged Maybe a
Nothing -> b
absent
  Unchanged (Just a
a) -> a -> b
f a
a
  Changed (DiffAdded a
a) -> a -> b
f a
a
  Changed (DiffChanged a
_ a
a d
_) -> a -> b
f a
a

reifyChange :: a -> Change d a -> a
reifyChange :: forall a d. a -> Change d a -> a
reifyChange a
absent = a -> (a -> a) -> Change d a -> a
forall b a d. b -> (a -> b) -> Change d a -> b
reifyChangeWith a
absent a -> a
forall a. a -> a
id

reifyChangeMaybe :: Change d a -> Maybe a
reifyChangeMaybe :: forall d a. Change d a -> Maybe a
reifyChangeMaybe = Maybe a -> (a -> Maybe a) -> Change d a -> Maybe a
forall b a d. b -> (a -> b) -> Change d a -> b
reifyChangeWith Maybe a
forall a. Maybe a
Nothing a -> Maybe a
forall a. a -> Maybe a
Just

reifyBoundsChangeMaybe :: BoundsChange -> Maybe VersionBounds
reifyBoundsChangeMaybe :: BoundsChange -> Maybe VersionBounds
reifyBoundsChangeMaybe = BoundsChange -> Maybe VersionBounds
forall d a. Change d a -> Maybe a
reifyChangeMaybe

reifyBoundsChange :: BoundsChange -> VersionBounds
reifyBoundsChange :: BoundsChange -> VersionBounds
reifyBoundsChange = VersionBounds -> BoundsChange -> VersionBounds
forall a d. a -> Change d a -> a
reifyChange VersionBounds
anyBounds

reifyBoundsChanges :: MutableDeps BoundsChange -> MutableBounds
reifyBoundsChanges :: MutableDeps BoundsChange -> MutableBounds
reifyBoundsChanges = (BoundsChange -> VersionBounds)
-> MutableDeps BoundsChange -> MutableBounds
forall map1 k v1 sort1 map2 v2 sort2.
(NMap map1 k v1 sort1, NMap map2 k v2 sort2) =>
(v1 -> v2) -> map1 -> map2
nMap BoundsChange -> VersionBounds
reifyBoundsChange

reifyVersionChange :: VersionChange -> Maybe Version
reifyVersionChange :: VersionChange -> Maybe Version
reifyVersionChange = VersionChange -> Maybe Version
forall d a. Change d a -> Maybe a
reifyChangeMaybe

reifyVersionChanges :: MutableDeps VersionChange -> MutableVersions
reifyVersionChanges :: MutableDeps VersionChange -> MutableVersions
reifyVersionChanges = (VersionChange -> Maybe Version)
-> MutableDeps VersionChange -> MutableVersions
forall map1 k v1 sort1 map2 v2 sort2.
(NMap map1 k v1 sort1, NMap map2 k v2 sort2) =>
(v1 -> v2) -> map1 -> map2
nMap VersionChange -> Maybe Version
reifyVersionChange

applyVersionChange :: VersionChange -> Maybe Version -> Maybe Version
applyVersionChange :: VersionChange -> Maybe Version -> Maybe Version
applyVersionChange VersionChange
d Maybe Version
_ = VersionChange -> Maybe Version
reifyVersionChange VersionChange
d

applyBoundsChange :: BoundsChange -> VersionBounds -> VersionBounds
applyBoundsChange :: BoundsChange -> VersionBounds -> VersionBounds
applyBoundsChange BoundsChange
d VersionBounds
old =
  VersionBounds -> Maybe VersionBounds -> VersionBounds
forall a. a -> Maybe a -> a
fromMaybe VersionBounds
old (BoundsChange -> Maybe VersionBounds
reifyBoundsChangeMaybe BoundsChange
d)

diff ::
  (a -> a -> Maybe d) ->
  a ->
  a ->
  Change d a
diff :: forall a d. (a -> a -> Maybe d) -> a -> a -> Change d a
diff a -> a -> Maybe d
mkDetail a
original a
new =
  case a -> a -> Maybe d
mkDetail a
original a
new of
    Just d
detail -> Diff d a -> Change d a
forall d a. Diff d a -> Change d a
Changed (a -> a -> d -> Diff d a
forall d a. a -> a -> d -> Diff d a
DiffChanged a
original a
new d
detail)
    Maybe d
Nothing -> Maybe a -> Change d a
forall d a. Maybe a -> Change d a
Unchanged (a -> Maybe a
forall a. a -> Maybe a
Just a
original)

diffMaybe ::
  (a -> a -> Maybe d) ->
  Maybe a ->
  Maybe a ->
  Change d a
diffMaybe :: forall a d. (a -> a -> Maybe d) -> Maybe a -> Maybe a -> Change d a
diffMaybe a -> a -> Maybe d
mkDetail Maybe a
original Maybe a
new =
  case (Maybe a
original, Maybe a
new) of
    (Just a
o, Just a
n) -> (a -> a -> Maybe d) -> a -> a -> Change d a
forall a d. (a -> a -> Maybe d) -> a -> a -> Change d a
diff a -> a -> Maybe d
mkDetail a
o a
n
    (Just a
o, Maybe a
Nothing) -> Maybe a -> Change d a
forall d a. Maybe a -> Change d a
Unchanged (a -> Maybe a
forall a. a -> Maybe a
Just a
o)
    (Maybe a
Nothing, Just a
n) -> Diff d a -> Change d a
forall d a. Diff d a -> Change d a
Changed (a -> Diff d a
forall d a. a -> Diff d a
DiffAdded a
n)
    (Maybe a
Nothing, Maybe a
Nothing) -> Maybe a -> Change d a
forall d a. Maybe a -> Change d a
Unchanged Maybe a
forall a. Maybe a
Nothing

versionDiffDetail :: Version -> Version -> Maybe ()
versionDiffDetail :: Version -> Version -> Maybe ()
versionDiffDetail Version
original Version
new
  | Version
original Version -> Version -> Bool
forall a. Eq a => a -> a -> Bool
== Version
new
  = Maybe ()
forall a. Maybe a
Nothing
  | Bool
otherwise
  = () -> Maybe ()
forall a. a -> Maybe a
Just ()

versionChange :: Maybe Version -> Maybe Version -> VersionChange
versionChange :: Maybe Version -> Maybe Version -> VersionChange
versionChange = (Version -> Version -> Maybe ())
-> Maybe Version -> Maybe Version -> VersionChange
forall a d. (a -> a -> Maybe d) -> Maybe a -> Maybe a -> Change d a
diffMaybe Version -> Version -> Maybe ()
versionDiffDetail

versionDiff :: Maybe Version -> Maybe Version -> Maybe (Diff () Version)
versionDiff :: Maybe Version -> Maybe Version -> Maybe (Diff () Version)
versionDiff Maybe Version
original Maybe Version
new =
  case Maybe Version -> Maybe Version -> VersionChange
versionChange Maybe Version
original Maybe Version
new of
    Changed Diff () Version
d -> Diff () Version -> Maybe (Diff () Version)
forall a. a -> Maybe a
Just Diff () Version
d
    Unchanged Maybe Version
_ -> Maybe (Diff () Version)
forall a. Maybe a
Nothing

boundsDiffDetail :: VersionBounds -> VersionBounds -> Maybe BoundsDiffDetail
boundsDiffDetail :: VersionBounds -> VersionBounds -> Maybe BoundsDiffDetail
boundsDiffDetail VersionBounds
original VersionBounds
new =
  These (Diff () Version) (Diff () Version) -> BoundsDiffDetail
BoundsDiffDetail (These (Diff () Version) (Diff () Version) -> BoundsDiffDetail)
-> Maybe (These (Diff () Version) (Diff () Version))
-> Maybe BoundsDiffDetail
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Diff () Version)
-> Maybe (Diff () Version)
-> Maybe (These (Diff () Version) (Diff () Version))
forall a b. Maybe a -> Maybe b -> Maybe (These a b)
maybeThese Maybe (Diff () Version)
diffL Maybe (Diff () Version)
diffU
  where
    diffL :: Maybe (Diff () Version)
diffL = Maybe Version -> Maybe Version -> Maybe (Diff () Version)
versionDiff VersionBounds
original.lower VersionBounds
combined.lower
    diffU :: Maybe (Diff () Version)
diffU = Maybe Version -> Maybe Version -> Maybe (Diff () Version)
versionDiff VersionBounds
original.upper VersionBounds
combined.upper
    combined :: VersionBounds
combined = VersionBounds
new VersionBounds -> VersionBounds -> VersionBounds
forall a. Semigroup a => a -> a -> a
<> VersionBounds
original

boundsChange :: VersionBounds -> VersionBounds -> BoundsChange
boundsChange :: VersionBounds -> VersionBounds -> BoundsChange
boundsChange = (VersionBounds -> VersionBounds -> Maybe BoundsDiffDetail)
-> VersionBounds -> VersionBounds -> BoundsChange
forall a d. (a -> a -> Maybe d) -> a -> a -> Change d a
diff VersionBounds -> VersionBounds -> Maybe BoundsDiffDetail
boundsDiffDetail

updateVersionChange :: Version -> VersionChange -> VersionChange
updateVersionChange :: Version -> VersionChange -> VersionChange
updateVersionChange Version
new VersionChange
d =
  (Version -> Version -> Maybe ())
-> Maybe Version -> Maybe Version -> VersionChange
forall a d. (a -> a -> Maybe d) -> Maybe a -> Maybe a -> Change d a
diffMaybe Version -> Version -> Maybe ()
versionDiffDetail (VersionChange -> Maybe Version
forall d a. Change d a -> Maybe a
changeOriginal VersionChange
d) (Version -> Maybe Version
forall a. a -> Maybe a
Just Version
new)

-- | We never want to remove any bounds, but mutations only return the bound they have targeted, so we need to fall back
-- to the original bounds when updating.
updateBoundsChange :: VersionBounds -> BoundsChange -> BoundsChange
updateBoundsChange :: VersionBounds -> BoundsChange -> BoundsChange
updateBoundsChange VersionBounds
new BoundsChange
d =
  (VersionBounds -> VersionBounds -> Maybe BoundsDiffDetail)
-> Maybe VersionBounds -> Maybe VersionBounds -> BoundsChange
forall a d. (a -> a -> Maybe d) -> Maybe a -> Maybe a -> Change d a
diffMaybe VersionBounds -> VersionBounds -> Maybe BoundsDiffDetail
boundsDiffDetail Maybe VersionBounds
original (VersionBounds -> Maybe VersionBounds
forall a. a -> Maybe a
Just VersionBounds
combined)
  where
    (Maybe VersionBounds
original, VersionBounds
combined) = case BoundsChange -> Maybe VersionBounds
forall d a. Change d a -> Maybe a
changeOriginal BoundsChange
d of
      Just VersionBounds
o -> (VersionBounds -> Maybe VersionBounds
forall a. a -> Maybe a
Just VersionBounds
o, VersionBounds
new VersionBounds -> VersionBounds -> VersionBounds
forall a. Semigroup a => a -> a -> a
<> VersionBounds
o)
      Maybe VersionBounds
Nothing -> (Maybe VersionBounds
forall a. Maybe a
Nothing, VersionBounds
new)

updateVersionChanges ::
  NMap vmap MutableDep (Maybe Version) s1 =>
  NMap map MutableDep VersionChange s2 =>
  vmap ->
  map ->
  map
updateVersionChanges :: forall vmap s1 map s2.
(NMap vmap MutableDep (Maybe Version) s1,
 NMap map MutableDep VersionChange s2) =>
vmap -> map -> map
updateVersionChanges =
  (Maybe Version -> VersionChange -> VersionChange)
-> vmap -> map -> map
forall map1 map2 k v1 v2 s1 s2.
(NMap map1 k v1 s1, NMap map2 k v2 s2) =>
(v1 -> v2 -> v2) -> map1 -> map2 -> map2
nAmend ((VersionChange -> VersionChange)
-> (Version -> VersionChange -> VersionChange)
-> Maybe Version
-> VersionChange
-> VersionChange
forall b a. b -> (a -> b) -> Maybe a -> b
maybe VersionChange -> VersionChange
forall a. a -> a
id Version -> VersionChange -> VersionChange
updateVersionChange)

updateBoundsChanges ::
  NMap vmap MutableDep VersionBounds s1 =>
  NMap map MutableDep BoundsChange s2 =>
  vmap ->
  map ->
  map
updateBoundsChanges :: forall vmap s1 map s2.
(NMap vmap MutableDep VersionBounds s1,
 NMap map MutableDep BoundsChange s2) =>
vmap -> map -> map
updateBoundsChanges =
  (VersionBounds -> BoundsChange -> BoundsChange)
-> vmap -> map -> map
forall map1 map2 k v1 v2 s1 s2.
(NMap map1 k v1 s1, NMap map2 k v2 s2) =>
(v1 -> v2 -> v2) -> map1 -> map2 -> map2
nAmend VersionBounds -> BoundsChange -> BoundsChange
updateBoundsChange

initChanges ::
  NMap map1 k (Maybe v1) s1 =>
  NMap map2 k (Change d v1) s2 =>
  map1 ->
  map2
initChanges :: forall map1 k v1 s1 map2 d s2.
(NMap map1 k (Maybe v1) s1, NMap map2 k (Change d v1) s2) =>
map1 -> map2
initChanges =
  (Maybe v1 -> Change d v1) -> map1 -> map2
forall map1 k v1 sort1 map2 v2 sort2.
(NMap map1 k v1 sort1, NMap map2 k v2 sort2) =>
(v1 -> v2) -> map1 -> map2
nMap Maybe v1 -> Change d v1
forall d a. Maybe a -> Change d a
Unchanged