diff --git a/src/Streaming/Binary.hs b/src/Streaming/Binary.hs
--- a/src/Streaming/Binary.hs
+++ b/src/Streaming/Binary.hs
@@ -17,10 +17,21 @@
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE OverloadedStrings #-}
 
-module Streaming.Binary (decode, decodeWith, decoded, decodedWith) where
+module Streaming.Binary
+  ( decode
+  , decodeWith
+  , decoded
+  , decodedWith
+  , encode
+  , encodeWith
+  , encoded
+  , encodedWith
+  ) where
 
 import qualified Data.Binary.Get as Binary
+import qualified Data.Binary.Put as Binary
 import Data.Binary (Binary(..))
+import qualified Data.ByteString.Builder.Extra as BS
 import qualified Data.ByteString.Streaming as Q
 import Data.ByteString.Streaming (ByteString)
 import Data.Int (Int64)
@@ -79,3 +90,37 @@
       lift (Q.nextChunk p) >>= \case
         Left res -> go total (k Nothing) (return res)
         Right (bs, p') -> go total (k (Just bs)) p'
+
+encode
+  :: (Binary a, MonadIO m)
+  => a
+  -> ByteString m ()
+encode = encodeWith put
+
+encodeWith
+  :: MonadIO m
+  => (a -> Binary.Put)
+  -> a
+  -> ByteString m ()
+encodeWith putter x =
+    Q.toStreamingByteStringWith
+      (BS.untrimmedStrategy BS.smallChunkSize BS.defaultChunkSize)
+      (Binary.execPut (putter x))
+
+encoded
+  :: (Binary a, MonadIO m)
+  => Stream (Of a) IO ()
+  -> ByteString m ()
+encoded = encodedWith put
+
+encodedWith
+  :: MonadIO m
+  => (a -> Binary.Put)
+  -> Stream (Of a) IO ()
+  -> ByteString m ()
+encodedWith putter xs =
+    hoist liftIO $
+    Q.toStreamingByteStringWith strategy $
+    Q.concatBuilders (S.map (Binary.execPut . putter) xs)
+  where
+    strategy = BS.untrimmedStrategy BS.smallChunkSize BS.defaultChunkSize
diff --git a/streaming-binary.cabal b/streaming-binary.cabal
--- a/streaming-binary.cabal
+++ b/streaming-binary.cabal
@@ -1,5 +1,5 @@
 name: streaming-binary
-version: 0.2.2.0
+version: 0.3.0.0
 synopsis: Streaming interface to binary.
 homepage: https://github.com/mboes/streaming-binary#readme
 license: BSD3
@@ -22,6 +22,7 @@
   build-depends:
     base >= 4.7 && < 5,
     binary >= 0.8,
+    bytestring >= 0.10,
     streaming >= 0.1.4,
     streaming-bytestring >= 0.1.4
   default-language: Haskell2010
diff --git a/test/Streaming/BinarySpec.hs b/test/Streaming/BinarySpec.hs
--- a/test/Streaming/BinarySpec.hs
+++ b/test/Streaming/BinarySpec.hs
@@ -14,7 +14,7 @@
 spec :: Spec
 spec = do
     let input n = Q.fromLazy $ runPut $ replicateM_ n $ put (42 :: Int)
-    describe "decoded" $ do
+    describe "decode" $ do
       it "fails on empty inputs" $ do
         (_, _, output) <- decode @Int (input 0)
         output `shouldBe` Left "not enough bytes"
@@ -41,3 +41,10 @@
         let input' = Q.take (fromIntegral (n - 1)) (input 10)
         (leftover, _, _) <- S.effects (decoded @Int input')
         Q.length_ leftover `shouldReturn` (n `div` 10) - 1
+    describe "laws" $ do
+      it "decode . encode = id for booleans" $ do
+        (_, _, output) <- decode (encode True)
+        output `shouldBe` Right True
+      it "decoded . encoded = id for booleans" $ do
+        xs <- S.replicate 10 True & encoded & decoded & void & S.toList_
+        xs `shouldBe` (replicate 10 True)
