{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE RankNTypes #-}

-- |
-- This module defines 'SomeEnc' - existentially quantified version of @Enc@
-- and basic combinators.
--
-- This construction is common to more dependently typed Haskell but is 
-- isomorphic to 'Data.TypedEncoding.Common.Types.CheckedEnc.CheckedEnc'.  
--
-- Post v0.4 /typed-encoding/ supports @CheckedEnc@ while @SomeEnc@ remains as
-- as example.
--
-- (Moved from @Data.TypedEncoding.Common.Types.SomeEnc@ in previous versions)
--
-- @since 0.5.0.0

module Examples.TypedEncoding.SomeEnc where

import           Data.TypedEncoding.Common.Types.Enc
import           Data.TypedEncoding.Common.Class.Common
import           Data.TypedEncoding.Common.Types.CheckedEnc
import           Examples.TypedEncoding.SomeEnc.SomeAnnotation

-- $setup
-- >>> :set -XOverloadedStrings -XMultiParamTypeClasses -XDataKinds -XAllowAmbiguousTypes
-- >>> import qualified Data.Text as T
-- >>> import Data.TypedEncoding.Combinators.Unsafe



-- | Existentially quantified quantified @Enc@
-- effectively isomorphic to 'CheckedEnc'
--
-- @since 0.2.0.0
data SomeEnc conf str where
    MkSomeEnc :: SymbolList xs => Enc xs conf str -> SomeEnc conf str

-- |
-- @since 0.2.0.0   
withSomeEnc :: SomeEnc conf str -> (forall xs . SymbolList xs => Enc xs conf str -> r) -> r
withSomeEnc :: SomeEnc conf str
-> (forall (xs :: [Symbol]).
    SymbolList xs =>
    Enc @[Symbol] xs conf str -> r)
-> r
withSomeEnc (MkSomeEnc Enc @[Symbol] xs conf str
enc) forall (xs :: [Symbol]).
SymbolList xs =>
Enc @[Symbol] xs conf str -> r
f = Enc @[Symbol] xs conf str -> r
forall (xs :: [Symbol]).
SymbolList xs =>
Enc @[Symbol] xs conf str -> r
f Enc @[Symbol] xs conf str
enc

-- |
-- @since 0.2.0.0 
toSome :: SymbolList xs => Enc xs conf str -> SomeEnc conf str
toSome :: Enc @[Symbol] xs conf str -> SomeEnc conf str
toSome = Enc @[Symbol] xs conf str -> SomeEnc conf str
forall (xs :: [Symbol]) conf str.
SymbolList xs =>
Enc @[Symbol] xs conf str -> SomeEnc conf str
MkSomeEnc

-- | 
-- >>> let enctest = unsafeSetPayload () "hello" :: Enc '["TEST"] () T.Text
-- >>> someToChecked . MkSomeEnc $ enctest
-- UnsafeMkCheckedEnc ["TEST"] () "hello"
-- 
-- @since 0.2.0.0 
someToChecked :: SomeEnc conf str -> CheckedEnc conf str
someToChecked :: SomeEnc conf str -> CheckedEnc conf str
someToChecked SomeEnc conf str
se = SomeEnc conf str
-> (forall (xs :: [Symbol]).
    SymbolList xs =>
    Enc @[Symbol] xs conf str -> CheckedEnc conf str)
-> CheckedEnc conf str
forall conf str r.
SomeEnc conf str
-> (forall (xs :: [Symbol]).
    SymbolList xs =>
    Enc @[Symbol] xs conf str -> r)
-> r
withSomeEnc SomeEnc conf str
se forall (xs :: [Symbol]).
SymbolList xs =>
Enc @[Symbol] xs conf str -> CheckedEnc conf str
forall (xs :: [Symbol]) c str.
SymbolList xs =>
Enc @[Symbol] xs c str -> CheckedEnc c str
toCheckedEnc

-- | 
-- >>> let tst = unsafeCheckedEnc ["TEST"] () "test"
-- >>> displ $ checkedToSome tst
-- "Some (Enc '[TEST] () (String test))"
-- 
-- @since 0.2.0.0 s
checkedToSome :: CheckedEnc conf str -> SomeEnc conf str
checkedToSome :: CheckedEnc conf str -> SomeEnc conf str
checkedToSome (UnsafeMkCheckedEnc [EncAnn]
xs conf
c str
s) = SomeAnnotation
-> (forall (xs :: [Symbol]).
    SymbolList xs =>
    Proxy @[Symbol] xs -> SomeEnc conf str)
-> SomeEnc conf str
forall r.
SomeAnnotation
-> (forall (xs :: [Symbol]).
    SymbolList xs =>
    Proxy @[Symbol] xs -> r)
-> r
withSomeAnnotation ([EncAnn] -> SomeAnnotation
someAnnValue [EncAnn]
xs) (\Proxy @[Symbol] xs
p -> Enc @[Symbol] xs conf str -> SomeEnc conf str
forall (xs :: [Symbol]) conf str.
SymbolList xs =>
Enc @[Symbol] xs conf str -> SomeEnc conf str
MkSomeEnc (Proxy @[Symbol] xs -> conf -> str -> Enc @[Symbol] xs conf str
forall k (nms :: k) conf str.
Proxy @k nms -> conf -> str -> Enc @k nms conf str
UnsafeMkEnc Proxy @[Symbol] xs
p conf
c str
s))


-- |
-- >>> let enctest = unsafeSetPayload () "hello" :: Enc '["TEST"] () T.Text
-- >>> displ $ MkSomeEnc enctest
-- "Some (Enc '[TEST] () (Text hello))"
instance (Show c, Displ str) => Displ (SomeEnc c str) where
    displ :: SomeEnc c str -> EncAnn
displ (MkSomeEnc Enc @[Symbol] xs c str
en) = 
       EncAnn
"Some (" EncAnn -> EncAnn -> EncAnn
forall a. [a] -> [a] -> [a]
++ Enc @[Symbol] xs c str -> EncAnn
forall x. Displ x => x -> EncAnn
displ Enc @[Symbol] xs c str
en EncAnn -> EncAnn -> EncAnn
forall a. [a] -> [a] -> [a]
++ EncAnn
")"