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


-- |
-- Module      : Data.Mutable.MutBranch
-- Copyright   : (c) Justin Le 2020
-- License     : BSD3
--
-- Maintainer  : justin@jle.im
-- Stability   : experimental
-- Portability : non-portable
--
-- Tools for working with potential branches of piecewise-mutable
-- values.
--
-- If "Data.Mutable.Parts" is for product types, then
-- "Data.Mutable.Branches" is for sum types.
--
-- See <https://mutable.jle.im/06-mutable-branches.html> for an
-- introduction to this module.
module Data.Mutable.Branches (
    MutBranch(..)
  , thawBranch
  , freezeBranch
  , hasBranch, hasn'tBranch
  , moveBranch
  , copyBranch
  , cloneBranch
  , unsafeThawBranch
  , unsafeFreezeBranch
  , withBranch, withBranch_
  , modifyBranch, modifyBranch'
  , updateBranch, updateBranch'
  , modifyBranchM, modifyBranchM'
  , updateBranchM, updateBranchM'
  -- * Built-in 'MutBranch'
  , compMB, idMB
  -- ** Using GHC Generics
  , constrMB, CLabel(..), GMutBranchConstructor, MapRef
  -- ** For common types
  , nilMB, consMB
  , nothingMB, justMB
  , leftMB, rightMB
  ) where

import           Control.Monad
import           Control.Monad.Primitive
import           Data.Generics.Product.Internal.HList
import           Data.Maybe
import           Data.Mutable.Class
import           Data.Mutable.Instances
import           Data.Mutable.Internal
import           Data.Primitive.MutVar
import           GHC.Generics
import           GHC.OverloadedLabels
import           GHC.TypeLits
import qualified Data.GenericLens.Internal              as GL
import qualified Data.Generics.Internal.Profunctor.Lens as GLP

