module Unison.Merge.TwoWay
  ( TwoWay (..),
    bothWays,
    gtoThreeWay,
    justTheTerms,
    justTheTypes,
    or,
    sequenceDefns,
    swap,
    toThreeWay,
    twoWay,
    unzipMap,
    updatedToThreeWay,
    who_,
  )
where

import Control.Lens (Lens')
import Data.Zip (unzipWith)
import Unison.Merge.EitherWay (EitherWay (..))
import Unison.Merge.Internal.Types (GThreeWay (..), ThreeWay (..), TwoWay (..))
import Unison.Merge.Updated (GUpdated (..), Updated)
import Unison.Prelude
import Unison.Util.Defns (Defns (..), DefnsF)
import Prelude hiding (or, zipWith)

bothWays :: a -> TwoWay a
bothWays :: forall a. a -> TwoWay a
bothWays a
x =
  a -> a -> TwoWay a
forall a. a -> a -> TwoWay a
TwoWay a
x a
x

gtoThreeWay :: a -> TwoWay b -> GThreeWay a b
gtoThreeWay :: forall a b. a -> TwoWay b -> GThreeWay a b
gtoThreeWay a
lca TwoWay {b
alice :: b
$sel:alice:TwoWay :: forall a. TwoWay a -> a
alice, b
bob :: b
$sel:bob:TwoWay :: forall a. TwoWay a -> a
bob} =
  GThreeWay {a
lca :: a
$sel:lca:GThreeWay :: a
lca, b
alice :: b
$sel:alice:GThreeWay :: b
alice, b
bob :: b
$sel:bob:GThreeWay :: b
bob}

justTheTerms :: TwoWay (Defns terms types) -> TwoWay terms
justTheTerms :: forall terms types. TwoWay (Defns terms types) -> TwoWay terms
justTheTerms =
  (Defns terms types -> terms)
-> TwoWay (Defns terms types) -> TwoWay terms
forall a b. (a -> b) -> TwoWay a -> TwoWay b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Getting terms (Defns terms types) terms
-> Defns terms types -> terms
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting terms (Defns terms types) terms
#terms)

justTheTypes :: TwoWay (Defns terms types) -> TwoWay types
justTheTypes :: forall terms types. TwoWay (Defns terms types) -> TwoWay types
justTheTypes =
  (Defns terms types -> types)
-> TwoWay (Defns terms types) -> TwoWay types
forall a b. (a -> b) -> TwoWay a -> TwoWay b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Getting types (Defns terms types) types
-> Defns terms types -> types
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting types (Defns terms types) types
#types)

or :: TwoWay Bool -> Bool
or :: TwoWay Bool -> Bool
or =
  (Bool -> Bool -> Bool) -> TwoWay Bool -> Bool
forall a b. (a -> a -> b) -> TwoWay a -> b
twoWay Bool -> Bool -> Bool
(||)

sequenceDefns :: TwoWay (Defns terms types) -> DefnsF TwoWay terms types
sequenceDefns :: forall terms types.
TwoWay (Defns terms types) -> DefnsF TwoWay terms types
sequenceDefns TwoWay (Defns terms types)
defns =
  TwoWay terms -> TwoWay types -> Defns (TwoWay terms) (TwoWay types)
forall terms types. terms -> types -> Defns terms types
Defns (TwoWay (Defns terms types) -> TwoWay terms
forall terms types. TwoWay (Defns terms types) -> TwoWay terms
justTheTerms TwoWay (Defns terms types)
defns) (TwoWay (Defns terms types) -> TwoWay types
forall terms types. TwoWay (Defns terms types) -> TwoWay types
justTheTypes TwoWay (Defns terms types)
defns)

-- | Swap who's considered Alice and who's considered Bob. Usually nonsense, but sometimes what you need!
swap :: TwoWay a -> TwoWay a
swap :: forall a. TwoWay a -> TwoWay a
swap (TwoWay a
x a
y) =
  a -> a -> TwoWay a
forall a. a -> a -> TwoWay a
TwoWay a
y a
x

toThreeWay :: a -> TwoWay a -> ThreeWay a
toThreeWay :: forall a. a -> TwoWay a -> ThreeWay a
toThreeWay a
lca TwoWay {a
$sel:alice:TwoWay :: forall a. TwoWay a -> a
alice :: a
alice, a
$sel:bob:TwoWay :: forall a. TwoWay a -> a
bob :: a
bob} =
  ThreeWay {a
lca :: a
$sel:lca:ThreeWay :: a
lca, a
alice :: a
$sel:alice:ThreeWay :: a
alice, a
bob :: a
$sel:bob:ThreeWay :: a
bob}

twoWay :: (a -> a -> b) -> TwoWay a -> b
twoWay :: forall a b. (a -> a -> b) -> TwoWay a -> b
twoWay a -> a -> b
f TwoWay {a
$sel:alice:TwoWay :: forall a. TwoWay a -> a
alice :: a
alice, a
$sel:bob:TwoWay :: forall a. TwoWay a -> a
bob :: a
bob} =
  a -> a -> b
f a
alice a
bob

-- | Unzip a @Map k (TwoWay v)@ into a @TwoWay (Map k v)@.
unzipMap :: (Ord k) => Map k (TwoWay v) -> TwoWay (Map k v)
unzipMap :: forall k v. Ord k => Map k (TwoWay v) -> TwoWay (Map k v)
unzipMap =
  (Map k v, Map k v) -> TwoWay (Map k v)
forall a. (a, a) -> TwoWay a
fromPair ((Map k v, Map k v) -> TwoWay (Map k v))
-> (Map k (TwoWay v) -> (Map k v, Map k v))
-> Map k (TwoWay v)
-> TwoWay (Map k v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TwoWay v -> (v, v)) -> Map k (TwoWay v) -> (Map k v, Map k v)
forall c a b. (c -> (a, b)) -> Map k c -> (Map k a, Map k b)
forall (f :: * -> *) c a b.
Unzip f =>
(c -> (a, b)) -> f c -> (f a, f b)
unzipWith (\TwoWay {v
$sel:alice:TwoWay :: forall a. TwoWay a -> a
alice :: v
alice, v
$sel:bob:TwoWay :: forall a. TwoWay a -> a
bob :: v
bob} -> (v
alice, v
bob))

updatedToThreeWay :: (Semigroup a) => TwoWay (Updated a) -> ThreeWay a
updatedToThreeWay :: forall a. Semigroup a => TwoWay (Updated a) -> ThreeWay a
updatedToThreeWay TwoWay {Updated a
$sel:alice:TwoWay :: forall a. TwoWay a -> a
alice :: Updated a
alice, Updated a
$sel:bob:TwoWay :: forall a. TwoWay a -> a
bob :: Updated a
bob} =
  ThreeWay
    { $sel:lca:ThreeWay :: a
lca = Updated a
alice.old a -> a -> a
forall a. Semigroup a => a -> a -> a
<> Updated a
bob.old,
      $sel:alice:ThreeWay :: a
alice = Updated a
alice.new,
      $sel:bob:ThreeWay :: a
bob = Updated a
bob.new
    }

who_ :: EitherWay x -> Lens' (TwoWay a) a
who_ :: forall x a. EitherWay x -> Lens' (TwoWay a) a
who_ = \case
  Alice x
_ -> (a -> f a) -> TwoWay a -> f (TwoWay a)
#alice
  Bob x
_ -> (a -> f a) -> TwoWay a -> f (TwoWay a)
#bob

--

fromPair :: (a, a) -> TwoWay a
fromPair :: forall a. (a, a) -> TwoWay a
fromPair (a
alice, a
bob) =
  TwoWay {a
$sel:alice:TwoWay :: a
alice :: a
alice, a
$sel:bob:TwoWay :: a
bob :: a
bob}