packages feed

base64 0.0.1.0 → 0.1.0.0

raw patch · 10 files changed

+346/−245 lines, 10 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Data.ByteString.Base64.Lens: class AsBase64 s where {
- Data.ByteString.Base64.Lens: class AsBase64Unpadded s where {
- Data.ByteString.Base64.Lens: instance Data.ByteString.Base64.Lens.AsBase64 Data.ByteString.Internal.ByteString
- Data.ByteString.Base64.Lens: instance Data.ByteString.Base64.Lens.AsBase64Unpadded Data.ByteString.Internal.ByteString
- Data.ByteString.Base64.Lens: type family Base64Unpadded s;
- Data.ByteString.Base64.Lens: }
- Data.Text.Encoding.Base64.Lens: class AsBase64 s where {
- Data.Text.Encoding.Base64.Lens: class AsBase64Unpadded s where {
- Data.Text.Encoding.Base64.Lens: instance Data.ByteString.Base64.Lens.AsBase64 Data.Text.Internal.Text
- Data.Text.Encoding.Base64.Lens: instance Data.ByteString.Base64.Lens.AsBase64Unpadded Data.Text.Internal.Text
- Data.Text.Encoding.Base64.Lens: type family Base64Unpadded s;
- Data.Text.Encoding.Base64.Lens: }
+ Data.ByteString.Base64.Lens: pattern Base64 :: ByteString -> ByteString
+ Data.ByteString.Base64.Lens: pattern Base64Unpadded :: ByteString -> ByteString
+ Data.ByteString.Base64.Lens: pattern Base64Url :: ByteString -> ByteString
+ Data.ByteString.Base64.Lens: pattern Base64UrlUnpadded :: ByteString -> ByteString
+ Data.Text.Encoding.Base64.Lens: pattern Base64 :: Text -> Text
+ Data.Text.Encoding.Base64.Lens: pattern Base64Unpadded :: Text -> Text
+ Data.Text.Encoding.Base64.Lens: pattern Base64Url :: Text -> Text
+ Data.Text.Encoding.Base64.Lens: pattern Base64UrlUnpadded :: Text -> Text
- Data.ByteString.Base64.Lens: _Base64 :: AsBase64 s => Prism' s (Base64 s)
+ Data.ByteString.Base64.Lens: _Base64 :: Prism' ByteString ByteString
- Data.ByteString.Base64.Lens: _Base64Unpadded :: AsBase64Unpadded s => Prism' s (Base64Unpadded s)
+ Data.ByteString.Base64.Lens: _Base64Unpadded :: Prism' ByteString ByteString
- Data.ByteString.Base64.Lens: _Base64Url :: AsBase64 s => Prism' s (Base64 s)
+ Data.ByteString.Base64.Lens: _Base64Url :: Prism' ByteString ByteString
- Data.ByteString.Base64.Lens: _Base64UrlUnpadded :: AsBase64Unpadded s => Prism' s (Base64Unpadded s)
+ Data.ByteString.Base64.Lens: _Base64UrlUnpadded :: Prism' ByteString ByteString
- Data.Text.Encoding.Base64.Lens: _Base64 :: AsBase64 s => Prism' s (Base64 s)
+ Data.Text.Encoding.Base64.Lens: _Base64 :: Prism' Text Text
- Data.Text.Encoding.Base64.Lens: _Base64Unpadded :: AsBase64Unpadded s => Prism' s (Base64Unpadded s)
+ Data.Text.Encoding.Base64.Lens: _Base64Unpadded :: Prism' Text Text
- Data.Text.Encoding.Base64.Lens: _Base64Url :: AsBase64 s => Prism' s (Base64 s)
+ Data.Text.Encoding.Base64.Lens: _Base64Url :: Prism' Text Text
- Data.Text.Encoding.Base64.Lens: _Base64UrlUnpadded :: AsBase64Unpadded s => Prism' s (Base64Unpadded s)
+ Data.Text.Encoding.Base64.Lens: _Base64UrlUnpadded :: Prism' Text Text

Files

README.md view
@@ -1,51 +1,91 @@ # Base64  [![Build Status](https://travis-ci.com/emilypi/base64.svg?branch=master)](https://travis-ci.com/emilypi/base64)+[![Hackage](https://img.shields.io/hackage/v/base64.svg)](https://hackage.haskell.org/package/base64)  Padded and unpadded base64 and base64url encodings for `Text` and `ByteString` values, along with their optics.  -### Why?+### Summary +What does this library provide? Here is the summary:++- Better performance over existing Base64 libraries (2x and 3x for most use-cases - see [PERFORMANCE.md](benchmarks/PERFORMANCE.md))+- Support for unpadded Base64 and Base64-url+- Support for `Text` encodings and decodings+- Optics for handling more complex structures with Base64 representations+++### Motivation+ Haskell has two main libraries for Base64: `memory`, and `base64-bytestring`. -Of these, `memory` is geared towards integration with other memory primitives in the library, without much of an eye towards performance, while `base64-bytestring` is built to exclusively address `ByteString` encoding and decoding, and is very performant. Many great strides have been made in the realm of Base64 performance and vectorization just in the past 5 years, which this library attempts to capture. Additionally, we attempt to fix percieved shortcomings with both APIs in the support of unpadded Base64 and Base64-url support (which `memory` provides, but not `base64-bytestring`), as well as supporting `Text` values (neither libraries provide), and also supplying some nice compositional optics for composing structures with Base64-encodable/decodable focii (neither libraries provide).+Of these, `memory` is geared towards integration with other memory primitives in the library, without much of an eye towards performance, while `base64-bytestring` is built to exclusively address `ByteString` encoding and decoding, and is very performant. Many great strides have been made in the realm of Base64 performance and vectorization just in the past 5 years, which this library attempts to capture. Additionally, we attempt to fix percieved shortcomings with both APIs in the support of unpadded Base64 and Base64-url support (which `memory` provides, but not `base64-bytestring`), as well as supporting `Text` values (neither libraries provide), supplying some optics for composing structures with Base64-encodable/decodable focii (neither libraries provide), and convenient pattern synonyms (no library to date does this). -### Optics+### Patterns -Structs may want to support encoding and decoding their substructures, which is supported with the following prismatic typeclass:+The pattern synonyms provided in this library are:  ```haskell-class AsBase64 s where-    type Base64 s-    -- | A prism into a base64-encoded focus of-    -- some type-    ---    _Base64 :: Prism' s (Base64 s)+pattern Base64 :: ByteString -> ByteString+pattern Base64Url :: ByteString -> ByteString+pattern Base64Unpadded :: ByteString -> ByteString+pattern Base64UrlUnpadded :: ByteString -> ByteString -    -- | A prism into the base64url-encoded focus of-    -- some type-    ---    _Base64Url :: Prism' s (Base64 s)+-- and++pattern Base64 :: Text -> Text+pattern Base64Url :: Text -> Text+pattern Base64Unpadded :: Text -> Text+pattern Base64UrlUnpadded :: Text -> Text ``` -The data of a `Prism` naturally conforms to this "encoding/decoding" dichotomy, where the `Review`, or "builder" half of the `Prism` of type `b -> t` is an encoding, and the "Matcher" half of the prism, of type `s -> Either t a`, represents a decoding of a similar structure. Monomorphizing for `t ~ s` and `a ~ b`, a simple `Prism` is formed:+These provide a convenient high level interface for passing Base64 encoded values. ++### Optics++`Prism`s for encoding and decoding `Text` and `ByteString` values are given as part of the library:++ ```haskell->>> _Base64 @Text # "<<???>>"-"PDw/Pz8+Pg=="+_Base64 :: Prism' ByteString ByteString+_Base64Url :: Prism' ByteString ByteString+_Base64Unpadded :: Prism' ByteString ByteString+_Base64UrlUnpadded :: Prism' ByteString ByteString ->>> "PDw/Pz8+Pg==" ^? _Base64 @Text-Just "<<???>>"+-- and++_Base64 :: Prism' Text Text+_Base64Url :: Prism' Text Text+_Base64Unpadded :: Prism' Text Text+_Base64UrlUnpadded :: Prism' Text Text+ ``` -The two most obvious types for which we have an instance are those that are supported natively by the library: `ByteString` and `Text`. Trivially, their instances consist of the functions provided here in this library.+If a particular structure has a `Lens` into some `Text` or `ByteString` value they might want to encode (or decode), then composing such a `Lens` with these `Prisms` yields an affine `Traversal`, resulting in a structure which has the focus of its `Lens` encoded as or decoded from Base64(-url). All one needs to do is compose their optics: -### Summary+```haskell -What does this library provide? Here is the summary:+data MyStruct = MyStruct+  { _a :: Int+  , _b :: Text+  } deriving Show -- Better performance over existing Base64 libraries (2x and 3x for most use-cases - see [PERFORMANCE.md](benchmarks/PERFORMANCE.md))-- Support for unpadded Base64 and Base64-url-- Support for `Text` encodings and decodings-- Classy optics for handling more complex structures with Base64 representations+b :: Lens' MyStruct Text+b = lens _b (\t b_ -> t { _b = b_ })++myB64Struct :: Traversal' s Text+myB64Struct = b . _Base64++-- >>> MyStruct 3 "U3Vu" ^? b . _Base64+-- MyStruct {_a = 3, _b = "Sun"}++bRe :: Review MyStruct Text+bRe = unto (\b -> MyStruct 0 b)++-- >>> bRe . _Base64 # "Sun"+-- MyStruct {_a = 0, _b = "UV3u"}+```++The data of a `Prism` naturally conforms to this "encoding/decoding" dichotomy, where the `Review`, or "builder" half of the `Prism` of type `b -> t` is an encoding, and the "Matcher" half of the prism, of type `s -> Either t a`, represents a decoding of a similar structure. Hence, `Prism` is the most appropriate structure.
base64.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.4  name:                base64-version:             0.0.1.0+version:             0.1.0.0 synopsis:            RFC 4648-compliant padded and unpadded base64 and base64url encodings description:   RFC 4648-compliant padded and unpadded base64 and base64url encoding and decoding.@@ -18,7 +18,7 @@   CHANGELOG.md   README.md -tested-with:         GHC ==8.8.1 || ==8.6.5 || ==8.6.3 || ==8.4.4 || ==8.4.3 || ==8.0.2+tested-with:         GHC ==8.8.1 || ==8.6.5 || ==8.6.3 || ==8.4.4 || ==8.4.3 || ==8.2.2  source-repository head   type:     git@@ -45,7 +45,7 @@    other-modules:       Data.ByteString.Base64.Internal -  build-depends:       base       >=4.9 && <5+  build-depends:       base       >=4.10 && <5                      , bytestring                      , deepseq                      , text@@ -70,7 +70,7 @@   type:                exitcode-stdio-1.0   hs-source-dirs:      test   main-is:             Base64Tests.hs-  build-depends:       base >=4.9 && <5+  build-depends:       base >=4.10 && <5                      , base64                      , base64-bytestring                      , random-bytestring@@ -85,7 +85,7 @@   type:                exitcode-stdio-1.0   hs-source-dirs:      benchmarks   main-is:             Base64Bench.hs-  build-depends:       base >=4.9 && <5+  build-depends:       base >=4.10 && <5                      , base64                      , base64-bytestring                      , bytestring
benchmarks/Base64Bench.hs view
@@ -32,20 +32,28 @@   main :: IO ()-main = defaultMain $ fmap benchN [25,100,1000,10000,100000]+main = defaultMain+    $ fmap (benchN random encode_) sizes+    ++ fmap (benchN (fmap B64.encodeBase64 . random) decode_) sizes+   where-    benchN n = env (random n) $ bgroup (show n) . bgroup_-    bgroup_ e =-      [ bgroup "encode"+    sizes = [25,100,1000,10000,100000]+    benchN f bs n = env (f n) $ bgroup (show n) . bs++    encode_ e =+      [ bgroup "base64 encode"         [ encodeBench @'Mem e         , encodeBench @'Bos e         , encodeBench @'B64 e         ]-      -- , bgroup "base64 decode"-      --   [ decodeBench @'Mem e-      --   , decodeBench @'Bos e-      --   , decodeBench @'B64 e-      --   ]+      ]++    decode_ e =+      [ bgroup "base64 decode"+        [ decodeBench @'Mem e+        , decodeBench @'Bos e+        , decodeBench @'B64 e+        ]       ]  encodeBench :: forall a. Harness a => Base64 a -> Benchmark
src/Data/ByteString/Base64.hs view
@@ -26,23 +26,23 @@  -- | Encode a 'ByteString' in base64 with padding. ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- encodeBase64 :: ByteString -> ByteString-encodeBase64 = encodeB64Padded base64Table+encodeBase64 = encodeBase64_ True base64Table {-# INLINE encodeBase64 #-}  -- | Decode a padded base64-encoded 'ByteString' ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- decodeBase64 :: ByteString -> Either Text ByteString-decodeBase64 = decodeB64 decodeB64Table+decodeBase64 = decodeBase64_ decodeB64Table {-# INLINE decodeBase64 #-}  -- | Encode a 'ByteString' in base64 without padding. ----- Note: in some circumstances, the use of padding ("=") in base-encoded data+-- __Note:__ in some circumstances, the use of padding ("=") in base-encoded data -- is not required or used. This is not one of them. If you are absolutely sure -- the length of your bytestring is divisible by 3, this function will be the same -- as 'encodeBase64' with padding, however, if not, you may see garbage appended to@@ -51,16 +51,16 @@ -- Only call unpadded variants when you can make assumptions about the length of -- your input data. ----- See: RFC-4648 section 3.2+-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> -- encodeBase64Unpadded :: ByteString -> ByteString-encodeBase64Unpadded = encodeB64Unpadded base64Table+encodeBase64Unpadded = encodeBase64_ False base64Table {-# INLINE encodeBase64Unpadded #-}  -- | Decode an unpadded base64-encoded 'ByteString' ----- See: RFC-4648 section 3.2+-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> -- decodeBase64Unpadded :: ByteString -> Either Text ByteString-decodeBase64Unpadded = decodeB64 decodeB64Table+decodeBase64Unpadded = decodeBase64_ decodeB64Table {-# INLINE decodeBase64Unpadded #-}
src/Data/ByteString/Base64/Internal.hs view
@@ -16,11 +16,10 @@ -- module Data.ByteString.Base64.Internal ( -- * Base64 encoding-  encodeB64Padded-, encodeB64Unpadded+  encodeBase64_    -- * Base64 decoding-, decodeB64+, decodeBase64_    -- * Decoding Tables   -- ** Standard@@ -37,6 +36,8 @@ ) where  +import Control.Monad (when)+ import Data.Bits import Data.ByteString (ByteString) import Data.ByteString.Internal@@ -103,65 +104,15 @@   -- -------------------------------------------------------------------------- ----- Unpadded Base64--encodeB64Unpadded :: EncodingTable -> ByteString -> ByteString-encodeB64Unpadded (EncodingTable _ !efp) (PS sfp !soff !slen) =-    unsafeCreate dlen $ \dptr ->-    withForeignPtr sfp $ \sptr ->-    withForeignPtr efp $ \eptr ->-      encodeB64UnpaddedInternal-        eptr-        (plusPtr sptr soff)-        (castPtr dptr)-        (plusPtr sptr (soff + slen))-  where-    !dlen = 4 * ((slen + 2) `div` 3)-{-# INLINE encodeB64Unpadded #-}---- | Unpadded Base64. The implicit assumption is that the input--- data has a length that is a multiple of 3----encodeB64UnpaddedInternal-    :: Ptr Word16-    -> Ptr Word8-    -> Ptr Word16-    -> Ptr Word8-    -> IO ()-encodeB64UnpaddedInternal etable sptr dptr end = go sptr dptr-  where-    w32 :: Word8 -> Word32-    w32 i = fromIntegral i-    {-# INLINE w32 #-}--    go !src !dst-      | src >= end = return ()-      | otherwise = do--        !i <- w32 <$> peek src-        !j <- w32 <$> peek (plusPtr src 1)-        !k <- w32 <$> peek (plusPtr src 2)--        let !w = (shiftL i 16) .|. (shiftL j 8) .|. k--        !x <- peekElemOff etable (fromIntegral (shiftR w 12))-        !y <- peekElemOff etable (fromIntegral (w .&. 0xfff))--        poke dst x-        poke (plusPtr dst 2) y--        go (plusPtr src 3) (plusPtr dst 4)-{-# INLINE encodeB64UnpaddedInternal #-}---- -------------------------------------------------------------------------- ----- Padded Base64+-- Encode Base64 -encodeB64Padded :: EncodingTable -> ByteString -> ByteString-encodeB64Padded (EncodingTable !aptr !efp) (PS !sfp !soff !slen) =+encodeBase64_ :: Bool -> EncodingTable -> ByteString -> ByteString+encodeBase64_ padding (EncodingTable !aptr !efp) (PS !sfp !soff !slen) =     unsafeCreate dlen $ \dptr ->     withForeignPtr sfp $ \sptr ->     withForeignPtr efp $ \eptr ->-      encodeB64PaddedInternal+      encodeBase64_'+        padding         aptr         eptr         (plusPtr sptr soff)@@ -170,16 +121,17 @@   where     dlen :: Int     !dlen = 4 * ((slen + 2) `div` 3)-{-# INLINE encodeB64Padded #-}+{-# INLINE encodeBase64_ #-} -encodeB64PaddedInternal-    :: Ptr Word8+encodeBase64_'+    :: Bool+    -> Ptr Word8     -> Ptr Word16     -> Ptr Word8     -> Ptr Word16     -> Ptr Word8     -> IO ()-encodeB64PaddedInternal (Ptr !alpha) !etable !sptr !dptr !end = go sptr dptr+encodeBase64_' !padded (Ptr !alpha) !etable !sptr !dptr !end = go sptr dptr   where     ix (W8# i) = W8# (indexWord8OffAddr# alpha (word2Int# i))     {-# INLINE ix #-}@@ -237,12 +189,15 @@           --           pokeByteOff dst 1 (ix b')           pokeByteOff dst 2 (ix c')++          when padded (pokeByteOff @Word8 dst 3 0x3d)+         else do           pokeByteOff dst 1 (ix b)-          pokeByteOff @Word8 dst 2 0x3d--        pokeByteOff @Word8 dst 3 0x3d-{-# INLINE encodeB64PaddedInternal #-}+          when padded $ do+            pokeByteOff @Word8 dst 2 0x3d+            pokeByteOff @Word8 dst 3 0x3d+{-# INLINE encodeBase64_' #-}  -- -------------------------------------------------------------------------- -- -- Decoding Base64@@ -291,15 +246,15 @@       ] {-# NOINLINE decodeB64UrlTable #-} -decodeB64 :: ForeignPtr Word8 -> ByteString -> Either Text ByteString-decodeB64 !dtfp (PS !sfp !soff !slen)+decodeBase64_ :: ForeignPtr Word8 -> ByteString -> Either Text ByteString+decodeBase64_ !dtfp (PS !sfp !soff !slen)     | r /= 0 = Left "invalid padding"     | otherwise = unsafeDupablePerformIO $       withForeignPtr dtfp $ \dtable ->         withForeignPtr sfp $ \sptr -> do         dfp <- mallocPlainForeignPtrBytes dlen         withForeignPtr dfp $ \dptr ->-          decodeB64Internal+          decodeBase64_'             dtable             (plusPtr sptr soff)             dptr@@ -308,9 +263,9 @@   where     (!q, !r) = divMod slen 4     !dlen = q * 3-{-# INLINE decodeB64 #-}+{-# INLINE decodeBase64_ #-} -decodeB64Internal+decodeBase64_'     :: Ptr Word8         -- ^ decode lookup table     -> Ptr Word8@@ -322,7 +277,7 @@     -> ForeignPtr Word8         -- ^ dst foreign ptr (for consing bs)     -> IO (Either Text ByteString)-decodeB64Internal !dtable !sptr !dptr !end !dfp = go dptr sptr 0+decodeBase64_' !dtable !sptr !dptr !end !dfp = go dptr sptr 0   where     err = return . Left . T.pack     {-# INLINE err #-}@@ -370,4 +325,4 @@               else do                 poke @Word8 (dst `plusPtr` 2) (fromIntegral w)                 go (dst `plusPtr` 3) (src `plusPtr` 4) (n + 3)-{-# INLINE decodeB64Internal #-}+{-# INLINE decodeBase64_' #-}
src/Data/ByteString/Base64/Lens.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ViewPatterns #-} -- | -- Module       : Data.Text.Encoding.Base64.Lens -- Copyright 	: (c) 2019 Emily Pillmore@@ -6,19 +7,22 @@ -- -- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy> -- Stability	: Experimental--- Portability	: TypeFamilies------ This module contains the 'AsBase64' instance for @Text@, which is--- defined to be the collection of 'Control.Lens.Type.Prism's defining the--- RFC 4648 specification for the Base64 encoding format.+-- Portability	: non-portable ----- In order to expose this file, you must build the package with--- '-foptics' enabled.+-- This module contains 'Control.Lens.Type.Prism's Base64-encoding and+-- decoding 'ByteString' values. -- module Data.ByteString.Base64.Lens-( -- * Classy Prisms-  AsBase64(..)-, AsBase64Unpadded(..)+( -- * Prisms+  _Base64+, _Base64Url+, _Base64Unpadded+, _Base64UrlUnpadded+  -- * Patterns+, pattern Base64+, pattern Base64Url+, pattern Base64Unpadded+, pattern Base64UrlUnpadded ) where  @@ -29,77 +33,97 @@ import qualified Data.ByteString.Base64.URL as B64U  --- | If a particular type @s@ has a base64 representation--- for any of its focii, this class provides the optical interface--- for satisfying the padded base64 spec in RFC 4648----class AsBase64 s where-    type Base64 s-    -- | A prism into a base64-encoded focus of-    -- some type-    ---    -- Examples:-    ---    -- >>> _Base64 @Text # "Sun"-    -- "UV3u"-    --    ---    -- >>> "PDw/Pz8+Pg==" ^? _Base64-    -- Just "<<???>>"-    ---    _Base64 :: Prism' s (Base64 s)--    -- | A prism into the base64url-encoded focus of-    -- some type-    ---    -- Examples:-    ---    -- >>> _Base64Url @Text # "Sun"-    -- "UV3u"-    ---    -- >>> "PDw_Pz8-Pg==" ^? _Base64Url-    -- Just "<<???>>"-    ---    _Base64Url :: Prism' s (Base64 s)+-- -------------------------------------------------------------------------- --+-- Optics --- | If a particular type @a@ has an unpadded base64 representation--- for any of its focii, this class provides the optical interface--- for satisfying the unpadded base64 spec in RFC 4648+-- | A 'Control.Lens.Type.Prism' into the Base64 encoding of a 'ByteString' value ---class AsBase64Unpadded s where-    type Base64Unpadded s-    -- | A prism into the unpadded base64-encoded focus of-    -- some type-    ---    _Base64Unpadded :: Prism' s (Base64Unpadded s)+-- >>> _Base64 # "Sun"+-- "UV3u"+--+-- >>> "UV3u" ^? _Base64+-- Just "Sun"+--+_Base64 :: Prism' ByteString ByteString+_Base64 = prism' B64.encodeBase64 $ \s -> case B64.decodeBase64 s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64 #-} -    -- | A prism into the unpadded base64url-encoded focus of-    -- some type-    ---    _Base64UrlUnpadded :: Prism' s (Base64Unpadded s)+-- | A 'Control.Lens.Type.Prism' into the Base64-url encoding of a 'ByteString' value+--+-- >>> _Base64Url # "Sun"+-- "UV3u"+--+-- >>> "PDw_Pz8-Pg==" ^? _Base64Url+-- Just "<<???>>"+--+_Base64Url :: Prism' ByteString ByteString+_Base64Url = prism' B64U.encodeBase64 $ \s -> case B64U.decodeBase64 s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64Url #-} +-- | A 'Control.Lens.Type.Prism' into the unpadded Base64 encoding of a+-- 'ByteString' value+--+-- Please note that unpadded variants should only be used+-- when assumptions about the data can be made. In particular, if the length of+-- the input is divisible by 3, then this is a safe function to call.+--+-- >>> _Base64Unpadded # "Sun"+-- "UV3u"+--+-- >>> "UV3u" ^? _Base64Unpadded+-- Just "Sun"+--+_Base64Unpadded :: Prism' ByteString ByteString+_Base64Unpadded = prism' B64.encodeBase64Unpadded $ \s -> case B64.decodeBase64Unpadded s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64Unpadded #-} -instance AsBase64 ByteString where-    type Base64 ByteString = ByteString+-- | A 'Control.Lens.Type.Prism' into the Base64-url encoding of a 'ByteString' value+--+-- Please note that unpadded variants should only be used+-- when assumptions about the data can be made. In particular, if the length of+-- the input is divisible by 3, then this is a safe function to call.+--+-- >>> _Base64UrlUnpadded # "<<??>>"+-- "PDw_Pz4-"+--+-- >>> "PDw_Pz4-" ^? _Base64UrlUnpadded+-- Just "<<??>>"+--+_Base64UrlUnpadded :: Prism' ByteString ByteString+_Base64UrlUnpadded = prism' B64U.encodeBase64Unpadded $ \s -> case B64U.decodeBase64Unpadded s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64UrlUnpadded #-} -    _Base64 = prism' B64.encodeBase64 $ \s -> case B64.decodeBase64 s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64 #-}+-- -------------------------------------------------------------------------- --+-- Patterns -    _Base64Url = prism' B64U.encodeBase64 $ \s -> case B64U.decodeBase64 s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64Url #-}+-- | Unidirectional pattern synonym for base64-encoded 'ByteString' values.+--+pattern Base64 :: ByteString -> ByteString+pattern Base64 a <- (preview _Base64 -> Just a) where+    Base64 a = _Base64 # a -instance AsBase64Unpadded ByteString where-    type Base64Unpadded ByteString = ByteString+-- | Unidirectional pattern synonym for base64url-encoded 'ByteString' values.+--+pattern Base64Url :: ByteString -> ByteString+pattern Base64Url a <- (preview _Base64Url -> Just a) where+    Base64Url a = _Base64Url # a -    _Base64Unpadded = prism' B64.encodeBase64 $ \s -> case B64U.decodeBase64 s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64Unpadded #-}+-- | Unidirectional pattern synonym for unpadded base64-encoded 'ByteString' values.+--+pattern Base64Unpadded :: ByteString -> ByteString+pattern Base64Unpadded a <- (preview _Base64Unpadded -> Just a) where+    Base64Unpadded a = _Base64Unpadded # a -    _Base64UrlUnpadded = prism' B64.encodeBase64 $ \s -> case B64U.decodeBase64Unpadded s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64UrlUnpadded #-}+-- | Unidirectional pattern synonym for unpadded base64url-encoded 'ByteString' values.+--+pattern Base64UrlUnpadded :: ByteString -> ByteString+pattern Base64UrlUnpadded a <- (preview _Base64UrlUnpadded -> Just a) where+    Base64UrlUnpadded a = _Base64UrlUnpadded # a
src/Data/ByteString/Base64/URL.hs view
@@ -25,17 +25,17 @@  -- | Encode a 'ByteString' in base64-url with padding. ----- See: RFC-4648 section 5+-- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> -- encodeBase64 :: ByteString -> ByteString-encodeBase64 = encodeB64Padded base64UrlTable+encodeBase64 = encodeBase64_ True base64UrlTable  -- | Decode a padded base64-url encoded 'ByteString' ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- decodeBase64 :: ByteString -> Either Text ByteString-decodeBase64 = decodeB64 decodeB64UrlTable+decodeBase64 = decodeBase64_ decodeB64UrlTable  -- | Encode a 'ByteString' in base64-url without padding. --@@ -48,14 +48,14 @@ -- Only call unpadded variants when you can make assumptions about the length of -- your input data. ----- See: RFC-4648 section 3.2+-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> -- encodeBase64Unpadded :: ByteString -> ByteString-encodeBase64Unpadded = encodeB64Unpadded base64UrlTable+encodeBase64Unpadded = encodeBase64_ False base64UrlTable  -- | Decode an unpadded base64-url encoded 'ByteString' ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- decodeBase64Unpadded :: ByteString -> Either Text ByteString-decodeBase64Unpadded = decodeB64 decodeB64UrlTable+decodeBase64Unpadded = decodeBase64_ decodeB64UrlTable
src/Data/Text/Encoding/Base64.hs view
@@ -26,14 +26,14 @@  -- | Encode 'Text' in base64 with padding. ----- See: RFC-4648 section 5+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- encodeBase64 :: Text -> Text encodeBase64 = T.decodeUtf8 . B64.encodeBase64 . T.encodeUtf8  -- | Decode a padded base64 encoded 'Text' value ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- decodeBase64 :: Text -> Either Text Text decodeBase64 = fmap T.decodeUtf8 . B64.decodeBase64 . T.encodeUtf8@@ -49,7 +49,7 @@ -- Only call unpadded variants when you can make assumptions about the length of -- your input data. ----- See: RFC-4648 section 3.2+-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> -- encodeBase64Unpadded :: Text -> Text encodeBase64Unpadded = T.decodeUtf8@@ -58,7 +58,7 @@  -- | Decode an unpadded base64 encoded 'Text' ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> -- decodeBase64Unpadded :: Text -> Either Text Text decodeBase64Unpadded = fmap T.decodeUtf8
src/Data/Text/Encoding/Base64/Lens.hs view
@@ -1,5 +1,5 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ViewPatterns #-} -- | -- Module       : Data.Text.Encoding.Base64.Lens -- Copyright 	: (c) 2019 Emily Pillmore@@ -7,50 +7,123 @@ -- -- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy> -- Stability	: Experimental--- Portability	: TypeFamilies------ This module contains the 'AsBase64' and 'AsBase64Unpadded' instances--- for 'Text', which defined to be the collection of 'Control.Lens.Type.Prism's defining the--- RFC 4648 specification for the padded and unpadded Base64 encoding format.+-- Portability	: non-portable ----- These typeclasses are re-exported for convenience+-- This module contains 'Control.Lens.Type.Prism's Base64-encoding and+-- decoding 'Text' values. -- module Data.Text.Encoding.Base64.Lens-( AsBase64(..)-, AsBase64Unpadded(..)+( -- * Prisms+  _Base64+, _Base64Url+, _Base64Unpadded+, _Base64UrlUnpadded+  -- * Patterns+, pattern Base64+, pattern Base64Url+, pattern Base64Unpadded+, pattern Base64UrlUnpadded ) where   import Control.Lens  import Data.Text (Text)-import Data.ByteString.Base64.Lens import qualified Data.Text.Encoding.Base64 as B64T import qualified Data.Text.Encoding.Base64.URL as B64TU  -instance AsBase64 Text where-    type Base64 Text = Text+-- -------------------------------------------------------------------------- --+-- Optics -    _Base64 = prism' B64T.encodeBase64 $ \s -> case B64T.decodeBase64 s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64 #-}+-- | A 'Control.Lens.Type.Prism' into the Base64 encoding of a 'Text' value.+--+-- >>> _Base64 # "Sun"+-- "UV3u"+--+-- >>> "UV3u" ^? _Base64+-- Just "Sun"+--+_Base64 :: Prism' Text Text+_Base64 = prism' B64T.encodeBase64 $ \s -> case B64T.decodeBase64 s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64 #-} -    _Base64Url = prism' B64TU.encodeBase64 $ \s -> case B64TU.decodeBase64 s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64Url #-}+-- | A 'Control.Lens.Type.Prism' into the Base64-url encoding of a 'Text' value.+--+-- >>> _Base64Url # "Sun"+-- "UV3u"+--+-- >>> "PDw_Pz8-Pg==" ^? _Base64Url+-- Just "<<???>>"+--+_Base64Url :: Prism' Text Text+_Base64Url = prism' B64TU.encodeBase64 $ \s -> case B64TU.decodeBase64 s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64Url #-} -instance AsBase64Unpadded Text where-    type Base64Unpadded Text = Text+-- | A 'Control.Lens.Type.Prism' into the unpadded Base64 encoding of a+-- 'Text' value.+--+-- Please note that unpadded variants should only be used+-- when assumptions about the data can be made. In particular, if the length of+-- the input is divisible by 3, then this is a safe function to call.+--+-- >>> _Base64Unpadded # "Sun"+-- "UV3u"+--+-- >>> "UV3u" ^? _Base64Unpadded+-- Just "Sun"+--+_Base64Unpadded :: Prism' Text Text+_Base64Unpadded = prism' B64T.encodeBase64Unpadded $ \s -> case B64T.decodeBase64Unpadded s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64Unpadded #-} -    _Base64Unpadded = prism' B64T.encodeBase64 $ \s -> case B64T.decodeBase64 s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64Unpadded #-}+-- | A 'Control.Lens.Type.Prism' into the Base64-url encoding of a 'Text' value.+--+-- Please note that unpadded variants should only be used+-- when assumptions about the data can be made. In particular, if the length of+-- the input is divisible by 3, then this is a safe function to call.+--+-- >>> _Base64UrlUnpadded # "<<??>>"+-- "PDw_Pz4-"+--+-- >>> "PDw_Pz4-" ^? _Base64UrlUnpadded+-- Just "<<??>>"+--+_Base64UrlUnpadded :: Prism' Text Text+_Base64UrlUnpadded = prism' B64TU.encodeBase64Unpadded $ \s -> case B64TU.decodeBase64Unpadded s of+    Left _ -> Nothing+    Right a -> Just a+{-# INLINE _Base64UrlUnpadded #-} -    _Base64UrlUnpadded = prism' B64TU.encodeBase64 $ \s -> case B64TU.decodeBase64Unpadded s of-      Left _ -> Nothing-      Right a -> Just a-    {-# INLINE _Base64UrlUnpadded #-}+-- -------------------------------------------------------------------------- --+-- Patterns++-- | Unidirectional pattern synonym for base64-encoded 'Text' values.+--+pattern Base64 :: Text -> Text+pattern Base64 a <- (preview _Base64 -> Just a) where+    Base64 a = _Base64 # a++-- | Unidirectional pattern synonym for base64url-encoded 'Text' values.+--+pattern Base64Url :: Text -> Text+pattern Base64Url a <- (preview _Base64Url -> Just a) where+    Base64Url a = _Base64Url # a++-- | Unidirectional pattern synonym for unpadded base64-encoded 'Text' values.+--+pattern Base64Unpadded :: Text -> Text+pattern Base64Unpadded a <- (preview _Base64Unpadded -> Just a) where+    Base64Unpadded a = _Base64Unpadded # a++-- | Unidirectional pattern synonym for unpadded base64url-encoded 'Text' values.+--+pattern Base64UrlUnpadded :: Text -> Text+pattern Base64UrlUnpadded a <- (preview _Base64UrlUnpadded -> Just a) where+    Base64UrlUnpadded a = _Base64UrlUnpadded # a
src/Data/Text/Encoding/Base64/URL.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE Trustworthy #-} -- | -- Module       : Data.Text.Encoding.Base64.URL -- Copyright 	: (c) 2019 Emily Pillmore@@ -25,21 +26,21 @@  -- | Encode a 'Text' in base64-url with padding. ----- See: RFC-4648 section 5+-- See: <https://tools.ietf.org/html/rfc4648#section-5 RFC-4648 section 5> -- encodeBase64 :: Text -> Text encodeBase64 = T.decodeUtf8 . B64U.encodeBase64 . T.encodeUtf8  -- | Decode a padded base64-url encoded 'Text' ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- decodeBase64 :: Text -> Either Text Text decodeBase64 = fmap T.decodeUtf8 . B64U.decodeBase64 . T.encodeUtf8  -- | Encode a 'Text' value in base64-url without padding. ----- Note: in some circumstances, the use of padding ("=") in base-encoded data+-- __Note:__ in some circumstances, the use of padding ("=") in base-encoded data -- is not required or used. If you are absolutely sure the length of your -- input data is divisible by 3, this function will be the same as 'encodeBase64' -- with padding. However, if not, you may see garbage appended to output in the@@ -48,7 +49,7 @@ -- Only call unpadded variants when you can make assumptions about the length of -- your input data. ----- See: RFC-4648 section 3.2+-- See: <https://tools.ietf.org/html/rfc4648#section-3.2 RFC-4648 section 3.2> -- encodeBase64Unpadded :: Text -> Text encodeBase64Unpadded = T.decodeUtf8@@ -57,7 +58,7 @@  -- | Decode an unpadded base64-url encoded 'Text' value ----- See: RFC-4648 section 4+-- See: <https://tools.ietf.org/html/rfc4648#section-4 RFC-4648 section 4> -- decodeBase64Unpadded :: Text -> Either Text Text decodeBase64Unpadded = fmap T.decodeUtf8