-- | A @'MutBranch' s b a@ represents the information that @b@ could
-- potentially be an @a@.  Similar in spirit to a @Prism' b a@.
--
-- @'MutBranch' s b a@ means that @a@ is one potential option that @b@
-- could be in, or that @b@ is a sum type and @a@ is one of the
-- branches/constructors.
--
-- See <https://mutable.jle.im/06-mutable-branches.html> for an
-- introduction to this module.
--
-- If 'Data.Mutable.Parts.MutPart' is for product types, then 'MutBranch'
-- is for sum types.
--
-- In this case, "branch" means "potential option".  For example, the
-- branches of 'Either' are 'Left' and 'Right'.
--
-- The simplest way to make these is by using 'constrMB'.  For instance, to
-- get the two branches of an 'Either':
--
-- @
-- constrMB #_Left   :: MutBranch s (Either a b) a
-- constrMB #_Right  :: MutBranch s (Either a b) b
-- @
--
-- @
-- ghci> r <- 'thawRef' (Left 10)
-- ghci> 'freezeBranch' ('constrMB' #_Left) r
-- Just 10
-- ghci> freezeBranch (constrMB #_Right) r
-- Nothing
-- @
--
-- It uses OverloadedLabels, but requires an underscore before the
-- constructor name due to limitations in the extension.
--
-- One nice way to /use/ these is with 'withBranch_':
--
-- @
-- ghci> r <- 'thawRef' (Just 10)
-- ghci> 'withBranch_' (constrMB #_Just) $ \i ->    -- @i@ is an Int ref
--    ..   modifyRef i (+ 1)
-- ghci> 'freezeRef' r
-- Just 11
-- @
--
-- @
-- ghci> r <- thawRef Nothing
-- ghci> withBranch_ (constrMB #_Just) $ \i ->    -- @i@ is an Int ref
--    ..   modifyRef i (+ 1)
-- ghci> freezeRef r
-- Nothing
-- @
--
-- Perhaps the most useful usage of this abstraction is for recursive data
-- types.
--
-- @
-- data List a = Nil | Cons a (List a)
--   deriving Generic
--
-- instance Mutable s a => 'Mutable' s (List a) where
--     type Ref s (List a) = 'GRef' s (List a)
-- @
--
-- @'GRef' s (List a)@ is now a mutable linked list!  Once we make the
-- 'MutBranch' for the nil and cons cases:
--
-- @
-- nilBranch :: MutBranch s (List a) ()
-- nilBranch = constrMB #_Nil
--
-- consBranch :: MutBranch s (List a) (a, List a)
-- consBranch = constrMB #_Cons
-- @
--
--
-- Here is a function to check if a linked list is currently empty:
--
-- @
-- isEmpty
--     :: (PrimMonad m, Mutable s a)
--     => Ref s (List a)
--     -> m Bool
-- isEmpty = hasBranch nilBranch
-- @
--
-- Here is one to "pop" a mutable linked list, giving us the first value
-- and shifting the rest of the list up.
--
-- @
-- popStack
--     :: (PrimMonad m, Mutable s a)
--     => Ref s (List a)
--     -> m (Maybe a)
-- popStack r = do
--     c <- projectBranch consBranch r
--     case c of
--       Nothing      -> pure Nothing
--       Just (x, xs) -> do
--         moveRef r xs
--         Just <$> freezeRef x
-- @
--
-- And here is a function to concatenate a second linked list to the end of a
-- first one.
--
-- @
-- concatLists
--     :: (PrimMonad m, Mutable s a)
--     => Ref s (List a)
--     -> Ref s (List a)
--     -> m ()
-- concatLists l1 l2 = do
--     c <- projectBranch consBranch l1
--     case c of
--       Nothing      -> moveRef l1 l2
--       Just (_, xs) -> concatLists xs l2
-- @
data MutBranch s b a = MutBranch
    { -- | With a 'MutBranch', attempt to get the mutable contents of
      -- a branch of a mutable
      -- @s@, if possible.
      --
      -- @
      -- ghci> r <- thawRef (Left 10)
      -- ghci> s <- projectBranch (constrMB #_Left) r
      -- ghci> case s of Just s' -> freezeRef s'
      -- 10
      -- @
      --
      -- @
      -- ghci> r <- thawRef (Right True)
      -- ghci> s <- projectBranch (constrMB #_Left) r
      -- ghci> case s of Nothing -> "it was Right"
      -- "it was Right"
      -- @
      MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch :: forall m. (PrimMonad m, PrimState m ~ s) => Ref s b -> m (Maybe (Ref s a))
      -- | Embed an @a@ ref as a part of a larger @s@ ref.  Note that this
      -- /does not copy or clone/: any mutations to the @a@ ref will be
      -- reflected in the @s@ ref, as long as the @s@ ref maintains the
      -- reference.
      --
      -- @
      -- ghci> r <- thawRef 100
      -- ghci> s <- embedBranch (constMB #_Left) r
      -- ghci> freezeRef s
      -- Left 100
      -- ghci> modifyRef r (+ 1)
      -- ghci> freezeRef s
      -- Left 101
      -- @
      --
      -- Any mutations on @s@ (as long as they keep the same branch) will
      -- also affect @a@:
      --
      -- @
      -- ghci> copyRef s (Left 0)
      -- ghci> freezeRef r
      -- 0
      -- @
      --
      -- However, "switching branches" on an 'Either' ref will cause it to
      -- loose the original reference:
      --
      -- @
      -- ghci> copyRef s (Right True)
      -- ghci> copyRef s (Left 999)
      -- ghci> freezeRef r
      -- 0
      -- @
    , MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
embedBranch :: forall m. (PrimMonad m, PrimState m ~ s) => Ref s a -> m (Ref s b)
    }

-- | Compose two 'MutBranch's, to drill down on what is being focused.
compMB :: MutBranch s a b -> MutBranch s b c -> MutBranch s a c
compMB :: MutBranch s a b -> MutBranch s b c -> MutBranch s a c
compMB mb1 :: MutBranch s a b
mb1 mb2 :: MutBranch s b c
mb2 = MutBranch :: forall s b a.
(forall (m :: * -> *).
 (PrimMonad m, PrimState m ~ s) =>
 Ref s b -> m (Maybe (Ref s a)))
-> (forall (m :: * -> *).
    (PrimMonad m, PrimState m ~ s) =>
    Ref s a -> m (Ref s b))
-> MutBranch s b a
MutBranch
    { projectBranch :: forall (m :: * -> *).
(PrimMonad m, PrimState m ~ s) =>
Ref s a -> m (Maybe (Ref s c))
projectBranch = MutBranch s a b
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Maybe (Ref s b))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s a b
mb1 (Ref s a -> m (Maybe (Ref s b)))
-> (Maybe (Ref s b) -> m (Maybe (Ref s c)))
-> Ref s a
-> m (Maybe (Ref s c))
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> \case
        Nothing -> Maybe (Ref s c) -> m (Maybe (Ref s c))
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (Ref s c)
forall a. Maybe a
Nothing
        Just s :: Ref s b
s  -> MutBranch s b c -> Ref s b -> m (Maybe (Ref s c))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b c
mb2 Ref s b
s
    , embedBranch :: forall (m :: * -> *).
(PrimMonad m, PrimState m ~ s) =>
Ref s c -> m (Ref s a)
embedBranch = MutBranch s a b
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Ref s a)
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
embedBranch MutBranch s a b
mb1 (Ref s b -> m (Ref s a))
-> (Ref s c -> m (Ref s b)) -> Ref s c -> m (Ref s a)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< MutBranch s b c
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s c -> m (Ref s b)
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
embedBranch MutBranch s b c
mb2
    }

-- | An identity 'MutBranch', treating the item itself as a whole branch.
-- 'cloneBranch' will always "match".
idMB :: MutBranch s a a
idMB :: MutBranch s a a
idMB = (forall (m :: * -> *).
 (PrimMonad m, PrimState m ~ s) =>
 Ref s a -> m (Maybe (Ref s a)))
-> (forall (m :: * -> *).
    (PrimMonad m, PrimState m ~ s) =>
    Ref s a -> m (Ref s a))
-> MutBranch s a a
forall s b a.
(forall (m :: * -> *).
 (PrimMonad m, PrimState m ~ s) =>
 Ref s b -> m (Maybe (Ref s a)))
-> (forall (m :: * -> *).
    (PrimMonad m, PrimState m ~ s) =>
    Ref s a -> m (Ref s b))
-> MutBranch s b a
MutBranch (Maybe (Ref s a) -> m (Maybe (Ref s a))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (Ref s a) -> m (Maybe (Ref s a)))
-> (Ref s a -> Maybe (Ref s a)) -> Ref s a -> m (Maybe (Ref s a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ref s a -> Maybe (Ref s a)
forall a. a -> Maybe a
Just) forall (f :: * -> *) a. Applicative f => a -> f a
forall (m :: * -> *).
(PrimMonad m, PrimState m ~ s) =>
Ref s a -> m (Ref s a)
pure

-- | With a 'MutBranch', thaw an @a@ into a mutable @s@ on that branch.
--
-- @
-- ghci> r <- 'thawBranch' ('constrMB' #_Left) 10
-- ghci> 'freezeRef' r
-- Left 10
-- @
thawBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a
    -> a
    -> m (Ref s b)
thawBranch :: MutBranch s b a -> a -> m (Ref s b)
thawBranch mb :: MutBranch s b a
mb = MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
embedBranch MutBranch s b a
mb (Ref s a -> m (Ref s b)) -> (a -> m (Ref s a)) -> a -> m (Ref s b)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< a -> m (Ref s a)
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
a -> m (Ref s a)
thawRef

-- | With a 'MutBranch', read out a specific @a@ branch of an @s@, if it exists.
--
-- @
-- ghci> r <- 'thawRef' (Left 10)
-- ghci> 'freezeBranch' ('constrMB' #_Left) r
-- Just 10
-- ghci> freezeBranch (constrMB #_Right) r
-- Nothing
-- @
freezeBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a    -- ^ How to check if is @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of
    -> m (Maybe a)
freezeBranch :: MutBranch s b a -> Ref s b -> m (Maybe a)
freezeBranch mb :: MutBranch s b a
mb = (Ref s a -> m a) -> Maybe (Ref s a) -> m (Maybe a)
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ref s a -> m a
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> m a
freezeRef (Maybe (Ref s a) -> m (Maybe a))
-> (Ref s b -> m (Maybe (Ref s a))) -> Ref s b -> m (Maybe a)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b a
mb

-- | Check if an @s@ is currently a certain branch @a@.
hasBranch
    :: (PrimMonad m, PrimState m ~ s)
    => MutBranch s b a
    -> Ref s b
    -> m Bool
hasBranch :: MutBranch s b a -> Ref s b -> m Bool
hasBranch mb :: MutBranch s b a
mb = (Maybe (Ref s a) -> Bool) -> m (Maybe (Ref s a)) -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe (Ref s a) -> Bool
forall a. Maybe a -> Bool
isJust (m (Maybe (Ref s a)) -> m Bool)
-> (Ref s b -> m (Maybe (Ref s a))) -> Ref s b -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b a
mb

-- | Check if an @s@ is /not/ currently a certain branch @a@.
hasn'tBranch
    :: (PrimMonad m, PrimState m ~ s)
    => MutBranch s b a
    -> Ref s b
    -> m Bool
hasn'tBranch :: MutBranch s b a -> Ref s b -> m Bool
hasn'tBranch mb :: MutBranch s b a
mb = (Maybe (Ref s a) -> Bool) -> m (Maybe (Ref s a)) -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe (Ref s a) -> Bool
forall a. Maybe a -> Bool
isNothing (m (Maybe (Ref s a)) -> m Bool)
-> (Ref s b -> m (Maybe (Ref s a))) -> Ref s b -> m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b a
mb

-- | With a 'MutBranch', /set/ @s@ to have the branch @a@.
--
-- @
-- ghci> r <- 'thawRef' (Left 10)
-- ghci> 'copyBranch' ('constrMB' #_Left) r 5678
-- ghci> 'freezeRef' r
-- Left 5678
-- ghci> copyBranch (constrMB #_Right) r True
-- ghci> freezeRef r
-- Right True
-- @
copyBranch
    :: (Mutable s b, Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b              -- ^ Structure to write into
    -> a                    -- ^ Value to set @s@ to be
    -> m ()
copyBranch :: MutBranch s b a -> Ref s b -> a -> m ()
copyBranch mb :: MutBranch s b a
mb r :: Ref s b
r = MutBranch s b a -> Ref s b -> Ref s a -> m ()
forall s b (m :: * -> *) a.
(Mutable s b, PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> Ref s a -> m ()
moveBranch MutBranch s b a
mb Ref s b
r (Ref s a -> m ()) -> (a -> m (Ref s a)) -> a -> m ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< a -> m (Ref s a)
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
a -> m (Ref s a)
thawRef

-- | With a 'MutBranch', overwrite an @s@ as an @a@, on that branch.
--
-- @
-- ghci> r <- thawRef (Left 10)
-- ghci> s <- thawRef 100
-- ghci> moveBranch (constrMB #_Left) r s
-- ghci> freezeRef r
-- Left 100
-- ghci> t <- thawRef True
-- ghci> moveBranch (constrMB #_Right) r t
-- ghci> freezeRef r
-- Right True
-- @
moveBranch
    :: (Mutable s b, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a
    -> Ref s b
    -> Ref s a
    -> m ()
moveBranch :: MutBranch s b a -> Ref s b -> Ref s a -> m ()
moveBranch mb :: MutBranch s b a
mb r :: Ref s b
r = Ref s b -> Ref s b -> m ()
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> Ref s a -> m ()
moveRef Ref s b
r (Ref s b -> m ()) -> (Ref s a -> m (Ref s b)) -> Ref s a -> m ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
embedBranch MutBranch s b a
mb

-- | With a 'MutBranch', attempt to clone out a branch of a mutable
-- @s@, if possible.
--
-- @
-- ghci> r <- thawRef (Left 10)
-- ghci> s <- cloneBranch (constrMB #_Left)
-- ghci> case s of Just s' -> freezeRef s'
-- 10
-- @
--
-- @
-- ghci> r <- thawRef (Right True)
-- ghci> s <- cloneBranch (constrMB #_Left)
-- ghci> case s of Nothing -> "it was Right"
-- "it was Right"
-- @
cloneBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b              -- ^ Structure to read out of
    -> m (Maybe (Ref s a))
cloneBranch :: MutBranch s b a -> Ref s b -> m (Maybe (Ref s a))
cloneBranch mb :: MutBranch s b a
mb = (Ref s a -> m (Ref s a)) -> Maybe (Ref s a) -> m (Maybe (Ref s a))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ref s a -> m (Ref s a)
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> m (Ref s a)
cloneRef (Maybe (Ref s a) -> m (Maybe (Ref s a)))
-> (Ref s b -> m (Maybe (Ref s a)))
-> Ref s b
-> m (Maybe (Ref s a))
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b a
mb

-- | A non-copying version of 'freezeBranch' 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.
unsafeFreezeBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a    -- ^ How to check if is @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of
    -> m (Maybe a)
unsafeFreezeBranch :: MutBranch s b a -> Ref s b -> m (Maybe a)
unsafeFreezeBranch mb :: MutBranch s b a
mb = (Ref s a -> m a) -> Maybe (Ref s a) -> m (Maybe a)
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ref s a -> m a
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> m a
unsafeFreezeRef (Maybe (Ref s a) -> m (Maybe a))
-> (Ref s b -> m (Maybe (Ref s a))) -> Ref s b -> m (Maybe a)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b a
mb

-- | A non-copying version of 'thawBranch' 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 use the original pure value,
-- since it can potentially directly mutate it.
unsafeThawBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a
    -> a
    -> m (Ref s b)
unsafeThawBranch :: MutBranch s b a -> a -> m (Ref s b)
unsafeThawBranch mb :: MutBranch s b a
mb = MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s a -> m (Ref s b)
embedBranch MutBranch s b a
mb (Ref s a -> m (Ref s b)) -> (a -> m (Ref s a)) -> a -> m (Ref s b)
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< a -> m (Ref s a)
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
a -> m (Ref s a)
unsafeThawRef


-- | With a 'MutBranch', if an @s@ is on the @a@ branch, perform an action
-- on the @a@ reference and overwrite the @s@ with the modified @a@.
-- Returns the result of the action, if @a@ was found.
--
-- @
-- ghci> r <- 'thawRef' (Just 10)
-- ghci> 'withBranch_' ('constrMB' #_Just) $ \i ->    -- @i@ is an Int ref
--    ..   'modifyRef' i (+ 1)
-- ghci> 'freezeRef' r
-- Just 11
-- @
--
-- @
-- ghci> r <- thawRef Nothing
-- ghci> withBranch_ (constrMB #_Just) $ \i ->    -- @i@ is an Int ref
--    ..   modifyRef i (+ 1)
-- ghci> freezeRef r
-- Nothing
-- @
withBranch
    :: (PrimMonad m, PrimState m ~ s)
    => MutBranch s b a    -- ^ How to check if is @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (Ref s a -> m r)   -- ^ Action to perform on the @a@ branch of @s@
    -> m (Maybe r)
withBranch :: MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
withBranch mb :: MutBranch s b a
mb r :: Ref s b
r f :: Ref s a -> m r
f = (Ref s a -> m r) -> Maybe (Ref s a) -> m (Maybe r)
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ref s a -> m r
f (Maybe (Ref s a) -> m (Maybe r))
-> m (Maybe (Ref s a)) -> m (Maybe r)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< MutBranch s b a -> Ref s b -> m (Maybe (Ref s a))
forall s b a.
MutBranch s b a
-> forall (m :: * -> *).
   (PrimMonad m, PrimState m ~ s) =>
   Ref s b -> m (Maybe (Ref s a))
projectBranch MutBranch s b a
mb Ref s b
r

-- | 'withBranch', but discarding the returned value.
withBranch_
    :: (PrimMonad m, PrimState m ~ s)
    => MutBranch s b a    -- ^ How to check if is @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (Ref s a -> m r)   -- ^ Action to perform on the @a@ branch of @s@
    -> m ()
withBranch_ :: MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m ()
withBranch_ mb :: MutBranch s b a
mb r :: Ref s b
r = m (Maybe r) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (Maybe r) -> m ())
-> ((Ref s a -> m r) -> m (Maybe r)) -> (Ref s a -> m r) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
withBranch MutBranch s b a
mb Ref s b
r

-- | With a 'MutBranch', run a pure function over a potential branch @a@ of
-- @s@.  If @s@ is not on that branch, leaves @s@ unchanged.
--
-- @
-- ghci> r <- 'thawRef' (Just 10)
-- ghci> 'modifyBranch' ('constrMB' #_Just) r (+ 1)
-- ghci> freezeRef r
-- Just 11
-- @
--
-- @
-- ghci> r <- thawRef Nothing
-- ghci> modifyBranch (constrMB #_Just) r (+ 1)
-- ghci> freezeRef r
-- Nothing
-- @
modifyBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> a)             -- ^ Pure function modifying @a@
    -> m ()
modifyBranch :: MutBranch s b a -> Ref s b -> (a -> a) -> m ()
modifyBranch mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> a
f = MutBranch s b a -> Ref s b -> (Ref s a -> m ()) -> m ()
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m ()
withBranch_ MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> a) -> m ()
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> a) -> m ()
`modifyRef` a -> a
f)

-- | 'modifyBranch', but forces the result before storing it back in the
-- reference.
modifyBranch'
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> a)             -- ^ Pure function modifying @a@
    -> m ()
modifyBranch' :: MutBranch s b a -> Ref s b -> (a -> a) -> m ()
modifyBranch' mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> a
f = MutBranch s b a -> Ref s b -> (Ref s a -> m ()) -> m ()
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m ()
withBranch_ MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> a) -> m ()
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> a) -> m ()
`modifyRef'` a -> a
f)

-- | 'modifyBranch' but for a monadic function.  Uses 'copyRef' into the
-- reference after the action is completed.
modifyBranchM
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> m a)             -- ^ Monadic function modifying @a@
    -> m ()
modifyBranchM :: MutBranch s b a -> Ref s b -> (a -> m a) -> m ()
modifyBranchM mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> m a
f = MutBranch s b a -> Ref s b -> (Ref s a -> m ()) -> m ()
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m ()
withBranch_ MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> m a) -> m ()
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> m a) -> m ()
`modifyRefM` a -> m a
f)

-- | 'modifyBranchM', but forces the result before storing it back in the
-- reference.
modifyBranchM'
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> m a)             -- ^ Monadic function modifying @a@
    -> m ()
modifyBranchM' :: MutBranch s b a -> Ref s b -> (a -> m a) -> m ()
modifyBranchM' mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> m a
f = MutBranch s b a -> Ref s b -> (Ref s a -> m ()) -> m ()
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m ()
withBranch_ MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> m a) -> m ()
forall s a (m :: * -> *).
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> m a) -> m ()
`modifyRefM'` a -> m a
f)

-- | With a 'MutBranch', run a pure function over a potential branch @a@ of
-- @s@.  The function returns the updated @a@ and also an output value to
-- observe.  If @s@ is not on that branch, leaves @s@ unchanged.
--
-- @
-- ghci> r <- 'thawRef' (Just 10)
-- ghci> 'updateBranch' ('constrMB' #_Just) r $ \i -> (i + 1, show i)
-- Just "10"
-- ghci> 'freezeRef' r
-- Just 11
-- @
--
-- @
-- ghci> r <- thawRef Nothing
-- ghci> updateBranch (constrMB #_Just) r $ \i -> (i + 1, show i)
-- Nothing
-- ghci> freezeRef r
-- Nothing
-- @
updateBranch
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> (a, r))
    -> m (Maybe r)
updateBranch :: MutBranch s b a -> Ref s b -> (a -> (a, r)) -> m (Maybe r)
updateBranch mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> (a, r)
f = MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
withBranch MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> (a, r)) -> m r
forall s a (m :: * -> *) b.
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> (a, b)) -> m b
`updateRef` a -> (a, r)
f)

-- | 'updateBranch', but forces the result before storing it back in the
-- reference.
updateBranch'
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> (a, r))
    -> m (Maybe r)
updateBranch' :: MutBranch s b a -> Ref s b -> (a -> (a, r)) -> m (Maybe r)
updateBranch' mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> (a, r)
f = MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
withBranch MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> (a, r)) -> m r
forall s a (m :: * -> *) b.
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> (a, b)) -> m b
`updateRef'` a -> (a, r)
f)

