ron-hs-0.4.0: src/Data/Ron/Value/Internal.hs
module Data.Ron.Value.Internal
where
import Control.Applicative ((<|>))
import Data.Foldable (msum)
import Data.Maybe (isNothing)
import Data.Ron.Class (ToRon (toRon))
import Data.Text (pack)
import qualified Data.Map.Strict as Map
import qualified Data.Vector as Vector
import Data.Ron.Value
(!==!) :: (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
a !==! b = if a == b then Nothing else Just (toRon a, toRon b)
vshow :: Show a => a -> Value
vshow = String . pack . show
similar' :: Value -> Value -> Bool
similar' a b = isNothing $ similar a b
-- | Like '==' but not precise for floats
similar :: Value -> Value -> Maybe (Value, Value)
similar (Integral a) (Integral b) = a !==! b
similar (Floating a) (Floating b) = if abs (a - b) < 0.001 then Nothing else Just (Floating a, Floating b)
similar (Char a) (Char b) = a !==! b
similar (String a) (String b) = a !==! b
similar (List a) (List b) = vecSimilar a b
similar (Map a) (Map b) = mapSimilar a b
similar (Unit n) (Unit m) = n !==! m
similar (Tuple n a) (Tuple m b) = (n !==! m) <|> vecSimilar a b
similar (Record n a) (Record m b) = (n !==! m) <|> mapSimilar a b
similar _ _ = Just (String "different types", Unit "")
vecSimilar :: Vector.Vector Value -> Vector.Vector Value -> Maybe (Value, Value)
vecSimilar a b = msum $ Vector.zipWith similar a b
mapSimilar :: (Eq k, Show k) => Map.Map k Value -> Map.Map k Value -> Maybe (Value, Value)
mapSimilar a b = go (Map.toAscList a) (Map.toAscList b) where
go [] [] = Nothing
go ((ak, av):as) ((bk, bv):bs) = (if ak == bk then Nothing else Just (vshow ak, vshow bk)) <|> (av `similar` bv) <|> go as bs
go x y = Just (toRon $ length x, toRon $ length y) -- different amount of values