diff --git a/hsrc_lib/Database/VCache/VGet.hs b/hsrc_lib/Database/VCache/VGet.hs
--- a/hsrc_lib/Database/VCache/VGet.hs
+++ b/hsrc_lib/Database/VCache/VGet.hs
@@ -15,6 +15,9 @@
     , getByteString, getByteStringLazy
     , getc
 
+    -- * zero copy access
+    , withBytes
+
     -- * Parser Combinators
     , isolate
     , label
@@ -118,7 +121,8 @@
         _ -> return (VGetE "getPVar")
 {-# INLINABLE getPVar #-}
 
--- | Read the VSpace. This value is constant for a full VGet operation.
+-- | Obtain the VSpace associated with content being read. Does not
+-- consume any data.
 getVSpace :: VGet VSpace 
 getVSpace = VGet $ \ s -> return (VGetR (vget_space s) s)
 {-# INLINE getVSpace #-}
@@ -229,13 +233,7 @@
 {-# INLINE getStorable #-}
 
 _getStorable :: (Storable a) => a -> VGet a
-_getStorable _dummy = 
-    let n = sizeOf _dummy in
-    consuming n $ VGet $ \ s -> do
-        let pTgt = vget_target s 
-        let s' = s { vget_target = pTgt `plusPtr` n }
-        a <- peekAligned (castPtr pTgt)
-        return (VGetR a s')
+_getStorable _dummy = withBytes (sizeOf _dummy) (peekAligned . castPtr)
 {-# INLINE _getStorable #-}
 
 -- | Load a number of bytes from the underlying object. A copy is
@@ -248,20 +246,27 @@
 {-# INLINE getByteString #-}
 
 _getByteString :: Int -> VGet BS.ByteString
-_getByteString n = consuming n $ VGet $ \ s -> do
-    let pSrc = vget_target s
+_getByteString n = withBytes n $ \ pSrc -> do
     pDst <- mallocBytes n
     copyBytes pDst pSrc n
     fp <- newForeignPtr finalizerFree pDst
-    let r = BSI.fromForeignPtr fp 0 n
-    let s' = s { vget_target = (pSrc `plusPtr` n) }
-    return (VGetR r s')
+    return $! BSI.fromForeignPtr fp 0 n
 
 -- | Get a lazy bytestring. (Simple wrapper on strict bytestring.)
 getByteStringLazy :: Int -> VGet LBS.ByteString
 getByteStringLazy n = LBS.fromStrict <$> getByteString n
 {-# INLINE getByteStringLazy #-}
 
+-- | Access a given number of bytes without copying them. These bytes
+-- are read-only, and are considered to be consumed upon returning. 
+-- The pointer should be considered invalid after returning from the
+-- withBytes computation.
+withBytes :: Int -> (Ptr Word8 -> IO a) -> VGet a
+withBytes n action = consuming n $ VGet $ \ s -> do
+    let pTgt = vget_target s  
+    let s' = s { vget_target = pTgt `plusPtr` n }
+    a <- action pTgt
+    return (VGetR a s')
 
 -- | Get a character from UTF-8 format. Assumes a valid encoding.
 -- (In case of invalid encoding, arbitrary characters may be returned.)
diff --git a/vcache.cabal b/vcache.cabal
--- a/vcache.cabal
+++ b/vcache.cabal
@@ -1,23 +1,24 @@
 Name: vcache
-Version: 0.2.3
-Synopsis: large, persistent, memcached values and structure sharing for Haskell 
+Version: 0.2.4
+Synopsis: semi-transparent persistence for Haskell using LMDB, STM
 Category: Database
 Description:
   VCache provides a nearly-transparent persistent memory for Haskell
-  with transactional variables, persistent roots, and large structured
-  values. The virtual space is a memory-mapped file via LMDB, with 
-  structure sharing and incremental GC. 
+  supporting ACID transactional variables and large structured values.
+  The virtual address space is modeled above a memory mapped file via
+  LMDB, with structure sharing and incremental reference counting GC.
   .
-  VCache is very similar to packages acid-state, perdure, and TCache.
-  VCache is intended as an acid-state alternative, offering flexibility
-  to model fine-grained variables or extremely large values.
+  VCache was developed as an alternative to acid-state in a context where
+  the persistent data is much bigger than the active working set and RAM.
+  Other similar packages include TCache and perdure. See the home page 
+  for a simple comparison.
   
 Author: David Barbour
 Maintainer: dmbarbour@gmail.com
 Homepage: http://github.com/dmbarbour/haskell-vcache
 
 Package-Url: 
-Copyright: (c) 2014 by David Barbour
+Copyright: (c) 2014-2015 by David Barbour
 License: BSD3
 license-file: LICENSE
 Stability: experimental
