summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwardKmett <>2013-08-21 21:13:54 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2013-08-21 21:13:54 (GMT)
commitc5eeb067a742e42e43d54f2062aa85c64ef30231 (patch)
tree1df711ceee5eeea2c44aa5244e3bfb49f9981bd2
parent3318b6d167eae6e9ae9d4120c148157d75bf81ec (diff)
version 0.110.11
-rw-r--r--CHANGELOG.markdown4
-rw-r--r--bytes.cabal6
-rw-r--r--src/Data/Bytes/Get.hs10
-rw-r--r--src/Data/Bytes/Put.hs10
-rw-r--r--src/Data/Bytes/Serial.hs4
-rw-r--r--src/Data/Bytes/Signed.hs53
-rw-r--r--src/Data/Bytes/VarInt.hs66
7 files changed, 149 insertions, 4 deletions
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
index 9ddb323..7d58750 100644
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,7 @@
+0.11
+----
+* Added `Data.Bytes.VarInt` and `Data.Bytes.Signed`.
+
0.10.2
------
* Switched to <stdint.h> to get more portable size correctness.
diff --git a/bytes.cabal b/bytes.cabal
index a0f2b35..00ba922 100644
--- a/bytes.cabal
+++ b/bytes.cabal
@@ -1,6 +1,6 @@
name: bytes
category: Data, Serialization
-version: 0.10.2
+version: 0.11
license: BSD3
cabal-version: >= 1.8
license-file: LICENSE
@@ -55,8 +55,10 @@ library
exposed-modules:
Data.Bytes.Get
- Data.Bytes.Serial
Data.Bytes.Put
+ Data.Bytes.Serial
+ Data.Bytes.Signed
+ Data.Bytes.VarInt
if flag(lib-Werror)
ghc-options: -Werror
diff --git a/src/Data/Bytes/Get.hs b/src/Data/Bytes/Get.hs
index ac58037..3ad5e0a 100644
--- a/src/Data/Bytes/Get.hs
+++ b/src/Data/Bytes/Get.hs
@@ -21,6 +21,8 @@
--------------------------------------------------------------------
module Data.Bytes.Get
( MonadGet(..)
+ , runGetL
+ , runGetS
) where
import Control.Applicative
@@ -404,3 +406,11 @@ instance (MonadGet m, Monoid w) => MonadGet (Lazy.RWST r w s m) where
distribute (Right b, s', w') = Right (Right b, s', w')
factor = either id id
{-# INLINE lookAheadE #-}
+
+-- | Get something from a lazy 'Lazy.ByteString' using 'B.runGet'.
+runGetL :: B.Get a -> Lazy.ByteString -> a
+runGetL = B.runGet
+
+-- | Get something from a strict 'Strict.ByteString' using 'S.runGet'.
+runGetS :: S.Get a -> Strict.ByteString -> Either String a
+runGetS = S.runGet
diff --git a/src/Data/Bytes/Put.hs b/src/Data/Bytes/Put.hs
index 7677ca5..934fa26 100644
--- a/src/Data/Bytes/Put.hs
+++ b/src/Data/Bytes/Put.hs
@@ -23,6 +23,8 @@
--------------------------------------------------------------------
module Data.Bytes.Put
( MonadPut(..)
+ , runPutL
+ , runPutS
) where
import Control.Applicative
@@ -238,3 +240,11 @@ instance (MonadPut m, Monoid w) => MonadPut (Lazy.WriterT w m)
instance (MonadPut m, Monoid w) => MonadPut (Strict.WriterT w m)
instance (MonadPut m, Monoid w) => MonadPut (Lazy.RWST r w s m)
instance (MonadPut m, Monoid w) => MonadPut (Strict.RWST r w s m)
+
+-- | Put a value into a lazy 'Lazy.ByteString' using 'B.runPut'.
+runPutL :: B.Put -> Lazy.ByteString
+runPutL = B.runPut
+
+-- | Put a value into a strict 'Strict.ByteString' using 'S.runPut'.
+runPutS :: S.Put -> Strict.ByteString
+runPutS = S.runPut
diff --git a/src/Data/Bytes/Serial.hs b/src/Data/Bytes/Serial.hs
index fd887a0..aedcf8b 100644
--- a/src/Data/Bytes/Serial.hs
+++ b/src/Data/Bytes/Serial.hs
@@ -125,11 +125,11 @@ foreign import ccall word64ToDouble :: Word64 -> Double
instance Serial Double where
serialize = serialize . doubleToWord64
- deserialize = liftM word64ToDouble restore
+ deserialize = liftM word64ToDouble deserialize
instance Serial Float where
serialize = serialize . floatToWord32
- deserialize = liftM word32ToFloat restore
+ deserialize = liftM word32ToFloat deserialize
instance Serial Char where
serialize = putWord32be . fromIntegral . fromEnum
diff --git a/src/Data/Bytes/Signed.hs b/src/Data/Bytes/Signed.hs
new file mode 100644
index 0000000..3280ac4
--- /dev/null
+++ b/src/Data/Bytes/Signed.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeFamilies #-}
+--------------------------------------------------------------------
+-- |
+-- License : BSD3
+-- Stability : experimental
+-- Portability: type-families
+--
+-- When one wants to think of an 'Int' as a dumb bitstring, converting
+-- it to a 'Word' avoids pesky complications with respect to sign
+-- extension.
+--------------------------------------------------------------------
+
+module Data.Bytes.Signed
+ ( Unsigned, unsigned
+ , Signed, signed
+ ) where
+
+import Data.Int
+import Data.Word
+
+type family Unsigned i :: *
+
+type instance Unsigned Int = Word
+type instance Unsigned Int8 = Word8
+type instance Unsigned Int16 = Word16
+type instance Unsigned Int32 = Word32
+type instance Unsigned Int64 = Word64
+
+type instance Unsigned Word = Word
+type instance Unsigned Word8 = Word8
+type instance Unsigned Word16 = Word16
+type instance Unsigned Word32 = Word32
+type instance Unsigned Word64 = Word64
+
+unsigned :: (Integral i, Num (Unsigned i)) => i -> Unsigned i
+unsigned = fromIntegral
+
+type family Signed i :: *
+type instance Signed Int = Int
+type instance Signed Int8 = Int8
+type instance Signed Int16 = Int16
+type instance Signed Int32 = Int32
+type instance Signed Int64 = Int64
+
+type instance Signed Word = Int
+type instance Signed Word8 = Int8
+type instance Signed Word16 = Int16
+type instance Signed Word32 = Int32
+type instance Signed Word64 = Int64
+
+signed :: (Integral i, Num (Signed i)) => i -> Signed i
+signed = fromIntegral
diff --git a/src/Data/Bytes/VarInt.hs b/src/Data/Bytes/VarInt.hs
new file mode 100644
index 0000000..4a8eac0
--- /dev/null
+++ b/src/Data/Bytes/VarInt.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE TypeFamilies #-}
+--------------------------------------------------------------------
+-- |
+-- License : BSD3
+-- Stability : experimental
+-- Portability: type-families, generalized newtype deriving
+--
+-- This module provides a 'VarInt' wrapper with a 'Serial' instance
+-- that generates base-128 variable-width ints. Values are encoded 7
+-- bits at a time, with the most significant being a continuation bit.
+-- Thus, the numbers from 0 to 127 require only a single byte to
+-- encode, those from 128 to 16383 require two bytes, etc.
+--
+-- This format is taken from Google's /Protocol Buffers/, which
+-- provides a bit more verbiage on the encoding:
+-- <https://developers.google.com/protocol-buffers/docs/encoding#varints>.
+--------------------------------------------------------------------
+
+module Data.Bytes.VarInt
+ ( VarInt(..)
+ ) where
+
+import Data.Bits
+import Data.Bytes.Get
+import Data.Bytes.Put
+import Data.Bytes.Serial
+import Data.Bytes.Signed
+import Data.Word
+
+-- | Integer/Word types serialized to base-128 variable-width ints.
+--
+-- >>> runPutL $ serialize (97 :: Word64)
+-- "a\NUL\NUL\NUL\NUL\NUL\NUL\NUL"
+-- >>> runPutL $ serialize (97 :: VarInt Word64)
+-- "a"
+newtype VarInt n = VarInt { unVarInt :: n }
+ deriving (Eq, Ord, Show, Enum, Num, Integral, Bounded, Real, Bits)
+
+type instance Unsigned (VarInt n) = VarInt (Unsigned n)
+type instance Signed (VarInt n) = VarInt (Signed n)
+
+instance (Bits n, Integral n, Bits (Unsigned n), Integral (Unsigned n)) => Serial (VarInt n) where
+ serialize (VarInt n) = putVarInt $ unsigned n
+ {-# INLINE serialize #-}
+
+ deserialize = getWord8 >>= getVarInt
+ {-# INLINE deserialize #-}
+
+putVarInt :: (MonadPut m, Integral a, Bits a) => a -> m ()
+putVarInt n
+ | n < 0x80 = putWord8 $ fromIntegral n
+ | otherwise = do
+ putWord8 $ setBit (fromIntegral n) 7
+ putVarInt $ shiftR n 7
+{-# INLINE putVarInt #-}
+
+getVarInt :: (MonadGet m, Num b, Bits b) => Word8 -> m b
+getVarInt n
+ | testBit n 7 = do
+ VarInt m <- getWord8 >>= getVarInt
+ return $ shiftL m 7 .|. clearBit (fromIntegral n) 7
+ | otherwise = return $ fromIntegral n
+{-# INLINE getVarInt #-}