{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TemplateHaskell #-} module Simplex.Chat.Remote.AppVersion ( AppVersionRange (minVersion, maxVersion), pattern AppVersionRange, AppVersion (..), pattern AppCompatible, mkAppVersionRange, compatibleAppVersion, isAppCompatible, ) where import Data.Aeson (FromJSON (..), ToJSON (..)) import qualified Data.Aeson as J import qualified Data.Aeson.Encoding as JE import qualified Data.Aeson.TH as JQ import qualified Data.Text as T import Data.Version (parseVersion, showVersion) import qualified Data.Version as V import Simplex.Messaging.Parsers (defaultJSON) import Text.ParserCombinators.ReadP (readP_to_S) newtype AppVersion = AppVersion {AppVersion -> Version appVersion :: V.Version} deriving (AppVersion -> AppVersion -> Bool (AppVersion -> AppVersion -> Bool) -> (AppVersion -> AppVersion -> Bool) -> Eq AppVersion forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a $c== :: AppVersion -> AppVersion -> Bool == :: AppVersion -> AppVersion -> Bool $c/= :: AppVersion -> AppVersion -> Bool /= :: AppVersion -> AppVersion -> Bool Eq, Eq AppVersion Eq AppVersion => (AppVersion -> AppVersion -> Ordering) -> (AppVersion -> AppVersion -> Bool) -> (AppVersion -> AppVersion -> Bool) -> (AppVersion -> AppVersion -> Bool) -> (AppVersion -> AppVersion -> Bool) -> (AppVersion -> AppVersion -> AppVersion) -> (AppVersion -> AppVersion -> AppVersion) -> Ord AppVersion AppVersion -> AppVersion -> Bool AppVersion -> AppVersion -> Ordering AppVersion -> AppVersion -> AppVersion forall a. Eq a => (a -> a -> Ordering) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> Bool) -> (a -> a -> a) -> (a -> a -> a) -> Ord a $ccompare :: AppVersion -> AppVersion -> Ordering compare :: AppVersion -> AppVersion -> Ordering $c< :: AppVersion -> AppVersion -> Bool < :: AppVersion -> AppVersion -> Bool $c<= :: AppVersion -> AppVersion -> Bool <= :: AppVersion -> AppVersion -> Bool $c> :: AppVersion -> AppVersion -> Bool > :: AppVersion -> AppVersion -> Bool $c>= :: AppVersion -> AppVersion -> Bool >= :: AppVersion -> AppVersion -> Bool $cmax :: AppVersion -> AppVersion -> AppVersion max :: AppVersion -> AppVersion -> AppVersion $cmin :: AppVersion -> AppVersion -> AppVersion min :: AppVersion -> AppVersion -> AppVersion Ord, Int -> AppVersion -> ShowS [AppVersion] -> ShowS AppVersion -> String (Int -> AppVersion -> ShowS) -> (AppVersion -> String) -> ([AppVersion] -> ShowS) -> Show AppVersion forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> AppVersion -> ShowS showsPrec :: Int -> AppVersion -> ShowS $cshow :: AppVersion -> String show :: AppVersion -> String $cshowList :: [AppVersion] -> ShowS showList :: [AppVersion] -> ShowS Show) instance ToJSON AppVersion where toJSON :: AppVersion -> Value toJSON (AppVersion Version v) = Text -> Value J.String (Text -> Value) -> (String -> Text) -> String -> Value forall b c a. (b -> c) -> (a -> b) -> a -> c . String -> Text T.pack (String -> Value) -> String -> Value forall a b. (a -> b) -> a -> b $ Version -> String showVersion Version v toEncoding :: AppVersion -> Encoding toEncoding (AppVersion Version v) = Text -> Encoding forall a. Text -> Encoding' a JE.text (Text -> Encoding) -> (String -> Text) -> String -> Encoding forall b c a. (b -> c) -> (a -> b) -> a -> c . String -> Text T.pack (String -> Encoding) -> String -> Encoding forall a b. (a -> b) -> a -> b $ Version -> String showVersion Version v instance FromJSON AppVersion where parseJSON :: Value -> Parser AppVersion parseJSON = String -> (Text -> Parser AppVersion) -> Value -> Parser AppVersion forall a. String -> (Text -> Parser a) -> Value -> Parser a J.withText String "AppVersion" ((Text -> Parser AppVersion) -> Value -> Parser AppVersion) -> (Text -> Parser AppVersion) -> Value -> Parser AppVersion forall a b. (a -> b) -> a -> b $ String -> Parser AppVersion forall {f :: * -> *}. MonadFail f => String -> f AppVersion parse (String -> Parser AppVersion) -> (Text -> String) -> Text -> Parser AppVersion forall b c a. (b -> c) -> (a -> b) -> a -> c . Text -> String T.unpack where parse :: String -> f AppVersion parse String s = case ((Version, String) -> Bool) -> [(Version, String)] -> [(Version, String)] forall a. (a -> Bool) -> [a] -> [a] filter (String -> Bool forall a. [a] -> 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) ([(Version, String)] -> [(Version, String)]) -> [(Version, String)] -> [(Version, String)] forall a b. (a -> b) -> a -> b $ ReadP Version -> ReadS Version forall a. ReadP a -> ReadS a readP_to_S ReadP Version parseVersion String s of (Version v, String _) : [(Version, String)] _ -> AppVersion -> f AppVersion forall a. a -> f a forall (f :: * -> *) a. Applicative f => a -> f a pure (AppVersion -> f AppVersion) -> AppVersion -> f AppVersion forall a b. (a -> b) -> a -> b $ Version -> AppVersion AppVersion Version v [(Version, String)] _ -> String -> f AppVersion forall a. String -> f a forall (m :: * -> *) a. MonadFail m => String -> m a fail (String -> f AppVersion) -> String -> f AppVersion forall a b. (a -> b) -> a -> b $ String "bad AppVersion: " String -> ShowS forall a. Semigroup a => a -> a -> a <> String s data AppVersionRange = AppVRange { AppVersionRange -> AppVersion minVersion :: AppVersion, AppVersionRange -> AppVersion maxVersion :: AppVersion } deriving (Int -> AppVersionRange -> ShowS [AppVersionRange] -> ShowS AppVersionRange -> String (Int -> AppVersionRange -> ShowS) -> (AppVersionRange -> String) -> ([AppVersionRange] -> ShowS) -> Show AppVersionRange forall a. (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a $cshowsPrec :: Int -> AppVersionRange -> ShowS showsPrec :: Int -> AppVersionRange -> ShowS $cshow :: AppVersionRange -> String show :: AppVersionRange -> String $cshowList :: [AppVersionRange] -> ShowS showList :: [AppVersionRange] -> ShowS Show) pattern AppVersionRange :: AppVersion -> AppVersion -> AppVersionRange pattern $mAppVersionRange :: forall {r}. AppVersionRange -> (AppVersion -> AppVersion -> r) -> ((# #) -> r) -> r AppVersionRange v1 v2 <- AppVRange v1 v2 {-# COMPLETE AppVersionRange #-} mkAppVersionRange :: AppVersion -> AppVersion -> AppVersionRange mkAppVersionRange :: AppVersion -> AppVersion -> AppVersionRange mkAppVersionRange AppVersion v1 AppVersion v2 | AppVersion v1 AppVersion -> AppVersion -> Bool forall a. Ord a => a -> a -> Bool <= AppVersion v2 = AppVersion -> AppVersion -> AppVersionRange AppVRange AppVersion v1 AppVersion v2 | Bool otherwise = String -> AppVersionRange forall a. HasCallStack => String -> a error String "invalid version range" newtype AppCompatible a = AppCompatible_ a pattern AppCompatible :: a -> AppCompatible a pattern $mAppCompatible :: forall {r} {a}. AppCompatible a -> (a -> r) -> ((# #) -> r) -> r AppCompatible a <- AppCompatible_ a {-# COMPLETE AppCompatible #-} isAppCompatible :: AppVersion -> AppVersionRange -> Bool isAppCompatible :: AppVersion -> AppVersionRange -> Bool isAppCompatible AppVersion v (AppVRange AppVersion v1 AppVersion v2) = AppVersion v1 AppVersion -> AppVersion -> Bool forall a. Ord a => a -> a -> Bool <= AppVersion v Bool -> Bool -> Bool && AppVersion v AppVersion -> AppVersion -> Bool forall a. Ord a => a -> a -> Bool <= AppVersion v2 isCompatibleAppRange :: AppVersionRange -> AppVersionRange -> Bool isCompatibleAppRange :: AppVersionRange -> AppVersionRange -> Bool isCompatibleAppRange (AppVRange AppVersion min1 AppVersion max1) (AppVRange AppVersion min2 AppVersion max2) = AppVersion min1 AppVersion -> AppVersion -> Bool forall a. Ord a => a -> a -> Bool <= AppVersion max2 Bool -> Bool -> Bool && AppVersion min2 AppVersion -> AppVersion -> Bool forall a. Ord a => a -> a -> Bool <= AppVersion max1 compatibleAppVersion :: AppVersionRange -> AppVersionRange -> Maybe (AppCompatible AppVersion) compatibleAppVersion :: AppVersionRange -> AppVersionRange -> Maybe (AppCompatible AppVersion) compatibleAppVersion AppVersionRange vr1 AppVersionRange vr2 = AppVersion -> AppVersion -> AppVersion forall a. Ord a => a -> a -> a min (AppVersionRange -> AppVersion maxVersion AppVersionRange vr1) (AppVersionRange -> AppVersion maxVersion AppVersionRange vr2) AppVersion -> Bool -> Maybe (AppCompatible AppVersion) `mkCompatibleIf` AppVersionRange -> AppVersionRange -> Bool isCompatibleAppRange AppVersionRange vr1 AppVersionRange vr2 mkCompatibleIf :: AppVersion -> Bool -> Maybe (AppCompatible AppVersion) AppVersion v mkCompatibleIf :: AppVersion -> Bool -> Maybe (AppCompatible AppVersion) `mkCompatibleIf` Bool cond = if Bool cond then AppCompatible AppVersion -> Maybe (AppCompatible AppVersion) forall a. a -> Maybe a Just (AppCompatible AppVersion -> Maybe (AppCompatible AppVersion)) -> AppCompatible AppVersion -> Maybe (AppCompatible AppVersion) forall a b. (a -> b) -> a -> b $ AppVersion -> AppCompatible AppVersion forall a. a -> AppCompatible a AppCompatible_ AppVersion v else Maybe (AppCompatible AppVersion) forall a. Maybe a Nothing $(JQ.deriveJSON defaultJSON ''AppVersionRange)