packages feed

api-tools-0.9.0.0: src/Data/API/Utils.hs

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 s = case filter (null . snd) (ReadP.readP_to_S parseVersion s) of
  [(v,_)] -> Just v
  _       -> Nothing


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

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


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

data MergeResult a b = OnlyInLeft a | InBoth a b | OnlyInRight b
  deriving (Eq, Show)

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

diffMaps :: (Eq a, Ord k) => Map k a -> Map k a -> Map k (MergeResult a a)
diffMaps m1 m2 = Map.filter different $ mergeMaps m1 m2
  where
    different (InBoth a b) = a /= b
    different _            = 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 m1 m2 = Map.traverseWithKey win $ mergeMaps m1 m2
  where
    win _ (InBoth x y)    = return (x, y)
    win k (OnlyInLeft x)  = Left (k, Left x)
    win k (OnlyInRight x) = Left (k, Right x)