diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- 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
--- 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 @@
 
   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
--- 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 @@
     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
--- 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 (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
--- a/src/Data/Bytes/Serial.hs
+++ b/src/Data/Bytes/Serial.hs
@@ -125,11 +125,11 @@
 
 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
--- /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
--- /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 #-}
