{-# LANGUAGE AllowAmbiguousTypes    #-}
{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs                  #-}
{-# LANGUAGE LambdaCase             #-}
{-# LANGUAGE RankNTypes             #-}
{-# LANGUAGE ScopedTypeVariables    #-}
{-# LANGUAGE TypeApplications       #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeInType             #-}
{-# LANGUAGE TypeOperators          #-}
{-# LANGUAGE UndecidableInstances   #-}

-- |
-- Module      : Data.Mutable.Parts
-- Copyright   : (c) Justin Le 2020
-- License     : BSD3
--
-- Maintainer  : justin@jle.im
-- Stability   : experimental
-- Portability : non-portable
--
-- Tools for working with individual components of piecewise-mutable
-- values.
--
-- If "Data.Mutable.Branches" is for sum types, then "Data.Mutable.Parts"
-- is for sum types.
--
-- See <https://mutable.jle.im/05-mutable-parts.html> for an introduction
-- to this module.
--
module Data.Mutable.Parts (
    MutPart(..)
  , withPart
  , freezePart, copyPart
  , movePartInto, movePartOver, movePartWithin
  , clonePart, unsafeFreezePart
  , modifyPart, modifyPart'
  , updatePart, updatePart'
  , modifyPartM, modifyPartM'
  , updatePartM, updatePartM'
  -- * Built-in 'MutPart'
  , compMP
  , idMP
  , mutFst, mutSnd
  -- ** Field
  , FieldMut(..), withField, mutField, Label(..)
  -- ** Position
  , PosMut(..), withPos, mutPos
  -- ** HList
  , TupleMut(..), withTuple
  -- ** Other
  , hkdMutParts, HKDMutParts
  , mutRec
  , coerceRef, withCoerceRef
  , MapRef
  ) where

import           Data.Coerce
import           Data.Generics.Product.Internal.HList
import           Data.Kind
import           Data.Mutable.Class
import           Data.Mutable.Instances
import           Data.Vinyl hiding                        (HList)
import           Data.Vinyl.Functor
import           GHC.Generics
import           GHC.TypeLits
import qualified Control.Category                         as C
import qualified Data.GenericLens.Internal                as GL
import qualified Data.Generics.Internal.Profunctor.Lens   as GLP
import qualified Data.Generics.Product.Fields             as GL
import qualified Data.Generics.Product.Internal.GLens     as GL
import qualified Data.Generics.Product.Internal.Positions as GL
import qualified Data.Generics.Product.Positions          as GL
import qualified Data.Vinyl.TypeLevel                     as V
import qualified Data.Vinyl.XRec                          as X


-- | A @'MutPart' m s a@ is a way to "zoom into" an @a@, as a part of
-- a mutable reference on @s@.  This allows you to only modify a single
-- @a@ part of the @s@, without touching the rest.  It's spiritually
-- similar to a @Lens' s a@.
--
-- If 'Data.Mutable.Branches.MutBranch' is for sum types, then 'MutPart' is
-- for product types.
--
-- See <https://mutable.jle.im/05-mutable-parts.html> for an introduction
-- to this type.
--
-- An example that is commonly found in the ecosystem is something like
-- (flipped) @write :: Int -> 'Data.Vector.MVector' s a -> a -> m ()@ from
-- "Data.Vector.Mutable" --- @write 3 :: 'Data.Vector.MVector' s a -> a ->
-- m ()@, for instance, lets you modify a specific part of the vector
-- without touching the rest.
--
-- You would /use/ a 'MutPart' using 'freezePart', 'copyPart',
-- 'modifyPart', etc.
--
-- For non-composite types, there won't really be any meaningful values.
-- However, we have them for many composite types.  For example, for
-- tuples:
--
-- @
-- 'mutFst' :: 'MutPart' m (a, b) a
-- 'mutSnd' :: MutPart m (a, b) b
-- @
--
-- @
-- ghci> r <- 'thawRef' (2, 4)
-- ghci> 'copyPart' mutFst r 100
-- ghci> 'freezeRef' r
-- (100, 4)
-- @
--
-- If you are using 'GRef' as an automatically-defined mutable reference,
-- then the easiest way to create these for your mutable types are with
-- 'fieldMut' and 'posMut'.
--
-- If you are using the "Higher-kinded data" pattern, then there's an easy
-- way to generate a 'MutPart' for every single field, if you have
-- a product type --- see 'hkdMutParts' for more information.
newtype MutPart m s a = MutPart { MutPart m s a -> Ref m s -> Ref m a
getMutPart :: Ref m s -> Ref m a }

-- | Compose two 'MutPart's one after the other.
--
-- Note this is also available (albeit flipped in arguments) through the
-- 'C.Category' instance.
compMP :: MutPart m a b -> MutPart m b c -> MutPart m a c
compMP :: MutPart m a b -> MutPart m b c -> MutPart m a c
compMP (MutPart f :: Ref m a -> Ref m b
f) (MutPart g :: Ref m b -> Ref m c
g) = (Ref m a -> Ref m c) -> MutPart m a c
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart (Ref m b -> Ref m c
g (Ref m b -> Ref m c) -> (Ref m a -> Ref m b) -> Ref m a -> Ref m c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ref m a -> Ref m b
f)
infixr 9 `compMP`

-- | The identity 'MutPart': simply focus into the same type itself.
--
-- Note this is also available through the 'C.Category' instance.
idMP :: MutPart m a a
idMP :: MutPart m a a
idMP = (Ref m a -> Ref m a) -> MutPart m a a
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart Ref m a -> Ref m a
forall a. a -> a
id

instance C.Category (MutPart m) where
    id :: MutPart m a a
id = MutPart m a a
forall (m :: * -> *) a. MutPart m a a
idMP
    . :: MutPart m b c -> MutPart m a b -> MutPart m a c
(.) = (MutPart m a b -> MutPart m b c -> MutPart m a c)
-> MutPart m b c -> MutPart m a b -> MutPart m a c
forall a b c. (a -> b -> c) -> b -> a -> c
flip MutPart m a b -> MutPart m b c -> MutPart m a c
forall (m :: * -> *) a b c.
MutPart m a b -> MutPart m b c -> MutPart m a c
compMP

instance X.IsoHKD (MutPart m s) a

-- | 'MutPart' into the first field of a tuple reference.
mutFst :: MutPart m (a, b) a
mutFst :: MutPart m (a, b) a
mutFst = (Ref m (a, b) -> Ref m a) -> MutPart m (a, b) a
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart Ref m (a, b) -> Ref m a
forall a b. (a, b) -> a
fst

-- | 'MutPart' into the second field of a tuple reference.
mutSnd :: MutPart m (a, b) b
mutSnd :: MutPart m (a, b) b
mutSnd = (Ref m (a, b) -> Ref m b) -> MutPart m (a, b) b
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart Ref m (a, b) -> Ref m b
forall a b. (a, b) -> b
snd

-- | Using a 'MutPart', perform a function on a @'Ref' m s@ as if you had
-- a @'Ref' m a@.
withPart
    :: MutPart m s a        -- ^ How to zoom into an @a@ from an @s@
    -> Ref m s              -- ^ The larger reference of @s@
    -> (Ref m a -> m r)     -- ^ What do do with the smaller sub-reference of @a@
    -> m r
withPart :: MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r
withPart mp :: MutPart m s a
mp x :: Ref m s
x f :: Ref m a -> m r
f = Ref m a -> m r
f (MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp Ref m s
x)

-- | With a 'MutPart', read out a specific part of a 'Ref'.
freezePart :: Mutable m a => MutPart m s a -> Ref m s -> m a
freezePart :: MutPart m s a -> Ref m s -> m a
freezePart mp :: MutPart m s a
mp = Ref m a -> m a
forall (m :: * -> *) a. Mutable m a => Ref m a -> m a
freezeRef (Ref m a -> m a) -> (Ref m s -> Ref m a) -> Ref m s -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | With a 'MutPart', overwrite into a specific part of a 'Ref'.
copyPart :: Mutable m a => MutPart m s a -> Ref m s -> a -> m ()
copyPart :: MutPart m s a -> Ref m s -> a -> m ()
copyPart mp :: MutPart m s a
mp = Ref m a -> a -> m ()
forall (m :: * -> *) a. Mutable m a => Ref m a -> a -> m ()
copyRef (Ref m a -> a -> m ())
-> (Ref m s -> Ref m a) -> Ref m s -> a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | With a 'MutPart', copy a 'Ref' containing a subvalue into a specific
-- part of a larger 'Ref'.
--
-- @
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
--   deriving Generic
--
-- instance Mutable m MyType where
--     type Ref m MyType = GRef m MyType
-- @
--
-- @
-- ghci> x <- thawRef $ MyType 3 4.5
-- ghci> y <- thawRef $ 100
-- ghci> movePartInto (fieldMut #mtInt) x y
-- ghci> freezeRef x
-- MyType 100 4.5
-- @
movePartInto
    :: Mutable m a
    => MutPart m s a
    -> Ref m s          -- ^ bigger type (destination)
    -> Ref m a          -- ^ smaller type (source)
    -> m ()
movePartInto :: MutPart m s a -> Ref m s -> Ref m a -> m ()
movePartInto mp :: MutPart m s a
mp = Ref m a -> Ref m a -> m ()
forall (m :: * -> *) a. Mutable m a => Ref m a -> Ref m a -> m ()
moveRef (Ref m a -> Ref m a -> m ())
-> (Ref m s -> Ref m a) -> Ref m s -> Ref m a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | With a 'MutPart', copy a specific part of a larger 'Ref' into a 'Ref'
-- of the smaller subvalue value.
--
-- @
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
--   deriving Generic
--
-- instance Mutable m MyType where
--     type Ref m MyType = GRef m MyType
-- @
--
-- @
-- ghci> x <- thawRef $ MyType 3 4.5
-- ghci> y <- thawRef $ 100
-- ghci> movePartOver (fieldMut #mtInt) y x
-- ghci> freezeRef y
-- 3
-- @
movePartOver
    :: Mutable m a
    => MutPart m s a
    -> Ref m a          -- ^ smaller type (destination)
    -> Ref m s          -- ^ bigger type (source)
    -> m ()
movePartOver :: MutPart m s a -> Ref m a -> Ref m s -> m ()
movePartOver mp :: MutPart m s a
mp r :: Ref m a
r = Ref m a -> Ref m a -> m ()
forall (m :: * -> *) a. Mutable m a => Ref m a -> Ref m a -> m ()
moveRef Ref m a
r (Ref m a -> m ()) -> (Ref m s -> Ref m a) -> Ref m s -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | With a 'MutPart', copy a specific part of a large 'Ref' into that
-- same part in another large 'Ref'.
--
-- @
-- data MyType = MT { mtInt :: Int, mtDouble :: Double }
--   deriving Generic
--
-- instance Mutable m MyType where
--     type Ref m MyType = GRef m MyType
-- @
--
-- @
-- ghci> x <- thawRef $ MyType 3   4.5
-- ghci> y <- thawRef $ MyType 100 12.34
-- ghci> movePartWithin (fieldMut #mtInt) x y
-- ghci> freezeRef x
-- MyType 100 4.5
-- @
movePartWithin
    :: Mutable m a
    => MutPart m s a
    -> Ref m s              -- ^ destination
    -> Ref m s              -- ^ source
    -> m ()
movePartWithin :: MutPart m s a -> Ref m s -> Ref m s -> m ()
movePartWithin mp :: MutPart m s a
mp r :: Ref m s
r v :: Ref m s
v = Ref m a -> Ref m a -> m ()
forall (m :: * -> *) a. Mutable m a => Ref m a -> Ref m a -> m ()
moveRef (MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp Ref m s
r) (MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp Ref m s
v)

-- | Clone out a subvalue of a larger 'Ref'.
clonePart
    :: Mutable m a
    => MutPart m s a
    -> Ref m s
    -> m (Ref m a)
clonePart :: MutPart m s a -> Ref m s -> m (Ref m a)
clonePart mp :: MutPart m s a
mp = Ref m a -> m (Ref m a)
forall (m :: * -> *) a. Mutable m a => Ref m a -> m (Ref m a)
cloneRef (Ref m a -> m (Ref m a))
-> (Ref m s -> Ref m a) -> Ref m s -> m (Ref m a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | A non-copying version of 'unsafeFreezeRef' that can be more efficient for
-- types where the mutable representation is the same as the immutable
-- one (like 'V.Vector').
--
-- This is safe as long as you never again modify the mutable
-- reference, since it can potentially directly mutate the frozen value
-- magically.
unsafeFreezePart :: Mutable m a => MutPart m s a -> Ref m s -> m a
unsafeFreezePart :: MutPart m s a -> Ref m s -> m a
unsafeFreezePart mp :: MutPart m s a
mp = Ref m a -> m a
forall (m :: * -> *) a. Mutable m a => Ref m a -> m a
unsafeFreezeRef (Ref m a -> m a) -> (Ref m s -> Ref m a) -> Ref m s -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp



-- | With a 'MutPart', modify a specific part of a 'Ref' with a pure
-- function.
modifyPart :: Mutable m a => MutPart m s a -> Ref m s -> (a -> a) -> m ()
modifyPart :: MutPart m s a -> Ref m s -> (a -> a) -> m ()
modifyPart mp :: MutPart m s a
mp = Ref m a -> (a -> a) -> m ()
forall (m :: * -> *) a. Mutable m a => Ref m a -> (a -> a) -> m ()
modifyRef (Ref m a -> (a -> a) -> m ())
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> a) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | 'modifyPart', but forces the result before storing it back in the
-- reference.
modifyPart' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> a) -> m ()
modifyPart' :: MutPart m s a -> Ref m s -> (a -> a) -> m ()
modifyPart' mp :: MutPart m s a
mp = Ref m a -> (a -> a) -> m ()
forall (m :: * -> *) a. Mutable m a => Ref m a -> (a -> a) -> m ()
modifyRef' (Ref m a -> (a -> a) -> m ())
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> a) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | 'updateRef', under a 'MutPart' to only modify a specific part of
-- a 'Ref'.
updatePart :: Mutable m a => MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b
updatePart :: MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b
updatePart mp :: MutPart m s a
mp = Ref m a -> (a -> (a, b)) -> m b
forall (m :: * -> *) a b.
Mutable m a =>
Ref m a -> (a -> (a, b)) -> m b
updateRef (Ref m a -> (a -> (a, b)) -> m b)
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> (a, b)) -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | 'updatePart', but forces the result before storing it back in the
-- reference.
updatePart' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b
updatePart' :: MutPart m s a -> Ref m s -> (a -> (a, b)) -> m b
updatePart' mp :: MutPart m s a
mp = Ref m a -> (a -> (a, b)) -> m b
forall (m :: * -> *) a b.
Mutable m a =>
Ref m a -> (a -> (a, b)) -> m b
updateRef' (Ref m a -> (a -> (a, b)) -> m b)
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> (a, b)) -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | With a 'MutPart', modify a specific part of a 'Ref' with a monadic
-- function.  Uses 'copyRef' into the reference after the action is
-- completed.
modifyPartM :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m a) -> m ()
modifyPartM :: MutPart m s a -> Ref m s -> (a -> m a) -> m ()
modifyPartM mp :: MutPart m s a
mp = Ref m a -> (a -> m a) -> m ()
forall (m :: * -> *) a.
Mutable m a =>
Ref m a -> (a -> m a) -> m ()
modifyRefM (Ref m a -> (a -> m a) -> m ())
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> m a) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | 'modifyPartM', but forces the result before storing it back in the
-- reference.
modifyPartM' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m a) -> m ()
modifyPartM' :: MutPart m s a -> Ref m s -> (a -> m a) -> m ()
modifyPartM' mp :: MutPart m s a
mp = Ref m a -> (a -> m a) -> m ()
forall (m :: * -> *) a.
Mutable m a =>
Ref m a -> (a -> m a) -> m ()
modifyRefM' (Ref m a -> (a -> m a) -> m ())
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> m a) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | 'updateRefM', under a 'MutPart' to only modify a specific part of
-- a 'Ref'.  'copyRef' into the reference after the action is completed.
updatePartM :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m (a, b)) -> m b
updatePartM :: MutPart m s a -> Ref m s -> (a -> m (a, b)) -> m b
updatePartM mp :: MutPart m s a
mp = Ref m a -> (a -> m (a, b)) -> m b
forall (m :: * -> *) a b.
Mutable m a =>
Ref m a -> (a -> m (a, b)) -> m b
updateRefM (Ref m a -> (a -> m (a, b)) -> m b)
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> m (a, b)) -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | 'updatePartM', but forces the result before storing it back in the
-- reference.
updatePartM' :: Mutable m a => MutPart m s a -> Ref m s -> (a -> m (a, b)) -> m b
updatePartM' :: MutPart m s a -> Ref m s -> (a -> m (a, b)) -> m b
updatePartM' mp :: MutPart m s a
mp = Ref m a -> (a -> m (a, b)) -> m b
forall (m :: * -> *) a b.
Mutable m a =>
Ref m a -> (a -> m (a, b)) -> m b
updateRefM' (Ref m a -> (a -> m (a, b)) -> m b)
-> (Ref m s -> Ref m a) -> Ref m s -> (a -> m (a, b)) -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart MutPart m s a
mp

-- | A 'MutPart' for a field in a vinyl 'Data.Vinyl.Rec', automatically
-- generated as the first field with a matching type.  This is polymorphic
-- to work over both 'Data.Vinyl.Rec' and 'Data.Vinyl.ARec'.
--
-- @
-- ghci> r <- 'thawRef' $ [1,2,3] 'V.:&' [True, False] :& 'V.RNil'
-- ghci> modifyPart (mutRec @Bool) r reverse
-- ghci> freezeRef r
-- [1,2,3] :& [False, True] :& RNil
-- @
mutRec
    :: forall a as f rec m.
     ( Ref m (rec f as) ~ rec (RecRef m f) as
     , RecElem rec a a as as (V.RIndex a as)
     , RecElemFCtx rec (RecRef m f)
     )
    => MutPart m (rec f as) (f a)
mutRec :: MutPart m (rec f as) (f a)
mutRec = (Ref m (rec f as) -> Ref m (f a)) -> MutPart m (rec f as) (f a)
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart ((Ref m (rec f as) -> Ref m (f a)) -> MutPart m (rec f as) (f a))
-> (Ref m (rec f as) -> Ref m (f a)) -> MutPart m (rec f as) (f a)
forall a b. (a -> b) -> a -> b
$ RecRef m f a -> Ref m (f a)
forall (m :: * -> *) k (f :: k -> *) (a :: k).
RecRef m f a -> Ref m (f a)
getRecRef (RecRef m f a -> Ref m (f a))
-> (rec (RecRef m f) as -> RecRef m f a)
-> rec (RecRef m f) as
-> Ref m (f a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (RecElem rec a a as as (RIndex a as),
 RecElemFCtx rec (RecRef m f)) =>
rec (RecRef m f) as -> RecRef m f a
forall k (r :: k) (rs :: [k]) (f :: k -> *)
       (record :: (k -> *) -> [k] -> *).
(RecElem record r r rs rs (RIndex r rs), RecElemFCtx record f) =>
record f rs -> f r
rget @a @as @(RecRef m f) @rec

-- | A 'MutPart' to get into a 'CoerceRef'.
coerceRef :: (Ref m s ~ CoerceRef m s a) => MutPart m s a
coerceRef :: MutPart m s a
coerceRef = (Ref m s -> Ref m a) -> MutPart m s a
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart Ref m s -> Ref m a
forall a b. Coercible a b => a -> b
coerce

-- | Handy wrapper over @'getMutPart' 'coerceRef'@.
withCoerceRef
    :: CoerceRef m s a
    -> (Ref m a -> m r)
    -> m r
withCoerceRef :: CoerceRef m s a -> (Ref m a -> m r) -> m r
withCoerceRef x :: CoerceRef m s a
x f :: Ref m a -> m r
f = Ref m a -> m r
f (CoerceRef m s a -> Ref m a
forall a b. Coercible a b => a -> b
coerce CoerceRef m s a
x)

-- | Typeclass used to implement 'hkdMutParts'.  See documentation of
-- 'hkdMutParts' for more information.
class (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m)) => HKDMutParts m z i o where
    hkdMutParts_ :: (z (RefFor m) -> i a) -> o a

instance (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m)) => HKDMutParts m z (K1 i (RefFor m c)) (K1 i (MutPart m (z Identity) c)) where
    hkdMutParts_ :: (z (RefFor m) -> K1 i (RefFor m c) a)
-> K1 i (MutPart m (z Identity) c) a
hkdMutParts_ f :: z (RefFor m) -> K1 i (RefFor m c) a
f = MutPart m (z Identity) c -> K1 i (MutPart m (z Identity) c) a
forall k i c (p :: k). c -> K1 i c p
K1 (MutPart m (z Identity) c -> K1 i (MutPart m (z Identity) c) a)
-> MutPart m (z Identity) c -> K1 i (MutPart m (z Identity) c) a
forall a b. (a -> b) -> a -> b
$ (Ref m (z Identity) -> Ref m c) -> MutPart m (z Identity) c
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart ((Ref m (z Identity) -> Ref m c) -> MutPart m (z Identity) c)
-> (Ref m (z Identity) -> Ref m c) -> MutPart m (z Identity) c
forall a b. (a -> b) -> a -> b
$ RefFor m c -> Ref m c
forall (m :: * -> *) a. RefFor m a -> Ref m a
getRefFor (RefFor m c -> Ref m c)
-> (z (RefFor m) -> RefFor m c) -> z (RefFor m) -> Ref m c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. K1 i (RefFor m c) a -> RefFor m c
forall i c k (p :: k). K1 i c p -> c
unK1 (K1 i (RefFor m c) a -> RefFor m c)
-> (z (RefFor m) -> K1 i (RefFor m c) a)
-> z (RefFor m)
-> RefFor m c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. z (RefFor m) -> K1 i (RefFor m c) a
f

instance (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m)) => HKDMutParts m z U1 U1 where
    hkdMutParts_ :: (z (RefFor m) -> U1 a) -> U1 a
hkdMutParts_ _ = U1 a
forall k (p :: k). U1 p
U1

instance (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m), TypeError ('Text "Cannot use hkdMutParts for uninhabited types: " ':<>: 'ShowType z)) => HKDMutParts m z V1 V1 where
    hkdMutParts_ :: (z (RefFor m) -> V1 a) -> V1 a
hkdMutParts_ _ = V1 a
forall a. HasCallStack => a
undefined

instance HKDMutParts m z i o => HKDMutParts m z (M1 a b i) (M1 a b o) where
    hkdMutParts_ :: (z (RefFor m) -> M1 a b i a) -> M1 a b o a
hkdMutParts_ f :: z (RefFor m) -> M1 a b i a
f = o a -> M1 a b o a
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 (o a -> M1 a b o a) -> o a -> M1 a b o a
forall a b. (a -> b) -> a -> b
$ (z (RefFor m) -> i a) -> o a
forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *)
       (o :: k -> *) (a :: k).
HKDMutParts m z i o =>
(z (RefFor m) -> i a) -> o a
hkdMutParts_ @m (M1 a b i a -> i a
forall i (c :: Meta) k (f :: k -> *) (p :: k). M1 i c f p -> f p
unM1 (M1 a b i a -> i a)
-> (z (RefFor m) -> M1 a b i a) -> z (RefFor m) -> i a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. z (RefFor m) -> M1 a b i a
f)

instance (HKDMutParts m z i o, HKDMutParts m z i' o') => HKDMutParts m z (i :*: i') (o :*: o') where
    hkdMutParts_ :: (z (RefFor m) -> (:*:) i i' a) -> (:*:) o o' a
hkdMutParts_ f :: z (RefFor m) -> (:*:) i i' a
f = (z (RefFor m) -> i a) -> o a
forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *)
       (o :: k -> *) (a :: k).
HKDMutParts m z i o =>
(z (RefFor m) -> i a) -> o a
hkdMutParts_ @m ((\(x :: i a
x:*:_)->i a
x) ((:*:) i i' a -> i a)
-> (z (RefFor m) -> (:*:) i i' a) -> z (RefFor m) -> i a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. z (RefFor m) -> (:*:) i i' a
f) o a -> o' a -> (:*:) o o' a
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: (z (RefFor m) -> i' a) -> o' a
forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *)
       (o :: k -> *) (a :: k).
HKDMutParts m z i o =>
(z (RefFor m) -> i a) -> o a
hkdMutParts_ @m ((\(_:*:y :: i' a
y)->i' a
y) ((:*:) i i' a -> i' a)
-> (z (RefFor m) -> (:*:) i i' a) -> z (RefFor m) -> i' a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. z (RefFor m) -> (:*:) i i' a
f)

instance (Mutable m (z Identity), Ref m (z Identity) ~ z (RefFor m), TypeError ('Text "Cannot use hkdMutParts for sum types: " ':<>: 'ShowType z)) => HKDMutParts m z (i :+: i') o where
    hkdMutParts_ :: (z (RefFor m) -> (:+:) i i' a) -> o a
hkdMutParts_ _ = o a
forall a. HasCallStack => a
undefined

-- | If you are using the "higher-kinded data" pattern, a la
-- <https://reasonablypolymorphic.com/blog/higher-kinded-data/>, and you
-- have the appropriate instance for 'Ref', then you can use this to
-- generate a 'MutPart' for every field, if you have a type with only one
-- constructor.
--
-- @
-- data MyTypeF f = MT
--      { mtInt    :: f Int
--      , mtDouble :: f Double
--      }
--   deriving Generic
--
-- instance Mutable (MyTypeF 'Identity') where
--     type Ref (MyTypeF 'Identity') = MyTypeF ('RefFor' m)
--
-- mx :: MutPart m (MyTypeF Identity) ('V.Vector' Int)
-- my :: MutPart m (MyTypeF Identity) (Vector Double)
-- MT mx my = hkdMutParts @MyTypeF
-- @
--
-- @
-- ghci> r <- thawRef (MT 3 4.5)
-- ghci> 'freezePart' mx r
-- 3
-- ghci> 'copyPart' (mtDouble (hkdMutParts @MyTypeF)) r 12.3
-- ghci> 'freezeRef' r
-- MT 3 12.3
-- @
--
-- Performance-wise, this is about equivalent to 'fieldMut' and 'posMut'
-- for the most part, so the main advantage would be purely syntactical. If
-- performance is an issue, you should benchmark all the different ways
-- just to be sure. As a general rule, it seems like deep nested accesses
-- are faster with composition of 'fieldMut' and 'posMut', but immediate
-- shallow access is often faster with 'hkdMutParts'...but this probably
-- does vary on a case-by-case basis.
hkdMutParts
    :: forall z m.
     ( Generic (z (RefFor m))
     , Generic (z (MutPart m (z Identity)))
     , HKDMutParts m z (Rep (z (RefFor m))) (Rep (z (MutPart m (z Identity))))
     )
    => z (MutPart m (z Identity))
hkdMutParts :: z (MutPart m (z Identity))
hkdMutParts = Rep (z (MutPart m (z Identity))) Any -> z (MutPart m (z Identity))
forall a x. Generic a => Rep a x -> a
to (Rep (z (MutPart m (z Identity))) Any
 -> z (MutPart m (z Identity)))
-> Rep (z (MutPart m (z Identity))) Any
-> z (MutPart m (z Identity))
forall a b. (a -> b) -> a -> b
$ (z (RefFor m) -> Rep (z (RefFor m)) Any)
-> Rep (z (MutPart m (z Identity))) Any
forall k (m :: * -> *) (z :: (* -> *) -> *) (i :: k -> *)
       (o :: k -> *) (a :: k).
HKDMutParts m z i o =>
(z (RefFor m) -> i a) -> o a
hkdMutParts_ @m @z z (RefFor m) -> Rep (z (RefFor m)) Any
forall a x. Generic a => a -> Rep a x
from

-- | Create a 'MutPart' for a field name.  Should work for any type with
-- one constructor whose mutable reference is 'GRef'.  See 'fieldMut' for
-- usage directions.
--
-- Mostly leverages the power of "Data.Generics.Product.Fields".
class (Mutable m s, Mutable m a) => FieldMut (fld :: Symbol) m s a | fld s -> a where
    -- | Create a 'MutPart' for a field name.  Should work for any type with
    -- one constructor whose mutable reference is 'GRef'.
    --
    -- Is meant to be used with OverloadedLabels:
    --
    -- @
    -- data MyType = MyType { mtInt :: Int, mtDouble :: Double }
    --   deriving (Generic, Show)
    --
    -- instance Mutable m MyType where
    --     type Ref m MyType = 'GRef' m MyType
    -- @
    --
    -- @
    -- ghci> r <- 'thawRef' (MyType 3 4.5)
    -- ghci> 'freezePart' ('fieldMut' #mtInt) r
    -- 3
    -- ghci> 'copyPart' (fieldMut #mtDouble) 1.23
    -- ghci> 'freezeRef' r
    -- MyType 3 1.23
    -- @
    --
    -- However, you can use it without OverloadedLabels by using 'Label' with
    -- TypeApplications:
    --
    -- @
    -- ghci> 'freezePart' ('fieldMut' ('Label' @"mtInt")) r
    -- 3
    -- @
    --
    -- This and 'posMut' are the main ways to generate a 'MutPart' for
    -- a type whose mutable reference is 'GRef'.  Note that because all of
    -- the lookups are done at compile-time, 'fieldMut' and 'posMut' have
    -- more or less identical performance characteristics.
    fieldMut
        :: Label fld        -- ^ field label (usually given using OverloadedLabels, @#blah)
        -> MutPart m s a

instance
      ( Mutable m s
      , Mutable m a
      , Ref m s ~ GRef m s
      , GL.GLens' (HasTotalFieldPSym fld) (GRef_ m (Rep s)) (Ref m a)
      , GL.HasField' fld s a
      )
      => FieldMut fld m s a where
    fieldMut :: Label fld -> MutPart m s a
fieldMut _ = (Ref m s -> Ref m a) -> MutPart m s a
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart ((Ref m s -> Ref m a) -> MutPart m s a)
-> (Ref m s -> Ref m a) -> MutPart m s a
forall a b. (a -> b) -> a -> b
$ Lens (GRef_ m (Rep s) ()) (GRef_ m (Rep s) ()) (Ref m a) (Ref m a)
-> GRef_ m (Rep s) () -> Ref m a
forall s a. Lens s s a a -> s -> a
GLP.view (forall (s :: * -> *) (t :: * -> *) a b x.
GLens (HasTotalFieldPSym fld) s t a b =>
Lens (s x) (t x) a b
forall (pred :: Pred) (s :: * -> *) (t :: * -> *) a b x.
GLens pred s t a b =>
Lens (s x) (t x) a b
GL.glens @(HasTotalFieldPSym fld)) (GRef_ m (Rep s) () -> Ref m a)
-> (GRef m s -> GRef_ m (Rep s) ()) -> GRef m s -> Ref m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GRef m s -> GRef_ m (Rep s) ()
forall (m :: * -> *) a. GRef m a -> GRef_ m (Rep a) ()
unGRef

data HasTotalFieldPSym :: Symbol -> GL.TyFun (Type -> Type) (Maybe Type)
type instance GL.Eval (HasTotalFieldPSym sym) tt = GL.HasTotalFieldP sym tt

-- | A helpful wrapper over @'withPart' ('fieldMut' #blah)@.  Create
-- a 'fieldMut' and directly use it.
withField
    :: FieldMut fld m s a
    => Label fld            -- ^ field label (usually given using OverloadedLabels, @#blah)
    -> Ref m s              -- ^ Larger record reference
    -> (Ref m a -> m b)     -- ^ What to do with the mutable field
    -> m b
withField :: Label fld -> Ref m s -> (Ref m a -> m b) -> m b
withField l :: Label fld
l = MutPart m s a -> Ref m s -> (Ref m a -> m b) -> m b
forall (m :: * -> *) s a r.
MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r
withPart (Label fld -> MutPart m s a
forall (fld :: Symbol) (m :: * -> *) s a.
FieldMut fld m s a =>
Label fld -> MutPart m s a
fieldMut Label fld
l)

-- | A helpful wrapper around @'getMutPart' ('fieldMut' #blah)@.  Directly
-- use a 'fieldMut' to access a mutable field.
mutField
    :: forall fld m s a. FieldMut fld m s a
    => Label fld            -- ^ field label (usually given using OverloadedLabels, @#blah)
    -> Ref m s              -- ^ Larger record reference
    -> Ref m a              -- ^ Internal mutable field
mutField :: Label fld -> Ref m s -> Ref m a
mutField = MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart (MutPart m s a -> Ref m s -> Ref m a)
-> (Label fld -> MutPart m s a) -> Label fld -> Ref m s -> Ref m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s a. FieldMut fld m s a => Label fld -> MutPart m s a
forall (fld :: Symbol) (m :: * -> *) s a.
FieldMut fld m s a =>
Label fld -> MutPart m s a
fieldMut @_ @m

-- | Create a 'MutPart' for a position in a product type.  Should work for any
-- type with one constructor whose mutable reference is 'GRef'.  See
-- 'posMut' for usage directions.
--
-- Mostly leverages the power of "Data.Generics.Product.Positions".
class (Mutable m s, Mutable m a) => PosMut (i :: Nat) m s a | i s -> a where
    -- | Create a 'MutPart' for a position in a product type.  Should work for any
    -- type with one constructor whose mutable reference is 'GRef'.
    --
    -- Meant to be used with TypeApplications:
    --
    -- @
    -- data MyType = MyType Int Double
    --   deriving (Generic, Show)
    --
    -- instance Mutable m MyType where
    --     type Ref m MyType = 'GRef' m MyType
    -- @
    --
    -- @
    -- ghci> r <- 'thawRef' (MyType 3 4.5)
    -- ghci> 'freezePart' ('posMut' \@1) r
    -- 3
    -- ghci> 'copyPart' (posMut \@2) 1.23
    -- ghci> 'freezeRef' r
    -- MyType 3 1.23
    -- @
    --
    -- This and 'fieldMut' are the main ways to generate a 'MutPart' for
    -- a type whose mutable reference is 'GRef'.  Note that because all of
    -- the lookups are done at compile-time, 'posMut' and 'fieldMut' have
    -- more or less identical performance characteristics.
    posMut :: MutPart m s a

instance
      ( Mutable m s
      , Mutable m a
      , Ref m s ~ GRef m s
      , gref ~ Fst (Traverse (GRef_ m (GL.CRep s)) 1)
      , Coercible (GRef_ m (Rep s) ()) (gref ())
      , GL.GLens' (HasTotalPositionPSym i) gref (Ref m a)
      , GL.HasPosition' i s a
      )
      => PosMut i m s a where
    posMut :: MutPart m s a
posMut = (Ref m s -> Ref m a) -> MutPart m s a
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart ((Ref m s -> Ref m a) -> MutPart m s a)
-> (Ref m s -> Ref m a) -> MutPart m s a
forall a b. (a -> b) -> a -> b
$ Lens (gref ()) (gref ()) (Ref m a) (Ref m a) -> gref () -> Ref m a
forall s a. Lens s s a a -> s -> a
GLP.view (forall (t :: * -> *) a b x.
GLens (HasTotalPositionPSym i) gref t a b =>
Lens (gref x) (t x) a b
forall (pred :: Pred) (s :: * -> *) (t :: * -> *) a b x.
GLens pred s t a b =>
Lens (s x) (t x) a b
GL.glens @(HasTotalPositionPSym i) @gref) (gref () -> Ref m a)
-> (GRef m s -> gref ()) -> GRef m s -> Ref m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Coercible (GRef_ m (Rep s) ()) (gref ()) =>
GRef_ m (Rep s) () -> gref ()
forall a b. Coercible a b => a -> b
coerce @_ @(gref ()) (GRef_ m (Rep s) () -> gref ())
-> (GRef m s -> GRef_ m (Rep s) ()) -> GRef m s -> gref ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GRef m s -> GRef_ m (Rep s) ()
forall (m :: * -> *) a. GRef m a -> GRef_ m (Rep a) ()
unGRef

data HasTotalPositionPSym :: Nat -> GL.TyFun (Type -> Type) (Maybe Type)
type instance GL.Eval (HasTotalPositionPSym t) tt = GL.HasTotalPositionP t tt

-- | A helpful wrapper over @'withPart' ('posMut' \@n)@.  Create
-- a 'posMut' and directly use it.
withPos
    :: forall i m s a r. PosMut i m s a
    => Ref m s              -- ^ Larger record reference
    -> (Ref m a -> m r)     -- ^ What to do with the mutable field
    -> m r
withPos :: Ref m s -> (Ref m a -> m r) -> m r
withPos = MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r
forall (m :: * -> *) s a r.
MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r
withPart (forall (i :: Nat) (m :: * -> *) s a.
PosMut i m s a =>
MutPart m s a
forall (m :: * -> *) s a. PosMut i m s a => MutPart m s a
posMut @i)

-- | A helpful wrapper around @'getMutPart' ('posMut' \@n)@.  Directly
-- use a 'posMut' to access a mutable field.
mutPos
    :: forall i m s a. PosMut i m s a
    => Ref m s              -- ^ Larger record reference
    -> Ref m a              -- ^ Internal mutable field
mutPos :: Ref m s -> Ref m a
mutPos = MutPart m s a -> Ref m s -> Ref m a
forall (m :: * -> *) s a. MutPart m s a -> Ref m s -> Ref m a
getMutPart (forall s a. PosMut i m s a => MutPart m s a
forall (i :: Nat) (m :: * -> *) s a.
PosMut i m s a =>
MutPart m s a
posMut @i @m)

-- | Create a 'MutPart' splitting out a product type into a tuple of refs
-- for every field in that product type. Should work for any type with one
-- constructor whose mutable reference is 'GRef'.  See 'tupleMut' for usage
-- directions.
--
-- Mostly leverages the power of "Data.Generics.Product.HList".
class (Mutable m s, Mutable m a) => TupleMut m s a | s -> a where
    -- | Create a 'MutPart' splitting out a product type into a tuple of refs
    -- for every field in that product type. Should work for any type with one
    -- constructor whose mutable reference is 'GRef'.
    --
    -- Probably most easily used using 'withTuple':
    --
    -- @
    -- data MyType = MyType Int Double
    --   deriving (Generic, Show)
    --
    -- instance Mutable m MyType where
    --     type Ref m MyType = 'GRef' m MyType
    -- @
    --
    -- Now there is an instance of @'TupleMut' m MyType (Int, Double)@.
    --
    -- @
    -- ghci> r <- 'thawRef' (MyType 3 4.5)
    -- ghci> 'withTuple' r $ \(rI, rD) -> do
    --    ..     'modifyRef' rI negate
    --    ..     modifyRef rD (* 2)
    -- ghci> 'freezeRef' r
    -- MyType (-3) 9
    -- @
    --
    -- As can be seen, within the lambda, we can get access to every
    -- mutable reference inside a @MyType@ reference.
    --
    -- Performance-wise, this appears to be faster than 'fieldMut' and
    -- 'posMut' when using a single reference, but slower if using all
    -- references.
    tupleMut :: MutPart m s a

instance
      ( Mutable m s
      , Mutable m a
      , Ref m s ~ GRef m s
      , GIsList (GRef_ m (Rep s)) (GRef_ m (Rep s)) (MapRef m as) (MapRef m as)
      , GIsList (Rep s) (Rep s) as as
      , ListTuple a a as as
      , ListTuple b b (MapRef m as) (MapRef m as)
      , Ref m a ~ b
      )
      => TupleMut m s a where
    tupleMut :: MutPart m s a
tupleMut = (Ref m s -> Ref m a) -> MutPart m s a
forall (m :: * -> *) s a. (Ref m s -> Ref m a) -> MutPart m s a
MutPart ((Ref m s -> Ref m a) -> MutPart m s a)
-> (Ref m s -> Ref m a) -> MutPart m s a
forall a b. (a -> b) -> a -> b
$ ListTuple b b (MapRef m as) (MapRef m as) =>
HList (MapRef m as) -> b
forall tuple tuple' (as :: [*]) (bs :: [*]).
ListTuple tuple tuple' as bs =>
HList as -> tuple
listToTuple @b @b @(MapRef m as) @(MapRef m as)
                       (HList (MapRef m as) -> b)
-> (GRef m s -> HList (MapRef m as)) -> GRef m s -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens
  (GRef_ m (Rep s) ())
  (GRef_ m (Rep s) ())
  (HList (MapRef m as))
  (HList (MapRef m as))
-> GRef_ m (Rep s) () -> HList (MapRef m as)
forall s a. Lens s s a a -> s -> a
GLP.view forall (f :: * -> *) (g :: * -> *) (as :: [*]) (bs :: [*]) x.
GIsList f g as bs =>
Iso (f x) (g x) (HList as) (HList bs)
Lens
  (GRef_ m (Rep s) ())
  (GRef_ m (Rep s) ())
  (HList (MapRef m as))
  (HList (MapRef m as))
glist
                       (GRef_ m (Rep s) () -> HList (MapRef m as))
-> (GRef m s -> GRef_ m (Rep s) ())
-> GRef m s
-> HList (MapRef m as)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GRef m s -> GRef_ m (Rep s) ()
forall (m :: * -> *) a. GRef m a -> GRef_ m (Rep a) ()
unGRef

-- | A helpful wrapper over @'withPart' 'tupleMut'@.  Directly operate on
-- the items in the data type, getting the references as a tuple.  See
-- 'tupleMut' for more details on when this should work.
--
-- @
-- data MyType = MyType Int Double
--   deriving (Generic, Show)
--
-- instance Mutable m MyType where
--     type Ref m MyType = 'GRef' m MyType
-- @
--
-- @
-- ghci> r <- 'thawRef' (MyType 3 4.5)
-- ghci> 'withTuple' r $ \(rI, rD) -> do
--    ..     'modifyRef' rI negate
--    ..     modifyRef rD (* 2)
-- ghci> 'freezeRef' r
-- MyType (-3) 9
-- @
withTuple
    :: TupleMut m s a
    => Ref m s              -- ^ Larger record reference
    -> (Ref m a -> m r)     -- ^ What to do with each mutable field.  The
                            -- @'Ref' m a@ will be a tuple of every field's ref.
    -> m r
withTuple :: Ref m s -> (Ref m a -> m r) -> m r
withTuple = MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r
forall (m :: * -> *) s a r.
MutPart m s a -> Ref m s -> (Ref m a -> m r) -> m r
withPart MutPart m s a
forall (m :: * -> *) s a. TupleMut m s a => MutPart m s a
tupleMut


-- stuff from generic-lens that wasn't exported

type G = Type -> Type

type family Traverse (a :: G) (n :: Nat) :: (G, Nat) where
  Traverse (M1 mt m s) n
    = Traverse1 (M1 mt m) (Traverse s n)
  Traverse (l :+: r) n
    = '(Fst (Traverse l n) :+: Fst (Traverse r n), n)
  Traverse (l :*: r) n
    = TraverseProd (:*:) (Traverse l n) r
  Traverse (K1 _ p) n
    = '(K1 (GL.Pos n) p, n + 1)
  Traverse U1 n
    = '(U1, n)

type family Traverse1 (w :: G -> G) (z :: (G, Nat)) :: (G, Nat) where
  Traverse1 w '(i, n) = '(w i, n)

-- | For products, we first traverse the left-hand side, followed by the second
-- using the counter returned by the left traversal.
type family TraverseProd (c :: G -> G -> G) (a :: (G, Nat)) (r :: G) :: (G, Nat) where
  TraverseProd w '(i, n) r = Traverse1 (w i) (Traverse r n)

type family Fst (p :: (a, b)) :: a where
  Fst '(a, b) = a