    {-# LANGUAGE CPP #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    #ifdef TRUSTWORTHY
    {-# LANGUAGE Trustworthy #-}
    #endif
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Control.Lens.Internal.Iso
    -- Copyright   :  (C) 2012-2016 Edward Kmett
    -- License     :  BSD-style (see the file LICENSE)
    -- Maintainer  :  Edward Kmett <ekmett@gmail.com>
    -- Stability   :  experimental
    -- Portability :  non-portable
    --
    ----------------------------------------------------------------------------
    module Control.Lens.Internal.Iso
      ( Exchange(..)
      , Reversing(..)
      ) where

    import Data.Profunctor
    import Data.Profunctor.Unsafe

    import qualified Data.ByteString       as StrictB
    import qualified Data.ByteString.Lazy  as LazyB
    import Data.Coerce
    import qualified Data.List.NonEmpty    as NonEmpty
    import qualified Data.Text             as StrictT
    import qualified Data.Text.Lazy        as LazyT
    import qualified Data.Vector           as Vector
    import qualified Data.Vector.Primitive as Prim
    import Data.Vector.Primitive (Prim)
    import qualified Data.Vector.Storable  as Storable
    import qualified Data.Vector.Unboxed   as Unbox
    import Data.Vector.Unboxed (Unbox)
    import qualified Data.Sequence         as Seq
    import Data.Sequence (Seq)
    import Foreign.Storable (Storable)

    ------------------------------------------------------------------------------
    -- Isomorphism: Exchange
    ------------------------------------------------------------------------------

    -- | This is used internally by the 'Control.Lens.Iso.Iso' code to provide
    -- efficient access to the two functions that make up an isomorphism.
    data Exchange a b s t = Exchange (s -> a) (b -> t)

    instance Functor (Exchange a b s) where
      fmap :: forall a b. (a -> b) -> Exchange a b s a -> Exchange a b s b
    fmap a -> b
    f (Exchange s -> a
    sa b -> a
    bt) = (s -> a) -> (b -> b) -> Exchange a b s b
    forall a b s t. (s -> a) -> (b -> t) -> Exchange a b s t
    Exchange s -> a
    sa (a -> b
    f (a -> b) -> (b -> a) -> b -> b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . b -> a
    bt)
      {-# INLINE fmap #-}

    instance Profunctor (Exchange a b) where
      dimap :: forall a b c d.
    (a -> b) -> (c -> d) -> Exchange a b b c -> Exchange a b a d
    dimap a -> b
    f c -> d
    g (Exchange b -> a
    sa b -> c
    bt) = (a -> a) -> (b -> d) -> Exchange a b a d
    forall a b s t. (s -> a) -> (b -> t) -> Exchange a b s t
    Exchange (b -> a
    sa (b -> a) -> (a -> b) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> b
    f) (c -> d
    g (c -> d) -> (b -> c) -> b -> d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . b -> c
    bt)
      {-# INLINE dimap #-}
      lmap :: forall a b c. (a -> b) -> Exchange a b b c -> Exchange a b a c
    lmap a -> b
    f (Exchange b -> a
    sa b -> c
    bt) = (a -> a) -> (b -> c) -> Exchange a b a c
    forall a b s t. (s -> a) -> (b -> t) -> Exchange a b s t
    Exchange (b -> a
    sa (b -> a) -> (a -> b) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> b
    f) b -> c
    bt
      {-# INLINE lmap #-}
      rmap :: forall b c a. (b -> c) -> Exchange a b a b -> Exchange a b a c
    rmap b -> c
    f (Exchange a -> a
    sa b -> b
    bt) = (a -> a) -> (b -> c) -> Exchange a b a c
    forall a b s t. (s -> a) -> (b -> t) -> Exchange a b s t
    Exchange a -> a
    sa (b -> c
    f (b -> c) -> (b -> b) -> b -> c
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . b -> b
    bt)
      {-# INLINE rmap #-}
      #. :: forall a b c (q :: * -> * -> *).
    Coercible c b =>
    q b c -> Exchange a b a b -> Exchange a b a c
    (#.) q b c
    _ = Exchange a b a b -> Exchange a b a c
    forall a b. Coercible a b => a -> b
    coerce
      {-# INLINE (#.) #-}
      .# :: forall a b c (q :: * -> * -> *).
    Coercible b a =>
    Exchange a b b c -> q a b -> Exchange a b a c
    (.#) Exchange a b b c
    p q a b
    _ = Exchange a b b c -> Exchange a b a c
    forall a b. Coercible a b => a -> b
    coerce Exchange a b b c
    p

    ------------------------------------------------------------------------------
    -- Reversible
    ------------------------------------------------------------------------------

    -- | This class provides a generalized notion of list reversal extended to other containers.
    class Reversing t where
      reversing :: t -> t

    instance Reversing [a] where
      reversing :: [a] -> [a]
    reversing = [a] -> [a]
    forall a. [a] -> [a]
    Prelude.reverse

    instance Reversing (NonEmpty.NonEmpty a) where
      reversing :: NonEmpty a -> NonEmpty a
    reversing = NonEmpty a -> NonEmpty a
    forall a. NonEmpty a -> NonEmpty a
    NonEmpty.reverse

    instance Reversing StrictB.ByteString where
      reversing :: ByteString -> ByteString
    reversing = ByteString -> ByteString
    StrictB.reverse

    instance Reversing LazyB.ByteString where
      reversing :: ByteString -> ByteString
    reversing = ByteString -> ByteString
    LazyB.reverse

    instance Reversing StrictT.Text where
      reversing :: Text -> Text
    reversing = Text -> Text
    StrictT.reverse

    instance Reversing LazyT.Text where
      reversing :: Text -> Text
    reversing = Text -> Text
    LazyT.reverse

    instance Reversing (Vector.Vector a) where
      reversing :: Vector a -> Vector a
    reversing = Vector a -> Vector a
    forall a. Vector a -> Vector a
    Vector.reverse

    instance Reversing (Seq a) where
      reversing :: Seq a -> Seq a
    reversing = Seq a -> Seq a
    forall a. Seq a -> Seq a
    Seq.reverse

    instance Prim a => Reversing (Prim.Vector a) where
      reversing :: Vector a -> Vector a
    reversing = Vector a -> Vector a
    forall a. Prim a => Vector a -> Vector a
    Prim.reverse

    instance Unbox a => Reversing (Unbox.Vector a) where
      reversing :: Vector a -> Vector a
    reversing = Vector a -> Vector a
    forall a. Unbox a => Vector a -> Vector a
    Unbox.reverse

    instance Storable a => Reversing (Storable.Vector a) where
      reversing :: Vector a -> Vector a
    reversing = Vector a -> Vector a
    forall a. Storable a => Vector a -> Vector a
    Storable.reverse