{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} #if __GLASGOW_HASKELL__ >= 710 {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PatternSynonyms #-} #endif ----------------------------------------------------------------------------- -- | -- Module : Data.ByteString.Strict.Lens -- Copyright : (C) 2012-2015 Edward Kmett -- License : BSD-style (see the file LICENSE) -- Maintainer : Edward Kmett <ekmett@gmail.com> -- Stability : experimental -- Portability : non-portable -- ---------------------------------------------------------------------------- module Data.ByteString.Strict.Lens ( packedBytes, unpackedBytes, bytes , packedChars, unpackedChars, chars #if __GLASGOW_HASKELL__ >= 710 , pattern Bytes , pattern Chars #endif ) where import Control.Lens import Control.Lens.Internal.ByteString import Data.ByteString as Words import Data.ByteString.Char8 as Char8 import Data.Word -- $setup -- >>> import Control.Lens -- >>> import Numeric.Lens -- | 'Data.ByteString.pack' (or 'Data.ByteString.unpack') a list of bytes into a 'ByteString' -- -- @ -- 'packedBytes' ≡ 'from' 'unpackedBytes' -- 'Data.ByteString.pack' x ≡ x '^.' 'packedBytes' -- 'Data.ByteString.unpack' x ≡ x '^.' 'from' 'packedBytes' -- @ -- -- >>> [104,101,108,108,111]^.packedBytes -- "hello" packedBytes :: Iso' [Word8] ByteString packedBytes = iso Words.pack unpackStrict {-# INLINE packedBytes #-} -- | 'Data.ByteString.unpack' (or 'Data.ByteString.pack') a 'ByteString' into a list of bytes -- -- @ -- 'unpackedBytes' ≡ 'from' 'packedBytes' -- 'Data.ByteString.unpack' x ≡ x '^.' 'unpackedBytes' -- 'Data.ByteString.pack' x ≡ x '^.' 'from' 'unpackedBytes' -- @ -- -- >>> "hello"^.packedChars.unpackedBytes -- [104,101,108,108,111] unpackedBytes :: Iso' ByteString [Word8] unpackedBytes = from packedBytes {-# INLINE unpackedBytes #-} -- | Traverse each 'Word8' in a 'ByteString'. -- -- This 'Traversal' walks the 'ByteString' in a tree-like fashion -- enable zippers to seek to locations in logarithmic time and accelerating -- many monoidal queries, but up to associativity (and constant factors) -- it is equivalent to the much slower: -- -- @ -- 'bytes' ≡ 'unpackedBytes' '.' 'traversed' -- @ -- -- >>> anyOf bytes (== 0x80) (Char8.pack "hello") -- False -- -- Note that when just using this as a 'Setter', @'setting' 'Data.ByteString.map'@ -- can be more efficient. bytes :: IndexedTraversal' Int ByteString Word8 bytes = traversedStrictTree {-# INLINE bytes #-} -- | 'Data.ByteString.Char8.pack' (or 'Data.ByteString.Char8.unpack') a list of characters into a 'ByteString' -- -- When writing back to the 'ByteString' it is assumed that every 'Char' -- lies between @'\x00'@ and @'\xff'@. -- -- @ -- 'packedChars' ≡ 'from' 'unpackedChars' -- 'Data.ByteString.Char8.pack' x ≡ x '^.' 'packedChars' -- 'Data.ByteString.Char8.unpack' x ≡ x '^.' 'from' 'packedChars' -- @ -- -- >>> "hello"^.packedChars.each.re (base 16 . enum).to (\x -> if Prelude.length x == 1 then '0':x else x) -- "68656c6c6f" packedChars :: Iso' String ByteString packedChars = iso Char8.pack unpackStrict8 {-# INLINE packedChars #-} -- | 'Data.ByteString.Char8.unpack' (or 'Data.ByteString.Char8.pack') a list of characters into a 'ByteString' -- -- When writing back to the 'ByteString' it is assumed that every 'Char' -- lies between @'\x00'@ and @'\xff'@. -- -- @ -- 'unpackedChars' ≡ 'from' 'packedChars' -- 'Data.ByteString.Char8.unpack' x ≡ x '^.' 'unpackedChars' -- 'Data.ByteString.Char8.pack' x ≡ x '^.' 'from' 'unpackedChars' -- @ -- -- >>> [104,101,108,108,111]^.packedBytes.unpackedChars -- "hello" unpackedChars :: Iso' ByteString String unpackedChars = from packedChars {-# INLINE unpackedChars #-} -- | Traverse the individual bytes in a 'ByteString' as characters. -- -- When writing back to the 'ByteString' it is assumed that every 'Char' -- lies between @'\x00'@ and @'\xff'@. -- -- This 'Traversal' walks the 'ByteString' in a tree-like fashion -- enable zippers to seek to locations in logarithmic time and accelerating -- many monoidal queries, but up to associativity (and constant factors) -- it is equivalent to the much slower: -- -- @ -- 'chars' = 'unpackedChars' '.' 'traverse' -- @ -- -- >>> anyOf chars (== 'h') "hello" -- True chars :: IndexedTraversal' Int ByteString Char chars = traversedStrictTree8 {-# INLINE chars #-} #if __GLASGOW_HASKELL__ >= 710 pattern Bytes b <- (view unpackedBytes -> b) where Bytes b = review unpackedBytes b pattern Chars b <- (view unpackedChars -> b) where Chars b = review unpackedChars b #endif