module Data.API.Utils
    ( simpleParseVersion
    , (?!)
    , (?!?)
      -- * Utils for merging and diffing maps
    , MergeResult(..)
    , mergeMaps
    , diffMaps
    , matchMaps
    ) where

import           Data.Map ( Map )
import qualified Data.Map                       as Map
import           Data.Version
import qualified Text.ParserCombinators.ReadP as ReadP

simpleParseVersion :: String -> Maybe Version
simpleParseVersion :: String -> Maybe Version
simpleParseVersion String
s = case ((Version, String) -> Bool)
-> [(Version, String)] -> [(Version, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (String -> Bool)
-> ((Version, String) -> String) -> (Version, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Version, String) -> String
forall a b. (a, b) -> b
snd) (ReadP Version -> ReadS Version
forall a. ReadP a -> ReadS a
ReadP.readP_to_S ReadP Version
parseVersion String
s) of
  [(Version
v,String
_)] -> Version -> Maybe Version
forall a. a -> Maybe a
Just Version
v
  [(Version, String)]
_       -> Maybe Version
forall a. Maybe a
Nothing


-- | The \"oh noes!\" operator.
--
(?!) :: Maybe a -> e -> Either e a
Maybe a
Nothing ?! :: Maybe a -> e -> Either e a
?! e
e = e -> Either e a
forall a b. a -> Either a b
Left  e
e
Just a
x  ?! e
_ = a -> Either e a
forall a b. b -> Either a b
Right a
x

(?!?) :: Either e a -> (e -> e') -> Either e' a
Left  e
e ?!? :: Either e a -> (e -> e') -> Either e' a
?!? e -> e'
f = e' -> Either e' a
forall a b. a -> Either a b
Left  (e -> e'
f e
e)
Right a
x ?!? e -> e'
_ = a -> Either e' a
forall a b. b -> Either a b
Right a
x


-------------------------------------
-- Utils for merging and diffing maps
--

data MergeResult a b = OnlyInLeft a | InBoth a b | OnlyInRight b
  deriving (MergeResult a b -> MergeResult a b -> Bool
(MergeResult a b -> MergeResult a b -> Bool)
-> (MergeResult a b -> MergeResult a b -> Bool)
-> Eq (MergeResult a b)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall a b.
(Eq a, Eq b) =>
MergeResult a b -> MergeResult a b -> Bool
/= :: MergeResult a b -> MergeResult a b -> Bool
$c/= :: forall a b.
(Eq a, Eq b) =>
MergeResult a b -> MergeResult a b -> Bool
== :: MergeResult a b -> MergeResult a b -> Bool
$c== :: forall a b.
(Eq a, Eq b) =>
MergeResult a b -> MergeResult a b -> Bool
Eq, Int -> MergeResult a b -> ShowS
[MergeResult a b] -> ShowS
MergeResult a b -> String
(Int -> MergeResult a b -> ShowS)
-> (MergeResult a b -> String)
-> ([MergeResult a b] -> ShowS)
-> Show (MergeResult a b)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall a b. (Show a, Show b) => Int -> MergeResult a b -> ShowS
forall a b. (Show a, Show b) => [MergeResult a b] -> ShowS
forall a b. (Show a, Show b) => MergeResult a b -> String
showList :: [MergeResult a b] -> ShowS
$cshowList :: forall a b. (Show a, Show b) => [MergeResult a b] -> ShowS
show :: MergeResult a b -> String
$cshow :: forall a b. (Show a, Show b) => MergeResult a b -> String
showsPrec :: Int -> MergeResult a b -> ShowS
$cshowsPrec :: forall a b. (Show a, Show b) => Int -> MergeResult a b -> ShowS
Show)

mergeMaps :: Ord k => Map k a -> Map k b -> Map k (MergeResult a b)
mergeMaps :: Map k a -> Map k b -> Map k (MergeResult a b)
mergeMaps Map k a
m1 Map k b
m2 = (MergeResult a b -> MergeResult a b -> MergeResult a b)
-> Map k (MergeResult a b)
-> Map k (MergeResult a b)
-> Map k (MergeResult a b)
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith (\(OnlyInLeft a
a) (OnlyInRight b
b) -> a -> b -> MergeResult a b
forall a b. a -> b -> MergeResult a b
InBoth a
a b
b)
                      ((a -> MergeResult a b) -> Map k a -> Map k (MergeResult a b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> MergeResult a b
forall a b. a -> MergeResult a b
OnlyInLeft Map k a
m1) ((b -> MergeResult a b) -> Map k b -> Map k (MergeResult a b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> MergeResult a b
forall a b. b -> MergeResult a b
OnlyInRight Map k b
m2)

diffMaps :: (Eq a, Ord k) => Map k a -> Map k a -> Map k (MergeResult a a)
diffMaps :: Map k a -> Map k a -> Map k (MergeResult a a)
diffMaps Map k a
m1 Map k a
m2 = (MergeResult a a -> Bool)
-> Map k (MergeResult a a) -> Map k (MergeResult a a)
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter MergeResult a a -> Bool
forall a. Eq a => MergeResult a a -> Bool
different (Map k (MergeResult a a) -> Map k (MergeResult a a))
-> Map k (MergeResult a a) -> Map k (MergeResult a a)
forall a b. (a -> b) -> a -> b
$ Map k a -> Map k a -> Map k (MergeResult a a)
forall k a b.
Ord k =>
Map k a -> Map k b -> Map k (MergeResult a b)
mergeMaps Map k a
m1 Map k a
m2
  where
    different :: MergeResult a a -> Bool
different (InBoth a
a a
b) = a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
b
    different MergeResult a a
_            = Bool
True

-- | Attempts to match the keys of the maps to produce a map from keys
-- to pairs.
matchMaps :: Ord k => Map k a -> Map k b -> Either (k, Either a b) (Map k (a, b))
matchMaps :: Map k a -> Map k b -> Either (k, Either a b) (Map k (a, b))
matchMaps Map k a
m1 Map k b
m2 = (k -> MergeResult a b -> Either (k, Either a b) (a, b))
-> Map k (MergeResult a b) -> Either (k, Either a b) (Map k (a, b))
forall (t :: * -> *) k a b.
Applicative t =>
(k -> a -> t b) -> Map k a -> t (Map k b)
Map.traverseWithKey k -> MergeResult a b -> Either (k, Either a b) (a, b)
forall a a b. a -> MergeResult a b -> Either (a, Either a b) (a, b)
win (Map k (MergeResult a b) -> Either (k, Either a b) (Map k (a, b)))
-> Map k (MergeResult a b) -> Either (k, Either a b) (Map k (a, b))
forall a b. (a -> b) -> a -> b
$ Map k a -> Map k b -> Map k (MergeResult a b)
forall k a b.
Ord k =>
Map k a -> Map k b -> Map k (MergeResult a b)
mergeMaps Map k a
m1 Map k b
m2
  where
    win :: a -> MergeResult a b -> Either (a, Either a b) (a, b)
win a
_ (InBoth a
x b
y)    = (a, b) -> Either (a, Either a b) (a, b)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
x, b
y)
    win a
k (OnlyInLeft a
x)  = (a, Either a b) -> Either (a, Either a b) (a, b)
forall a b. a -> Either a b
Left (a
k, a -> Either a b
forall a b. a -> Either a b
Left a
x)
    win a
k (OnlyInRight b
x) = (a, Either a b) -> Either (a, Either a b) (a, b)
forall a b. a -> Either a b
Left (a
k, b -> Either a b
forall a b. b -> Either a b
Right b
x)