-- | 'updateBranch' but for a monadic function.  Uses 'copyRef' into the
-- reference after the action is completed.
updateBranchM
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> m (a, r))
    -> m (Maybe r)
updateBranchM :: MutBranch s b a -> Ref s b -> (a -> m (a, r)) -> m (Maybe r)
updateBranchM mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> m (a, r)
f = MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
withBranch MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> m (a, r)) -> m r
forall s a (m :: * -> *) b.
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> m (a, b)) -> m b
`updateRefM` a -> m (a, r)
f)

-- | 'updateBranchM', but forces the result before storing it back in the
-- reference.
updateBranchM'
    :: (Mutable s a, PrimMonad m, PrimState m ~ s)
    => MutBranch s b a      -- ^ How to check if @s@ is an @a@
    -> Ref s b            -- ^ Structure to read out of and write into
    -> (a -> m (a, r))
    -> m (Maybe r)
updateBranchM' :: MutBranch s b a -> Ref s b -> (a -> m (a, r)) -> m (Maybe r)
updateBranchM' mb :: MutBranch s b a
mb r :: Ref s b
r f :: a -> m (a, r)
f = MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
forall (m :: * -> *) s b a r.
(PrimMonad m, PrimState m ~ s) =>
MutBranch s b a -> Ref s b -> (Ref s a -> m r) -> m (Maybe r)
withBranch MutBranch s b a
mb Ref s b
r (Ref s a -> (a -> m (a, r)) -> m r
forall s a (m :: * -> *) b.
(Mutable s a, PrimMonad m, PrimState m ~ s) =>
Ref s a -> (a -> m (a, b)) -> m b
`updateRefM'` a -> m (a, r)
f)



