Eben.hs 3.2 KB

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