module Must (Must (..), inRange, exceedsUpperBound) where
import Data.List (isInfixOf)
import Text.Read (readMaybe)
data Must
= MtDisabled
| MtExact Integer
| MtRange (Maybe Integer) (Maybe Integer)
deriving (Must -> Must -> Bool
(Must -> Must -> Bool) -> (Must -> Must -> Bool) -> Eq Must
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Must -> Must -> Bool
== :: Must -> Must -> Bool
$c/= :: Must -> Must -> Bool
/= :: Must -> Must -> Bool
Eq)
instance Show Must where
show :: Must -> String
show Must
MtDisabled = String
"0"
show (MtExact Integer
n) = Integer -> String
forall a. Show a => a -> String
show Integer
n
show (MtRange Maybe Integer
Nothing Maybe Integer
Nothing) = String
".."
show (MtRange Maybe Integer
Nothing (Just Integer
max)) = String
".." String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show Integer
max
show (MtRange (Just Integer
min) Maybe Integer
Nothing) = Integer -> String
forall a. Show a => a -> String
show Integer
min String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".."
show (MtRange (Just Integer
min) (Just Integer
max)) = Integer -> String
forall a. Show a => a -> String
show Integer
min String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".." String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show Integer
max
instance Read Must where
readsPrec :: Int -> ReadS Must
readsPrec Int
_ String
"0" = [(Must
MtDisabled, String
"")]
readsPrec Int
_ String
s
| String
".." String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
s = ReadS Must
parseRange String
s
| Bool
otherwise = ReadS Must
parseExact String
s
where
parseRange :: String -> [(Must, String)]
parseRange :: ReadS Must
parseRange String
str = case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'.') String
str of
(String
minStr, Char
'.' : Char
'.' : String
maxStr) ->
let minPart :: Maybe Integer
minPart = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
minStr then Maybe Integer
forall a. Maybe a
Nothing else String -> Maybe Integer
forall a. Read a => String -> Maybe a
readMaybe String
minStr
maxPart :: Maybe Integer
maxPart = if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
maxStr then Maybe Integer
forall a. Maybe a
Nothing else String -> Maybe Integer
forall a. Read a => String -> Maybe a
readMaybe String
maxStr
in case (Maybe Integer
minPart, Maybe Integer
maxPart, String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
minStr, String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
maxStr) of
(Maybe Integer
Nothing, Maybe Integer
Nothing, Bool
False, Bool
False) -> []
(Maybe Integer
Nothing, Maybe Integer
Nothing, Bool
True, Bool
True) -> []
(Maybe Integer
Nothing, Just Integer
max, Bool
True, Bool
False) ->
[(Maybe Integer -> Maybe Integer -> Must
MtRange Maybe Integer
forall a. Maybe a
Nothing (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
max), String
"") | Integer
max Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0]
(Just Integer
min, Maybe Integer
Nothing, Bool
False, Bool
True) ->
[(Maybe Integer -> Maybe Integer -> Must
MtRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
min) Maybe Integer
forall a. Maybe a
Nothing, String
"") | Integer
min Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0]
(Just Integer
min, Just Integer
max, Bool
False, Bool
False) ->
[(Maybe Integer -> Maybe Integer -> Must
MtRange (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
min) (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
max), String
"") | Integer
min Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
max Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0 Bool -> Bool -> Bool
&& Integer
min Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
max]
(Maybe Integer, Maybe Integer, Bool, Bool)
_ -> []
(String, String)
_ -> []
parseExact :: String -> [(Must, String)]
parseExact :: ReadS Must
parseExact String
str = case String -> Maybe Integer
forall a. Read a => String -> Maybe a
readMaybe String
str of
Just Integer
n | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0 -> [(if Integer
n Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0 then Must
MtDisabled else Integer -> Must
MtExact Integer
n, String
"")]
Just Integer
_ -> []
Maybe Integer
Nothing -> []
inRange :: Must -> Integer -> Bool
inRange :: Must -> Integer -> Bool
inRange Must
MtDisabled Integer
_ = Bool
True
inRange (MtExact Integer
expected) Integer
actual = Integer
actual Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
expected
inRange (MtRange Maybe Integer
minVal Maybe Integer
maxVal) Integer
actual =
Bool
checkMin Bool -> Bool -> Bool
&& Bool
checkMax
where
checkMin :: Bool
checkMin = Bool -> (Integer -> Bool) -> Maybe Integer -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
actual) Maybe Integer
minVal
checkMax :: Bool
checkMax = Bool -> (Integer -> Bool) -> Maybe Integer -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True (Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
actual) Maybe Integer
maxVal
exceedsUpperBound :: Must -> Integer -> Bool
exceedsUpperBound :: Must -> Integer -> Bool
exceedsUpperBound Must
MtDisabled Integer
_ = Bool
False
exceedsUpperBound (MtExact Integer
n) Integer
current = Integer
current Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
n
exceedsUpperBound (MtRange Maybe Integer
_ (Just Integer
max)) Integer
current = Integer
current Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
max
exceedsUpperBound (MtRange Maybe Integer
_ Maybe Integer
Nothing) Integer
_ = Bool
False