-- | A version of 'Data.Vinyl.Derived.Label' that removes an underscore at
-- the beginning when used with -XOverloadedLabels.  Used to specify
-- constructors, since labels are currently not able to start with capital
-- letters.
data CLabel (ctor :: Symbol) = CLabel

instance (ctor_ ~ AppendSymbol "_" ctor) => IsLabel ctor_ (CLabel ctor) where
    fromLabel :: CLabel ctor
fromLabel = CLabel ctor
forall (ctor :: Symbol). CLabel ctor
CLabel



-- | Typeclass powering 'constrMB' using GHC Generics.
--
-- Heavily inspired by "Data.Generics.Sum.Constructors".
class (GMutable s f, Mutable s a) => GMutBranchConstructor (ctor :: Symbol) s f a | ctor f -> a where
    gmbcProj  :: (PrimMonad m, PrimState m ~ s) => CLabel ctor -> GRef_ s f x -> m (Maybe (Ref s a))
    gmbcEmbed :: (PrimMonad m, PrimState m ~ s) => CLabel ctor -> Ref s a -> m (GRef_ s f x)

instance
      ( GMutable s f
      , Mutable s a
      , GIsList (GRef_ s f) (GRef_ s f) (MapRef s as) (MapRef s as)
      , GIsList f f as as
      , ListTuple a a as as
      , ListRefTuple s b as
      , Ref s a ~ b
      )
      => GMutBranchConstructor ctor s (M1 C ('MetaCons ctor fixity fields) f) a where
    gmbcProj :: CLabel ctor
-> GRef_ s (M1 C ('MetaCons ctor fixity fields) f) x
-> m (Maybe (Ref s a))
gmbcProj _  = Maybe b -> m (Maybe b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe b -> m (Maybe b))
-> (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x -> Maybe b)
-> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
-> m (Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Maybe b
forall a. a -> Maybe a
Just
                (b -> Maybe b)
-> (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x -> b)
-> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
-> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens (GRef_ s f x) (GRef_ s f x) b b -> GRef_ s f x -> b
forall s a. Lens s s a a -> s -> a
GLP.view (p i (HList (MapRef s as)) (HList (MapRef s as))
-> p i (GRef_ s f x) (GRef_ s f x)
forall (f :: * -> *) (g :: * -> *) (as :: [*]) (bs :: [*]) x.
GIsList f g as bs =>
Iso (f x) (g x) (HList as) (HList bs)
glist (p i (HList (MapRef s as)) (HList (MapRef s as))
 -> p i (GRef_ s f x) (GRef_ s f x))
-> (p i b b -> p i (HList (MapRef s as)) (HList (MapRef s as)))
-> p i b b
-> p i (GRef_ s f x) (GRef_ s f x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ListRefTuple s b as => Iso' (HList (MapRef s as)) b
forall s b (as :: [*]).
ListRefTuple s b as =>
Iso' (HList (MapRef s as)) b
tupledRef @s @b @as)
                (GRef_ s f x -> b)
-> (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
    -> GRef_ s f x)
-> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
-> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x -> GRef_ s f x
forall i (c :: Meta) k (f :: k -> *) (p :: k). M1 i c f p -> f p
unM1
    gmbcEmbed :: CLabel ctor
-> Ref s a -> m (GRef_ s (M1 C ('MetaCons ctor fixity fields) f) x)
gmbcEmbed _ = M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
-> m (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x)
forall (f :: * -> *) a. Applicative f => a -> f a
pure
                (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
 -> m (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x))
-> (b -> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x)
-> b
-> m (M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GRef_ s f x -> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1
                (GRef_ s f x -> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x)
-> (b -> GRef_ s f x)
-> b
-> M1 C ('MetaCons ctor fixity fields) (GRef_ s f) x
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens b b (GRef_ s f x) (GRef_ s f x) -> b -> GRef_ s f x
forall s a. Lens s s a a -> s -> a
GLP.view (Iso (GRef_ s f x) (GRef_ s f x) b b
-> Iso b b (GRef_ s f x) (GRef_ s f x)
forall s t a b. Iso s t a b -> Iso b a t s
GL.fromIso (p i (HList (MapRef s as)) (HList (MapRef s as))
-> p i (GRef_ s f x) (GRef_ s f x)
forall (f :: * -> *) (g :: * -> *) (as :: [*]) (bs :: [*]) x.
GIsList f g as bs =>
Iso (f x) (g x) (HList as) (HList bs)
glist (p i (HList (MapRef s as)) (HList (MapRef s as))
 -> p i (GRef_ s f x) (GRef_ s f x))
-> (p i b b -> p i (HList (MapRef s as)) (HList (MapRef s as)))
-> p i b b
-> p i (GRef_ s f x) (GRef_ s f x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ListRefTuple s b as => Iso' (HList (MapRef s as)) b
forall s b (as :: [*]).
ListRefTuple s b as =>
Iso' (HList (MapRef s as)) b
tupledRef @s @b @as))


instance GMutBranchConstructor ctor m f a => GMutBranchConstructor ctor m (M1 D meta f) a where
    gmbcProj :: CLabel ctor -> GRef_ m (M1 D meta f) x -> m (Maybe (Ref m a))
gmbcProj  lb :: CLabel ctor
lb = CLabel ctor -> GRef_ m f x -> m (Maybe (Ref m a))
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> GRef_ s f x -> m (Maybe (Ref s a))
gmbcProj CLabel ctor
lb (GRef_ m f x -> m (Maybe (Ref m a)))
-> (M1 D meta (GRef_ m f) x -> GRef_ m f x)
-> M1 D meta (GRef_ m f) x
-> m (Maybe (Ref m a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. M1 D meta (GRef_ m f) x -> GRef_ m f x
forall i (c :: Meta) k (f :: k -> *) (p :: k). M1 i c f p -> f p
unM1
    gmbcEmbed :: CLabel ctor -> Ref m a -> m (GRef_ m (M1 D meta f) x)
gmbcEmbed lb :: CLabel ctor
lb = (GRef_ m f x -> M1 D meta (GRef_ m f) x)
-> m (GRef_ m f x) -> m (M1 D meta (GRef_ m f) x)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap GRef_ m f x -> M1 D meta (GRef_ m f) x
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 (m (GRef_ m f x) -> m (M1 D meta (GRef_ m f) x))
-> (Ref m a -> m (GRef_ m f x))
-> Ref m a
-> m (M1 D meta (GRef_ m f) x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CLabel ctor -> Ref m a -> m (GRef_ m f x)
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> Ref s a -> m (GRef_ s f x)
gmbcEmbed CLabel ctor
lb

instance
      ( Mutable s a
      , GMutBranchSum ctor (GL.HasCtorP ctor l) s l r a
      )
      => GMutBranchConstructor ctor s (l :+: r) a where
    gmbcProj :: CLabel ctor -> GRef_ s (l :+: r) x -> m (Maybe (Ref s a))
gmbcProj  = forall s (l :: * -> *) (r :: * -> *) a (m :: * -> *) x.
(GMutBranchSum ctor (HasCtorP ctor l) s l r a, PrimMonad m,
 PrimState m ~ s) =>
CLabel ctor
-> MutSumF s (GRef_ s l) (GRef_ s r) x -> m (Maybe (Ref s a))
forall (ctor :: Symbol) (contains :: Bool) s (l :: * -> *)
       (r :: * -> *) a (m :: * -> *) x.
(GMutBranchSum ctor contains s l r a, PrimMonad m,
 PrimState m ~ s) =>
CLabel ctor
-> MutSumF s (GRef_ s l) (GRef_ s r) x -> m (Maybe (Ref s a))
gmbsProj @ctor @(GL.HasCtorP ctor l)
    gmbcEmbed :: CLabel ctor -> Ref s a -> m (GRef_ s (l :+: r) x)
gmbcEmbed = forall s (l :: * -> *) (r :: * -> *) a (m :: * -> *) x.
(GMutBranchSum ctor (HasCtorP ctor l) s l r a, PrimMonad m,
 PrimState m ~ s) =>
CLabel ctor -> Ref s a -> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
forall (ctor :: Symbol) (contains :: Bool) s (l :: * -> *)
       (r :: * -> *) a (m :: * -> *) x.
(GMutBranchSum ctor contains s l r a, PrimMonad m,
 PrimState m ~ s) =>
CLabel ctor -> Ref s a -> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
gmbsEmbed @ctor @(GL.HasCtorP ctor l)


class ( GMutable s l
      , GMutable s r
      , Mutable s a
      ) => GMutBranchSum (ctor :: Symbol) (contains :: Bool) s l r a | ctor l r -> a where
    gmbsProj
        :: (PrimMonad m, PrimState m ~ s)
        => CLabel ctor
        -> MutSumF s (GRef_ s l) (GRef_ s r) x
        -> m (Maybe (Ref s a))
    gmbsEmbed
        :: (PrimMonad m, PrimState m ~ s)
        => CLabel ctor
        -> Ref s a
        -> m (MutSumF s (GRef_ s l) (GRef_ s r) x)

instance
      ( GMutable s r
      , GMutBranchConstructor ctor s l a
      , GIsList (GRef_ s l) (GRef_ s l) (MapRef s as) (MapRef s as)
      , GIsList l l as as
      , ListTuple a a as as
      , ListRefTuple s b as
      , Ref s a ~ b
      )
      => GMutBranchSum ctor 'True s l r a where
    gmbsProj :: CLabel ctor
-> MutSumF s (GRef_ s l) (GRef_ s r) x -> m (Maybe (Ref s a))
gmbsProj lb :: CLabel ctor
lb (MutSumF r :: MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
r) = MutVar (PrimState m) ((:+:) (GRef_ s l) (GRef_ s r) x)
-> m ((:+:) (GRef_ s l) (GRef_ s r) x)
forall (m :: * -> *) a.
PrimMonad m =>
MutVar (PrimState m) a -> m a
readMutVar MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
MutVar (PrimState m) ((:+:) (GRef_ s l) (GRef_ s r) x)
r m ((:+:) (GRef_ s l) (GRef_ s r) x)
-> ((:+:) (GRef_ s l) (GRef_ s r) x -> m (Maybe b)) -> m (Maybe b)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      L1 x :: GRef_ s l x
x -> CLabel ctor -> GRef_ s l x -> m (Maybe (Ref s a))
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> GRef_ s f x -> m (Maybe (Ref s a))
gmbcProj CLabel ctor
lb GRef_ s l x
x
      R1 _ -> Maybe b -> m (Maybe b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe b
forall a. Maybe a
Nothing
    gmbsEmbed :: CLabel ctor -> Ref s a -> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
gmbsEmbed _ = (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
 -> MutSumF s (GRef_ s l) (GRef_ s r) x)
-> m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x))
-> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
-> MutSumF s (GRef_ s l) (GRef_ s r) x
forall k s (f :: k -> *) (g :: k -> *) (a :: k).
MutVar s ((:+:) f g a) -> MutSumF s f g a
MutSumF (m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x))
 -> m (MutSumF s (GRef_ s l) (GRef_ s r) x))
-> (b -> m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)))
-> b
-> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (:+:) (GRef_ s l) (GRef_ s r) x
-> m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x))
forall (m :: * -> *) a.
PrimMonad m =>
a -> m (MutVar (PrimState m) a)
newMutVar ((:+:) (GRef_ s l) (GRef_ s r) x
 -> m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)))
-> (b -> (:+:) (GRef_ s l) (GRef_ s r) x)
-> b
-> m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GRef_ s l x -> (:+:) (GRef_ s l) (GRef_ s r) x
forall k (f :: k -> *) (g :: k -> *) (p :: k). f p -> (:+:) f g p
L1
                (GRef_ s l x -> (:+:) (GRef_ s l) (GRef_ s r) x)
-> (b -> GRef_ s l x) -> b -> (:+:) (GRef_ s l) (GRef_ s r) x
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lens b b (GRef_ s l x) (GRef_ s l x) -> b -> GRef_ s l x
forall s a. Lens s s a a -> s -> a
GLP.view (Iso (GRef_ s l x) (GRef_ s l x) b b
-> Iso b b (GRef_ s l x) (GRef_ s l x)
forall s t a b. Iso s t a b -> Iso b a t s
GL.fromIso (p i (HList (MapRef s as)) (HList (MapRef s as))
-> p i (GRef_ s l x) (GRef_ s l x)
forall (f :: * -> *) (g :: * -> *) (as :: [*]) (bs :: [*]) x.
GIsList f g as bs =>
Iso (f x) (g x) (HList as) (HList bs)
glist (p i (HList (MapRef s as)) (HList (MapRef s as))
 -> p i (GRef_ s l x) (GRef_ s l x))
-> (p i b b -> p i (HList (MapRef s as)) (HList (MapRef s as)))
-> p i b b
-> p i (GRef_ s l x) (GRef_ s l x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ListRefTuple s b as => Iso' (HList (MapRef s as)) b
forall s b (as :: [*]).
ListRefTuple s b as =>
Iso' (HList (MapRef s as)) b
tupledRef @s @b @as))

instance
      ( GMutable s l
      , GMutBranchConstructor ctor s r a
      , Ref s a ~ b
      )
      => GMutBranchSum ctor 'False s l r a where
    gmbsProj :: CLabel ctor
-> MutSumF s (GRef_ s l) (GRef_ s r) x -> m (Maybe (Ref s a))
gmbsProj lb :: CLabel ctor
lb (MutSumF r :: MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
r) = MutVar (PrimState m) ((:+:) (GRef_ s l) (GRef_ s r) x)
-> m ((:+:) (GRef_ s l) (GRef_ s r) x)
forall (m :: * -> *) a.
PrimMonad m =>
MutVar (PrimState m) a -> m a
readMutVar MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
MutVar (PrimState m) ((:+:) (GRef_ s l) (GRef_ s r) x)
r m ((:+:) (GRef_ s l) (GRef_ s r) x)
-> ((:+:) (GRef_ s l) (GRef_ s r) x -> m (Maybe b)) -> m (Maybe b)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      L1 _ -> Maybe b -> m (Maybe b)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe b
forall a. Maybe a
Nothing
      R1 x :: GRef_ s r x
x -> CLabel ctor -> GRef_ s r x -> m (Maybe (Ref s a))
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> GRef_ s f x -> m (Maybe (Ref s a))
gmbcProj CLabel ctor
lb GRef_ s r x
x
    gmbsEmbed :: CLabel ctor -> Ref s a -> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
gmbsEmbed lb :: CLabel ctor
lb r :: Ref s a
r = do
      GRef_ s r x
gr <- CLabel ctor -> Ref s a -> m (GRef_ s r x)
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> Ref s a -> m (GRef_ s f x)
gmbcEmbed CLabel ctor
lb Ref s a
r
      MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
-> MutSumF s (GRef_ s l) (GRef_ s r) x
forall k s (f :: k -> *) (g :: k -> *) (a :: k).
MutVar s ((:+:) f g a) -> MutSumF s f g a
MutSumF (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x)
 -> MutSumF s (GRef_ s l) (GRef_ s r) x)
-> m (MutVar s ((:+:) (GRef_ s l) (GRef_ s r) x))
-> m (MutSumF s (GRef_ s l) (GRef_ s r) x)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (:+:) (GRef_ s l) (GRef_ s r) x
-> m (MutVar (PrimState m) ((:+:) (GRef_ s l) (GRef_ s r) x))
forall (m :: * -> *) a.
PrimMonad m =>
a -> m (MutVar (PrimState m) a)
newMutVar (GRef_ s r x -> (:+:) (GRef_ s l) (GRef_ s r) x
forall k (f :: k -> *) (g :: k -> *) (p :: k). g p -> (:+:) f g p
R1 GRef_ s r x
gr)


-- | Create a 'MutBranch' for any data type with a 'Generic' instance by
-- specifying the constructor name using OverloadedLabels
--
-- @
-- ghci> r <- 'thawRef' (Left 10)
-- ghci> 'freezeBranch' ('constrMB' #_Left) r
-- Just 10
-- ghci> freezeBranch (constrMB #_Right) r
-- Nothing
-- @
--
-- Note that due to limitations in OverloadedLabels, you must prefix the
-- constructor name with an undescore.
--
-- There also isn't currently any way to utilize OverloadedLabels with
-- operator identifiers, so using it with operator constructors (like @:@
-- and @[]@) requires explicit TypeApplications:
--
-- @
-- -- | 'MutBranch' focusing on the cons case of a list
-- consMB :: (PrimMonad m, Mutable s a) => MutBranch s [a] (a, [a])
-- consMB = 'constrMB' ('CLabel' @":")
-- @
constrMB
    :: forall ctor s b a.
     ( Ref s b ~ GRef s b
     , GMutBranchConstructor ctor s (Rep b) a
     )
    => CLabel ctor
    -> MutBranch s b a
constrMB :: CLabel ctor -> MutBranch s b a
constrMB l :: CLabel ctor
l = MutBranch :: forall s b a.
(forall (m :: * -> *).
 (PrimMonad m, PrimState m ~ s) =>
 Ref s b -> m (Maybe (Ref s a)))
-> (forall (m :: * -> *).
    (PrimMonad m, PrimState m ~ s) =>
    Ref s a -> m (Ref s b))
-> MutBranch s b a
MutBranch
    { projectBranch :: forall (m :: * -> *).
(PrimMonad m, PrimState m ~ s) =>
Ref s b -> m (Maybe (Ref s a))
projectBranch = CLabel ctor -> GRef_ s (Rep b) () -> m (Maybe (Ref s a))
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> GRef_ s f x -> m (Maybe (Ref s a))
gmbcProj CLabel ctor
l (GRef_ s (Rep b) () -> m (Maybe (Ref s a)))
-> (GRef s b -> GRef_ s (Rep b) ())
-> GRef s b
-> m (Maybe (Ref s a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GRef s b -> GRef_ s (Rep b) ()
forall s a. GRef s a -> GRef_ s (Rep a) ()
unGRef
    , embedBranch :: forall (m :: * -> *).
(PrimMonad m, PrimState m ~ s) =>
Ref s a -> m (Ref s b)
embedBranch   = (GRef_ s (Rep b) () -> GRef s b)
-> m (GRef_ s (Rep b) ()) -> m (GRef s b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap GRef_ s (Rep b) () -> GRef s b
forall s a. GRef_ s (Rep a) () -> GRef s a
GRef (m (GRef_ s (Rep b) ()) -> m (GRef s b))
-> (Ref s a -> m (GRef_ s (Rep b) ())) -> Ref s a -> m (GRef s b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CLabel ctor -> Ref s a -> m (GRef_ s (Rep b) ())
forall (ctor :: Symbol) s (f :: * -> *) a (m :: * -> *) x.
(GMutBranchConstructor ctor s f a, PrimMonad m, PrimState m ~ s) =>
CLabel ctor -> Ref s a -> m (GRef_ s f x)
gmbcEmbed CLabel ctor
l
    }

-- | 'MutBranch' focusing on the nil case of a list
nilMB :: Mutable s a => MutBranch s [a] ()
nilMB :: MutBranch s [a] ()
nilMB = CLabel "[]" -> MutBranch s [a] ()
forall (ctor :: Symbol) s b a.
(Ref s b ~ GRef s b, GMutBranchConstructor ctor s (Rep b) a) =>
CLabel ctor -> MutBranch s b a
constrMB (CLabel "[]"
forall (ctor :: Symbol). CLabel ctor
CLabel @"[]")

-- | 'MutBranch' focusing on the cons case of a list
consMB :: Mutable s a => MutBranch s [a] (a, [a])
consMB :: MutBranch s [a] (a, [a])
consMB = CLabel ":" -> MutBranch s [a] (a, [a])
forall (ctor :: Symbol) s b a.
(Ref s b ~ GRef s b, GMutBranchConstructor ctor s (Rep b) a) =>
CLabel ctor -> MutBranch s b a
constrMB (CLabel ":"
forall (ctor :: Symbol). CLabel ctor
CLabel @":")

-- | 'MutBranch' focusing on the 'Nothing' case of a 'Maybe'
nothingMB :: Mutable s a => MutBranch s (Maybe a) ()
nothingMB :: MutBranch s (Maybe a) ()
nothingMB = CLabel "Nothing" -> MutBranch s (Maybe a) ()
forall (ctor :: Symbol) s b a.
(Ref s b ~ GRef s b, GMutBranchConstructor ctor s (Rep b) a) =>
CLabel ctor -> MutBranch s b a
constrMB IsLabel "_Nothing" (CLabel "Nothing")
CLabel "Nothing"
#_Nothing

-- | 'MutBranch' focusing on the 'Just' case of a 'Maybe'
justMB :: Mutable s a => MutBranch s (Maybe a) a
justMB :: MutBranch s (Maybe a) a
justMB = CLabel "Just" -> MutBranch s (Maybe a) a
forall (ctor :: Symbol) s b a.
(Ref s b ~ GRef s b, GMutBranchConstructor ctor s (Rep b) a) =>
CLabel ctor -> MutBranch s b a
constrMB IsLabel "_Just" (CLabel "Just")
CLabel "Just"
#_Just

-- | 'MutBranch' focusing on the 'Left' case of an 'Either'
leftMB :: (Mutable s a, Mutable s b) => MutBranch s (Either a b) a
leftMB :: MutBranch s (Either a b) a
leftMB = CLabel "Left" -> MutBranch s (Either a b) a
forall (ctor :: Symbol) s b a.
(Ref s b ~ GRef s b, GMutBranchConstructor ctor s (Rep b) a) =>
CLabel ctor -> MutBranch s b a
constrMB IsLabel "_Left" (CLabel "Left")
CLabel "Left"
#_Left

-- | 'MutBranch' focusing on the 'Right' case of an 'Either'
rightMB :: (Mutable s a, Mutable s b) => MutBranch s (Either a b) b
rightMB :: MutBranch s (Either a b) b
rightMB = CLabel "Right" -> MutBranch s (Either a b) b
forall (ctor :: Symbol) s b a.
(Ref s b ~ GRef s b, GMutBranchConstructor ctor s (Rep b) a) =>
CLabel ctor -> MutBranch s b a
constrMB IsLabel "_Right" (CLabel "Right")
CLabel "Right"
#_Right