redo using record syntax

This commit is contained in:
Joey Hess 2011-03-15 19:11:21 -04:00
parent 940c4e361d
commit 675ee89749

100
Key.hs
View file

@ -7,39 +7,17 @@
module Key where module Key where
import Data.String.Utils
import Test.QuickCheck import Test.QuickCheck
import Data.Maybe import Utility
import Data.List
{- A Key has a unique name, is associated with a backend, {- A Key has a unique name, is associated with a backend,
- and may contain other metadata. -} - and may contain other metadata. -}
data Field = KeyName | KeyBackend | KeySize | KeyModTime data Key = Key {
deriving (Eq, Ord, Show) keyName :: String,
newtype Key = Key [(Field, String)] keyBackend :: String,
deriving (Eq, Ord) keySize :: Maybe Int,
keyMtime :: Maybe Int
{- Generates a Key given a name, a backend and a list of other metadata. -} } deriving (Eq, Ord)
keyGen :: String -> String -> [(Field, String)] -> Key
keyGen name backend meta = Key $ (KeyName, name):(KeyBackend, backend):meta
{- Gets the name of a Key. -}
keyName :: Key -> String
keyName key = fromJust $ keyField key KeyName
{- Gets the backend associated with a Key. -}
keyBackend :: Key -> String
keyBackend key = fromJust $ keyField key KeyBackend
{- Looks up a given Field of a Key's metadata. -}
keyField :: Key -> Field -> Maybe String
keyField (Key meta) field =
if null matches
then Nothing
else Just $ snd $ head matches
where
matches = filter match meta
match (f, _) = f == field
fieldSep :: Char fieldSep :: Char
fieldSep = ',' fieldSep = ','
@ -48,41 +26,47 @@ fieldSep = ','
- The name field is always shown last, and is the only field - The name field is always shown last, and is the only field
- allowed to contain the fieldSep. -} - allowed to contain the fieldSep. -}
instance Show Key where instance Show Key where
show k@(Key meta) = join [fieldSep] $ map showp meta' ++ [name] show Key { keyBackend = b, keySize = s, keyMtime = m, keyName = n } =
('b' : b) +++ ('s' ?: s) +++ ('m' ?: m) +++ ('n' : n)
where where
name = 'n':keyName k "" +++ y = y
meta' = sort $ (filter (\(f, _) -> f /= KeyName)) meta x +++ "" = x
showp (f, v) = (field f) : v x +++ y = x ++ fieldSep:y
c ?: (Just v) = c:(show v)
_ ?: _ = ""
field KeyBackend = 'b' readKey :: String -> Maybe Key
field KeySize = 's' readKey s = if key == stub then Nothing else key
field KeyModTime = 'm' where
field f = error $ "unknown key field" ++ show f key = findfields s stub
instance Read Key where stub = Just Key {
readsPrec _ s = [(Key (findfields s []), "")] keyName = "",
where keyBackend = "",
findfields ('n':v) m = (KeyName, v):m -- rest is name keySize = Nothing,
findfields (c:v) m = keyMtime = Nothing
case span (/= fieldSep) v of }
(v', _:r) -> findfields r (field c v' m)
_ -> m findfields ('n':v) (Just k) = Just $ k { keyName = v }
findfields [] m = m findfields (c:v) (Just k) =
case span (/= fieldSep) v of
field 'b' v m = (KeyBackend, v):m (v', _:r) -> findfields r $ addfield k c v'
field 's' v m = (KeySize, v):m _ -> Nothing
field 'm' v m = (KeyModTime, v):m findfields _ v = v
field _ _ m = m
addfield k 'b' v = Just k { keyBackend = v }
addfield k 's' v = Just k { keySize = readMaybe v }
addfield k 'm' v = Just k { keyMtime = readMaybe v }
addfield _ _ _ = Nothing
-- for quickcheck -- for quickcheck
instance Arbitrary Key where instance Arbitrary Key where
arbitrary = do arbitrary = do
backendname <- arbitrary n <- arbitrary
value <- arbitrary b <- elements ['A'..'Z']
return $ keyGen value backendname [] s <- arbitrary
m <- arbitrary
return $ Key { keyName = n, keyBackend = [b] , keySize = s, keyMtime = m }
prop_idempotent_key_read_show :: Key -> Bool prop_idempotent_key_read_show :: Key -> Bool
prop_idempotent_key_read_show k prop_idempotent_key_read_show k = Just k == (readKey $ show k)
-- backend names will never contain the fieldSep
| fieldSep `elem` (keyBackend k) = True
| otherwise = k == (read $ show k)