diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Revision history for base64-lens
 
+## 0.3.1
+
+* Add lazy and short text and bytestring optics
+* Add safe/trustworthy pragmas
+* Migrate to Github CI
+* Update nix derivation
+
 ## 0.3
 
 * Instead of focusing on the `Base64Lenient` `Iso` as a `Lens` (which swaps its focus compared to its sibling `Prism`s),
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,74 +4,3 @@
 [![Hackage](https://img.shields.io/hackage/v/base64-lens.svg)](https://hackage.haskell.org/package/base64-lens)
 
 This package provides optics and convenient pattern synonyms for the [base64](https://hackage.haskell.org/package/base64) library.
-
-### Patterns
-
-The pattern synonyms provided in this library are:
-
-```haskell
-pattern Base64 :: ByteString -> ByteString
-pattern Base64Url :: ByteString -> ByteString
-pattern Base64UrlUnpadded :: ByteString -> ByteString
-pattern Base64Lenient :: ByteString -> ByteString
-pattern Base64UrlLenient :: ByteString -> ByteString
-
--- and 
-
-pattern Base64 :: Text -> Text
-pattern Base64Url :: Text -> Text
-pattern Base64UrlUnpadded :: Text -> Text
-pattern Base64Lenient :: Text -> Text
-pattern Base64UrlLenient :: Text -> Text
-```
-
-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 :: Prism' ByteString ByteString
-_Base64Url :: Prism' ByteString ByteString
-_Base64UrlUnpadded :: Prism' ByteString ByteString
-_Base64Lenient :: Iso' ByteString ByteString
-_Base64UrlLenient :: Iso' ByteString ByteString
-
--- and
-
-_Base64 :: Prism' Text Text
-_Base64Url :: Prism' Text Text
-_Base64UrlUnpadded :: Prism' Text Text
-_Base64Lenient :: Iso' Text Text
-_Base64UrlLenient :: Iso' Text Text
-```
-
-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:
-
-```haskell
-
-data MyStruct = MyStruct
-  { _a :: Int
-  , _b :: Text
-  } deriving Show
-
-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.
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,6 +1,4 @@
-module Main where
-
-import Distribution.Extra.Doctest (defaultMainWithDoctests)
+import Distribution.Simple
 
 main :: IO ()
-main = defaultMainWithDoctests "doctests"
+main = defaultMain
diff --git a/base64-lens.cabal b/base64-lens.cabal
--- a/base64-lens.cabal
+++ b/base64-lens.cabal
@@ -1,62 +1,46 @@
-cabal-version:       1.24
-
-name:                base64-lens
-version:             0.3.0
-synopsis:            Optics for the Base64 library
-description:
-  Prisms and pattern synonyms for the Base64 library
-homepage:            https://github.com/emilypi/base64-lens
-bug-reports:         https://github.com/emilypi/base64-lens/issues
-license:             BSD3
-license-file:        LICENSE
-author:              Emily Pillmore
-maintainer:          emilypi@cohomolo.gy
-copyright:           (c) 2019 Emily Pillmore
-category:            Data
-build-type:          Custom
+cabal-version:      2.0
+name:               base64-lens
+version:            0.3.1
+synopsis:           Optics for the Base64 library
+description:        Prisms and pattern synonyms for the Base64 library
+homepage:           https://github.com/emilypi/base64-lens
+bug-reports:        https://github.com/emilypi/base64-lens/issues
+license:            BSD3
+license-file:       LICENSE
+author:             Emily Pillmore
+maintainer:         Emily Pillmore <emilypi@cohomolo.gy>
+copyright:          (c) 2019-2021 Emily Pillmore
+category:           Data
+build-type:         Simple
 extra-source-files:
   CHANGELOG.md
   README.md
 
-tested-with:         GHC ==8.8.1 || ==8.6.5 || ==8.6.3 || ==8.4.4 || ==8.4.3 || ==8.2.2
+tested-with:
+  GHC ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.4
 
 source-repository head
   type:     git
-  location: https://github.com/emilypi/base64.git
-
-
-custom-setup
-  setup-depends:
-      base           >=4.10 && <5
-    , Cabal
-    , cabal-doctest
-
+  location: https://github.com/emilypi/base64-lens.git
 
 library
-  exposed-modules:     Data.ByteString.Base64.Lens
-                     , Data.Text.Encoding.Base64.Lens
-
-  build-depends:       base       >=4.10 && <5
-                     , base64     >=0.4  && <0.5
-                     , bytestring >=0.10 && <0.11
-                     , lens       >=4.0  && <5
-                     , text       >=1.2  && <1.3
-
-  hs-source-dirs:      src
-  default-language:    Haskell2010
-  ghc-options:         -Wall
-
-
-test-suite doctests
-  default-language:    Haskell2010
-  type:                exitcode-stdio-1.0
-  main-is:             doctests.hs
+  exposed-modules:
+    Data.ByteString.Base64.Lens
+    Data.ByteString.Lazy.Base64.Lens
+    Data.ByteString.Short.Base64.Lens
+    Data.Text.Encoding.Base64.Error.Lens
+    Data.Text.Encoding.Base64.Lens
+    Data.Text.Lazy.Encoding.Base64.Lens
+    Data.Text.Short.Encoding.Base64.Lens
 
-  build-depends:       base            >=4.10  && <5
-                     , base64-lens
-                     , doctest
-                     , lens
+  build-depends:
+      base        >=4.10 && <5
+    , base64      ^>=0.4
+    , bytestring  ^>=0.10
+    , lens        >=4.0  && <5.1
+    , text        ^>=1.2
+    , text-short  ^>=0.1
 
-  hs-source-dirs:      test
-  ghc-options:         -Wall -threaded
-  x-doctest-options:   --fast
+  hs-source-dirs:   src
+  default-language: Haskell2010
+  ghc-options:      -Wall
diff --git a/src/Data/ByteString/Base64/Lens.hs b/src/Data/ByteString/Base64/Lens.hs
--- a/src/Data/ByteString/Base64/Lens.hs
+++ b/src/Data/ByteString/Base64/Lens.hs
@@ -1,8 +1,14 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE ViewPatterns #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
 -- |
--- Module       : Data.Text.Encoding.Base64.Lens
--- Copyright 	: (c) 2019 Emily Pillmore
+-- Module       : Data.ByteString.Base64.Lens
+-- Copyright 	: (c) 2019-2021 Emily Pillmore
 -- License	: BSD-style
 --
 -- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
diff --git a/src/Data/ByteString/Lazy/Base64/Lens.hs b/src/Data/ByteString/Lazy/Base64/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/Lazy/Base64/Lens.hs
@@ -0,0 +1,165 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ViewPatterns #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
+-- |
+-- Module       : Data.ByteString.Lazy.Base64.Lens
+-- Copyright 	: (c) 2019-2021 Emily Pillmore
+-- License	: BSD-style
+--
+-- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
+-- Stability	: Experimental
+-- Portability	: non-portable
+--
+-- This module contains 'Prism''s and 'Iso''s for Base64-encoding and
+-- decoding 'ByteString' values.
+--
+module Data.ByteString.Lazy.Base64.Lens
+( -- * Prisms
+  _Base64
+, _Base64Url
+, _Base64UrlUnpadded
+, _Base64Lenient
+, _Base64UrlLenient
+  -- * Patterns
+, pattern Base64
+, pattern Base64Url
+, pattern Base64UrlUnpadded
+, pattern Base64Lenient
+, pattern Base64UrlLenient
+) where
+
+
+import Control.Lens
+
+import Data.ByteString.Lazy (ByteString)
+import qualified Data.ByteString.Lazy.Base64 as BL64
+import qualified Data.ByteString.Lazy.Base64.URL as BL64U
+
+
+-- $setup
+--
+-- >>> import Control.Lens
+-- >>> import Data.ByteString.Lazy.Base64.Lens
+--
+-- >>> :set -XOverloadedStrings
+-- >>> :set -XTypeApplications
+
+
+-- -------------------------------------------------------------------------- --
+-- Optics
+
+-- | A 'Prism'' into the Base64 encoding of a 'ByteString' value
+--
+-- >>> _Base64 # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^? _Base64
+-- Just "Sun"
+--
+_Base64 :: Prism' ByteString ByteString
+_Base64 = prism' BL64.encodeBase64' $ \s -> case BL64.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64 #-}
+
+-- | A 'Prism'' into the Base64url encoding of a 'ByteString' value
+--
+-- >>> _Base64Url # "Sun"
+-- "U3Vu"
+--
+-- >>> "PDw_Pz8-Pg==" ^? _Base64Url
+-- Just "<<???>>"
+--
+_Base64Url :: Prism' ByteString ByteString
+_Base64Url = prism' BL64U.encodeBase64' $ \s -> case BL64U.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64Url #-}
+
+-- | A 'Prism'' into the Base64url 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' BL64U.encodeBase64Unpadded' $ \s -> case BL64U.decodeBase64Unpadded s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64UrlUnpadded #-}
+
+-- | An 'Iso'' into the Base64 encoding of a 'ByteString' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso'. Please take care!
+--
+-- >>> _Base64Lenient # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^. _Base64Lenient
+-- "Sun"
+--
+_Base64Lenient :: Iso' ByteString ByteString
+_Base64Lenient = iso BL64.decodeBase64Lenient BL64.encodeBase64'
+
+-- | An 'Iso'' into the Base64url encoding of a 'ByteString' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso'. Please take care!
+--
+-- >>> _Base64UrlLenient # "<<??>>"
+-- "PDw_Pz4-"
+--
+-- >>> "PDw_Pz4-" ^. _Base64UrlLenient
+-- "<<??>>"
+--
+_Base64UrlLenient :: Iso' ByteString ByteString
+_Base64UrlLenient = iso BL64U.decodeBase64Lenient BL64U.encodeBase64'
+
+-- -------------------------------------------------------------------------- --
+-- Patterns
+
+-- | Bidirectional pattern synonym for base64-encoded 'ByteString' values.
+--
+pattern Base64 :: ByteString -> ByteString
+pattern Base64 a <- (preview _Base64 -> Just a) where
+    Base64 a = _Base64 # a
+
+-- | Bidirectional pattern synonym for base64url-encoded 'ByteString' values.
+--
+pattern Base64Url :: ByteString -> ByteString
+pattern Base64Url a <- (preview _Base64Url -> Just a) where
+    Base64Url a = _Base64Url # a
+
+-- | Bidirectional pattern synonym for unpadded base64url-encoded 'ByteString' values.
+--
+pattern Base64UrlUnpadded :: ByteString -> ByteString
+pattern Base64UrlUnpadded a <- (preview _Base64UrlUnpadded -> Just a) where
+    Base64UrlUnpadded a = _Base64UrlUnpadded # a
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'ByteString' values
+--
+pattern Base64Lenient :: ByteString -> ByteString
+pattern Base64Lenient a <- (view (from _Base64Lenient) -> a) where
+    Base64Lenient a = view _Base64Lenient a
+{-# COMPLETE Base64Lenient #-}
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'ByteString' values
+--
+pattern Base64UrlLenient :: ByteString -> ByteString
+pattern Base64UrlLenient a <- (view (from _Base64UrlLenient) -> a) where
+    Base64UrlLenient a = view _Base64UrlLenient a
+{-# COMPLETE Base64UrlLenient #-}
diff --git a/src/Data/ByteString/Short/Base64/Lens.hs b/src/Data/ByteString/Short/Base64/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/ByteString/Short/Base64/Lens.hs
@@ -0,0 +1,165 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ViewPatterns #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
+-- |
+-- Module       : Data.ByteString.Short.Base64.Lens
+-- Copyright 	: (c) 2019-2021 Emily Pillmore
+-- License	: BSD-style
+--
+-- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
+-- Stability	: Experimental
+-- Portability	: non-portable
+--
+-- This module contains 'Prism''s and 'Iso''s for Base64-encoding and
+-- decoding 'ShortByteString' values.
+--
+module Data.ByteString.Short.Base64.Lens
+( -- * Prisms
+  _Base64
+, _Base64Url
+, _Base64UrlUnpadded
+, _Base64Lenient
+, _Base64UrlLenient
+  -- * Patterns
+, pattern Base64
+, pattern Base64Url
+, pattern Base64UrlUnpadded
+, pattern Base64Lenient
+, pattern Base64UrlLenient
+) where
+
+
+import Control.Lens
+
+import Data.ByteString.Short (ShortByteString)
+import qualified Data.ByteString.Short.Base64 as BS64
+import qualified Data.ByteString.Short.Base64.URL as BS64U
+
+
+-- $setup
+--
+-- >>> import Control.Lens
+-- >>> import Data.ByteString.Short.Base64.Lens
+--
+-- >>> :set -XOverloadedStrings
+-- >>> :set -XTypeApplications
+
+
+-- -------------------------------------------------------------------------- --
+-- Optics
+
+-- | A 'Prism'' into the Base64 encoding of a 'ShortByteString' value
+--
+-- >>> _Base64 # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^? _Base64
+-- Just "Sun"
+--
+_Base64 :: Prism' ShortByteString ShortByteString
+_Base64 = prism' BS64.encodeBase64' $ \s -> case BS64.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64 #-}
+
+-- | A 'Prism'' into the Base64url encoding of a 'ShortByteString' value
+--
+-- >>> _Base64Url # "Sun"
+-- "U3Vu"
+--
+-- >>> "PDw_Pz8-Pg==" ^? _Base64Url
+-- Just "<<???>>"
+--
+_Base64Url :: Prism' ShortByteString ShortByteString
+_Base64Url = prism' BS64U.encodeBase64' $ \s -> case BS64U.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64Url #-}
+
+-- | A 'Prism'' into the Base64url encoding of a 'ShortByteString' 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' ShortByteString ShortByteString
+_Base64UrlUnpadded = prism' BS64U.encodeBase64Unpadded' $ \s -> case BS64U.decodeBase64Unpadded s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64UrlUnpadded #-}
+
+-- | An 'Iso'' into the Base64 encoding of a 'ShortByteString' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso'. Please take care!
+--
+-- >>> _Base64Lenient # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^. _Base64Lenient
+-- "Sun"
+--
+_Base64Lenient :: Iso' ShortByteString ShortByteString
+_Base64Lenient = iso BS64.decodeBase64Lenient BS64.encodeBase64'
+
+-- | An 'Iso'' into the Base64url encoding of a 'ShortByteString' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso'. Please take care!
+--
+-- >>> _Base64UrlLenient # "<<??>>"
+-- "PDw_Pz4-"
+--
+-- >>> "PDw_Pz4-" ^. _Base64UrlLenient
+-- "<<??>>"
+--
+_Base64UrlLenient :: Iso' ShortByteString ShortByteString
+_Base64UrlLenient = iso BS64U.decodeBase64Lenient BS64U.encodeBase64'
+
+-- -------------------------------------------------------------------------- --
+-- Patterns
+
+-- | Bidirectional pattern synonym for base64-encoded 'ShortByteString' values.
+--
+pattern Base64 :: ShortByteString -> ShortByteString
+pattern Base64 a <- (preview _Base64 -> Just a) where
+    Base64 a = _Base64 # a
+
+-- | Bidirectional pattern synonym for base64url-encoded 'ShortByteString' values.
+--
+pattern Base64Url :: ShortByteString -> ShortByteString
+pattern Base64Url a <- (preview _Base64Url -> Just a) where
+    Base64Url a = _Base64Url # a
+
+-- | Bidirectional pattern synonym for unpadded base64url-encoded 'ShortByteString' values.
+--
+pattern Base64UrlUnpadded :: ShortByteString -> ShortByteString
+pattern Base64UrlUnpadded a <- (preview _Base64UrlUnpadded -> Just a) where
+    Base64UrlUnpadded a = _Base64UrlUnpadded # a
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'ShortByteString' values
+--
+pattern Base64Lenient :: ShortByteString -> ShortByteString
+pattern Base64Lenient a <- (view (from _Base64Lenient) -> a) where
+    Base64Lenient a = view _Base64Lenient a
+{-# COMPLETE Base64Lenient #-}
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'ShortByteString' values
+--
+pattern Base64UrlLenient :: ShortByteString -> ShortByteString
+pattern Base64UrlLenient a <- (view (from _Base64UrlLenient) -> a) where
+    Base64UrlLenient a = view _Base64UrlLenient a
+{-# COMPLETE Base64UrlLenient #-}
diff --git a/src/Data/Text/Encoding/Base64/Error/Lens.hs b/src/Data/Text/Encoding/Base64/Error/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Text/Encoding/Base64/Error/Lens.hs
@@ -0,0 +1,45 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE LambdaCase #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
+-- |
+-- Module       : Data.Text.Encoding.Base64.Error.Lens
+-- Copyright    : (c) 2019-2021 Emily Pillmore
+-- License      : BSD-style
+--
+-- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>
+-- Stability    : Experimental
+-- Portability  : non-portable
+--
+-- This module contains 'Prism''s for the `Data.Text.Encoding.Base64.Error.Base64Error`
+-- datatype.
+--
+module Data.Text.Encoding.Base64.Error.Lens
+( -- * Prisms
+  _DecodeError
+, _ConversionError
+) where
+
+
+import Control.Lens
+
+import Data.Text (Text)
+import Data.Text.Encoding.Base64.Error (Base64Error(..))
+
+
+-- | A 'Prism'' into the 'DecodeError' case of a 'Base64Error'
+--
+_DecodeError :: Prism' (Base64Error err) Text
+_DecodeError = prism' DecodeError $ \case
+    DecodeError t -> Just t
+    ConversionError{} -> Nothing
+
+-- | A 'Prism'' into the 'ConversionError' case of a 'Base64Error'
+--
+_ConversionError :: Prism' (Base64Error err) err
+_ConversionError = prism' ConversionError $ \case
+    ConversionError err -> Just err
+    DecodeError{} -> Nothing
diff --git a/src/Data/Text/Encoding/Base64/Lens.hs b/src/Data/Text/Encoding/Base64/Lens.hs
--- a/src/Data/Text/Encoding/Base64/Lens.hs
+++ b/src/Data/Text/Encoding/Base64/Lens.hs
@@ -1,8 +1,14 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE PatternSynonyms #-}
 {-# LANGUAGE ViewPatterns #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
 -- |
 -- Module       : Data.Text.Encoding.Base64.Lens
--- Copyright 	: (c) 2019 Emily Pillmore
+-- Copyright 	: (c) 2019-2021 Emily Pillmore
 -- License	: BSD-style
 --
 -- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
diff --git a/src/Data/Text/Lazy/Encoding/Base64/Lens.hs b/src/Data/Text/Lazy/Encoding/Base64/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Text/Lazy/Encoding/Base64/Lens.hs
@@ -0,0 +1,163 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ViewPatterns #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
+-- |
+-- Module       : Data.Text.Lazy.Encoding.Base64.Lens
+-- Copyright 	: (c) 2019-2021 Emily Pillmore
+-- License	: BSD-style
+--
+-- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
+-- Stability	: Experimental
+-- Portability	: non-portable
+--
+-- This module contains 'Prism's and 'Iso''s Base64-encoding and
+-- decoding 'Text' values.
+--
+module Data.Text.Lazy.Encoding.Base64.Lens
+( -- * Prisms
+  _Base64
+, _Base64Url
+, _Base64UrlUnpadded
+, _Base64Lenient
+, _Base64UrlLenient
+  -- * Patterns
+, pattern Base64
+, pattern Base64Url
+, pattern Base64UrlUnpadded
+, pattern Base64Lenient
+, pattern Base64UrlLenient
+) where
+
+import Control.Lens
+
+import Data.Text.Lazy (Text)
+import qualified Data.Text.Lazy.Encoding.Base64 as B64TL
+import qualified Data.Text.Lazy.Encoding.Base64.URL as B64TLU
+
+
+-- $setup
+--
+-- >>> import Control.Lens
+-- >>> import Data.Text.Lazy.Encoding.Base64.Lens
+--
+-- >>> :set -XOverloadedStrings
+-- >>> :set -XTypeApplications
+
+-- -------------------------------------------------------------------------- --
+-- Optics
+
+-- | A 'Prism' into the Base64 encoding of a 'Text' value.
+--
+-- >>> _Base64 # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^? _Base64
+-- Just "Sun"
+--
+_Base64 :: Prism' Text Text
+_Base64 = prism' B64TL.encodeBase64 $ \s -> case B64TL.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64 #-}
+
+-- | A 'Prism' into the Base64-url encoding of a 'Text' value.
+--
+-- >>> _Base64Url # "Sun"
+-- "U3Vu"
+--
+-- >>> "PDw_Pz8-Pg==" ^? _Base64Url
+-- Just "<<???>>"
+--
+_Base64Url :: Prism' Text Text
+_Base64Url = prism' B64TLU.encodeBase64 $ \s -> case B64TLU.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64Url #-}
+
+-- | A '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' B64TLU.encodeBase64Unpadded $ \s -> case B64TLU.decodeBase64Unpadded s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64UrlUnpadded #-}
+
+-- | An 'Iso'' into the Base64 encoding of a 'Text' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso' in general. Please take care!
+--
+-- >>> _Base64Lenient # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^. _Base64Lenient
+-- "Sun"
+--
+_Base64Lenient :: Iso' Text Text
+_Base64Lenient = iso B64TL.decodeBase64Lenient B64TL.encodeBase64
+
+-- | An 'Iso'' into the Base64url encoding of a 'Text' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso' in general. Please take care!
+--
+-- >>> _Base64UrlLenient # "<<??>>"
+-- "PDw_Pz4-"
+--
+-- >>> "PDw_Pz4-" ^. _Base64UrlLenient
+-- "<<??>>"
+--
+_Base64UrlLenient :: Iso' Text Text
+_Base64UrlLenient = iso B64TLU.decodeBase64Lenient B64TLU.encodeBase64
+
+-- -------------------------------------------------------------------------- --
+-- 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 base64url-encoded 'Text' values.
+--
+pattern Base64UrlUnpadded :: Text -> Text
+pattern Base64UrlUnpadded a <- (preview _Base64UrlUnpadded -> Just a) where
+    Base64UrlUnpadded a = _Base64UrlUnpadded # a
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'Text' values
+--
+pattern Base64Lenient :: Text -> Text
+pattern Base64Lenient a <- (view (from _Base64Lenient) -> a) where
+    Base64Lenient a = view _Base64Lenient a
+{-# COMPLETE Base64Lenient #-}
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'Text' values
+--
+pattern Base64UrlLenient :: Text -> Text
+pattern Base64UrlLenient a <- (view (from _Base64UrlLenient) -> a) where
+    Base64UrlLenient a = view _Base64UrlLenient a
+{-# COMPLETE Base64UrlLenient #-}
diff --git a/src/Data/Text/Short/Encoding/Base64/Lens.hs b/src/Data/Text/Short/Encoding/Base64/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Text/Short/Encoding/Base64/Lens.hs
@@ -0,0 +1,163 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ViewPatterns #-}
+#if MIN_VERSION_lens(5,0,0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
+-- |
+-- Module       : Data.Text.Short.Encoding.Base64.Lens
+-- Copyright 	: (c) 2019-2021 Emily Pillmore
+-- License	: BSD-style
+--
+-- Maintainer	: Emily Pillmore <emilypi@cohomolo.gy>
+-- Stability	: Experimental
+-- Portability	: non-portable
+--
+-- This module contains 'Prism's and 'Iso''s Base64-encoding and
+-- decoding 'ShortText' values.
+--
+module Data.Text.Short.Encoding.Base64.Lens
+( -- * Prisms
+  _Base64
+, _Base64Url
+, _Base64UrlUnpadded
+, _Base64Lenient
+, _Base64UrlLenient
+  -- * Patterns
+, pattern Base64
+, pattern Base64Url
+, pattern Base64UrlUnpadded
+, pattern Base64Lenient
+, pattern Base64UrlLenient
+) where
+
+import Control.Lens
+
+import Data.Text.Short (ShortText)
+import qualified Data.Text.Short.Encoding.Base64 as TS64
+import qualified Data.Text.Short.Encoding.Base64.URL as TS64U
+
+
+-- $setup
+--
+-- >>> import Control.Lens
+-- >>> import Data.Text.Short.Encoding.Base64.Lens
+--
+-- >>> :set -XOverloadedStrings
+-- >>> :set -XTypeApplications
+
+-- -------------------------------------------------------------------------- --
+-- Optics
+
+-- | A 'Prism' into the Base64 encoding of a 'ShortText' value.
+--
+-- >>> _Base64 # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^? _Base64
+-- Just "Sun"
+--
+_Base64 :: Prism' ShortText ShortText
+_Base64 = prism' TS64.encodeBase64 $ \s -> case TS64.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64 #-}
+
+-- | A 'Prism' into the Base64-url encoding of a 'ShortText' value.
+--
+-- >>> _Base64Url # "Sun"
+-- "U3Vu"
+--
+-- >>> "PDw_Pz8-Pg==" ^? _Base64Url
+-- Just "<<???>>"
+--
+_Base64Url :: Prism' ShortText ShortText
+_Base64Url = prism' TS64U.encodeBase64 $ \s -> case TS64U.decodeBase64 s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64Url #-}
+
+-- | A 'Prism' into the Base64-url encoding of a 'ShortText' 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' ShortText ShortText
+_Base64UrlUnpadded = prism' TS64U.encodeBase64Unpadded $ \s -> case TS64U.decodeBase64Unpadded s of
+    Left _ -> Nothing
+    Right a -> Just a
+{-# INLINE _Base64UrlUnpadded #-}
+
+-- | An 'Iso'' into the Base64 encoding of a 'ShortText' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso' in general. Please take care!
+--
+-- >>> _Base64Lenient # "Sun"
+-- "U3Vu"
+--
+-- >>> "U3Vu" ^. _Base64Lenient
+-- "Sun"
+--
+_Base64Lenient :: Iso' ShortText ShortText
+_Base64Lenient = iso TS64.decodeBase64Lenient TS64.encodeBase64
+
+-- | An 'Iso'' into the Base64url encoding of a 'ShortText' value
+-- using lenient decoding.
+--
+--
+-- _Note:_ This is not a lawful 'Iso' in general. Please take care!
+--
+-- >>> _Base64UrlLenient # "<<??>>"
+-- "PDw_Pz4-"
+--
+-- >>> "PDw_Pz4-" ^. _Base64UrlLenient
+-- "<<??>>"
+--
+_Base64UrlLenient :: Iso' ShortText ShortText
+_Base64UrlLenient = iso TS64U.decodeBase64Lenient TS64U.encodeBase64
+
+-- -------------------------------------------------------------------------- --
+-- Patterns
+
+-- | Unidirectional pattern synonym for base64-encoded 'ShortText' values.
+--
+pattern Base64 :: ShortText -> ShortText
+pattern Base64 a <- (preview _Base64 -> Just a) where
+    Base64 a = _Base64 # a
+
+-- | Unidirectional pattern synonym for base64url-encoded 'ShortText' values.
+--
+pattern Base64Url :: ShortText -> ShortText
+pattern Base64Url a <- (preview _Base64Url -> Just a) where
+    Base64Url a = _Base64Url # a
+
+-- | Unidirectional pattern synonym for unpadded base64url-encoded 'ShortText' values.
+--
+pattern Base64UrlUnpadded :: ShortText -> ShortText
+pattern Base64UrlUnpadded a <- (preview _Base64UrlUnpadded -> Just a) where
+    Base64UrlUnpadded a = _Base64UrlUnpadded # a
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'ShortText' values
+--
+pattern Base64Lenient :: ShortText -> ShortText
+pattern Base64Lenient a <- (view (from _Base64Lenient) -> a) where
+    Base64Lenient a = view _Base64Lenient a
+{-# COMPLETE Base64Lenient #-}
+
+-- | Bidirectional pattern synonym for leniently Base64-encoded 'ShortText' values
+--
+pattern Base64UrlLenient :: ShortText -> ShortText
+pattern Base64UrlLenient a <- (view (from _Base64UrlLenient) -> a) where
+    Base64UrlLenient a = view _Base64UrlLenient a
+{-# COMPLETE Base64UrlLenient #-}
diff --git a/test/doctests.hs b/test/doctests.hs
deleted file mode 100644
--- a/test/doctests.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import Build_doctests (flags, pkgs, module_sources)
-import Test.DocTest (doctest)
-
-main :: IO ()
-main = doctest $ flags ++ pkgs ++ module_sources
