Eben.hs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-# LANGUAGE ViewPatterns #-}
  3. {-# LANGUAGE FlexibleInstances #-}
  4. module Data.Eben where
  5. import qualified Data.ByteString as B
  6. import Data.ByteString.Lazy (ByteString)
  7. import qualified Data.ByteString.Lazy as BS
  8. import Data.ByteString.Builder (Builder)
  9. import qualified Data.ByteString.Builder as BL
  10. import Data.Int (Int64)
  11. import Data.List (sortOn)
  12. import Data.Map.Strict (Map)
  13. import qualified Data.Map as M
  14. import Data.Monoid ((<>))
  15. import Data.Word (Word8)
  16. data Value
  17. = List [Value]
  18. | Dict (Map B.ByteString Value)
  19. | Integer Int64
  20. | Float Float
  21. | String B.ByteString
  22. deriving (Eq, Show, Read)
  23. decode :: ByteString -> Maybe (Value, ByteString)
  24. decode = go
  25. where go bs = case BS.uncons bs of
  26. Just (108, rs) -> decodeList [] rs
  27. Just (100, rs) -> decodeDict [] rs
  28. Just (105, rs) -> decodeInt rs
  29. Just (102, rs) -> decodeFloat rs
  30. Just (i , rs)
  31. | isDigit (fromIntegral i) -> do
  32. (s, rs) <- decodeBS bs
  33. return (String s, rs)
  34. | otherwise -> Nothing
  35. decodeList ls bs = case BS.uncons bs of
  36. Just (101, rs) -> Just (List ls, rs)
  37. _ -> do
  38. (x, rs) <- go bs
  39. decodeList (ls ++ [x]) rs
  40. decodeDict ls bs = case BS.uncons bs of
  41. Just (101, rs) -> Just (Dict (M.fromList ls), rs)
  42. _ -> do
  43. (k, rs) <- decodeBS bs
  44. (v, rs') <- go rs
  45. decodeDict ((k,v):ls) rs'
  46. decodeInt bs =
  47. let (is, rs) = BS.break (== 101) bs
  48. in return (Integer (toNum 0 is), BS.tail rs)
  49. decodeFloat bs =
  50. let (fs, rs) = BS.splitAt 4 bs
  51. in return (Float 0.0, BS.tail rs)
  52. decodeBS bs =
  53. let (is, rs') = BS.break (== 58) bs
  54. len = toNum 0 is
  55. (str, rs'') = BS.splitAt len (BS.tail rs')
  56. in Just (BS.toStrict str, rs'')
  57. class FromEben t where
  58. fromEben :: Value -> Maybe t
  59. instance FromEben Float where
  60. fromEben (Float f) = Just f
  61. fromEben (Integer i) = Just (fromIntegral i)
  62. fromEben _ = Nothing
  63. instance FromEben Int where
  64. fromEben (Integer i) = Just (fromIntegral i)
  65. fromEben _ = Nothing
  66. instance FromEben a => FromEben [a] where
  67. fromEben (List ls) = mapM fromEben ls
  68. fromEben _ = Nothing
  69. instance (FromEben a, FromEben b) => FromEben (a, b) where
  70. fromEben (List [x,y]) = (,) <$> fromEben x <*> fromEben y
  71. fromEben _ = Nothing
  72. asDict :: Value -> Maybe (Map B.ByteString Value)
  73. asDict (Dict ds) = Just ds
  74. asDict _ = Nothing
  75. asList :: Value -> Maybe [Value]
  76. asList (List ls) = Just ls
  77. asList _ = Nothing
  78. asFloat :: Value -> Maybe Float
  79. asFloat (Float f) = Just f
  80. asFloat (Integer i) = Just (fromIntegral i)
  81. asFloat _ = Nothing
  82. lookup :: B.ByteString -> Value -> Maybe Value
  83. lookup k (Dict ds) = M.lookup k ds
  84. lookup _ _ = Nothing
  85. isDigit :: Word8 -> Bool
  86. isDigit n = n >= 48 && n <= 57
  87. toDigit :: Word8 -> Int64
  88. toDigit n = fromIntegral n - 48
  89. toNum :: Int64 -> ByteString -> Int64
  90. toNum n (BS.uncons->Just(b, bs)) =
  91. toNum (n * 10 + toDigit b) bs
  92. toNum n _ = n
  93. class ToEben t where
  94. toEben :: t -> Value
  95. instance ToEben a => ToEben [a] where
  96. toEben = List . map toEben
  97. instance ToEben Float where
  98. toEben = Float
  99. instance ToEben Int where
  100. toEben = Integer . fromIntegral
  101. instance ToEben Integer where
  102. toEben = Integer . fromIntegral
  103. instance (ToEben l, ToEben r) => ToEben (l, r) where
  104. toEben (x, y) = List [ toEben x, toEben y ]
  105. dict :: [(B.ByteString, Value)] -> Value
  106. dict = Dict . M.fromList
  107. encode :: Value -> ByteString
  108. encode = BL.toLazyByteString . go
  109. where go (List vs) =
  110. BL.char7 'l' <> foldMap go vs <> BL.char7 'e'
  111. go (Dict vs) =
  112. BL.char7 'd'
  113. <> mconcat [ str k <> go v | (k, v) <- sortOn fst (M.toList vs) ]
  114. <> BL.char7 'e'
  115. go (Integer i) =
  116. BL.char7 'i' <> BL.string8 (show i) <> BL.char7 'e'
  117. go (Float f) =
  118. BL.char7 'f' <> BL.floatLE f <> BL.char7 'e'
  119. go (String bs) = str bs
  120. str bs =
  121. BL.intDec (B.length bs)
  122. <> BL.char7 ':'
  123. <> BL.byteString bs