-- {-# LANGUAGE PolyKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-} -- | Combinators for creating encoding using existing encodings. -- -- @since 0.4.2.0 module Data.TypedEncoding.Instances.Support.Bool where import Data.TypedEncoding.Combinators.Unsafe import Data.TypedEncoding.Common.Types.Enc import Data.Proxy import Data.TypedEncoding.Common.Types import GHC.TypeLits -- import Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums (encFBan) -- import Data.TypedEncoding -- $setup -- >>> :set -XDataKinds -XFlexibleInstances -XFlexibleContexts -XOverloadedStrings -XTypeApplications -XScopedTypeVariables -- >>> import Data.TypedEncoding -- >>> import Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums (encFBan) -- | Defines new encoding by specifying 2 encodings, one needs to succeed. -- -- @since 0.4.2.0 implEncOr' :: forall alg alg1 alg2 nm nm1 nm2 c str . (KnownSymbol nm) => Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm2 alg2 c str -> Encoding (Either EncodeEx) nm alg c str implEncOr' enc1 enc2 = UnsafeMkEncoding Proxy f where f :: forall xs . Enc xs c str -> Either EncodeEx (Enc (nm ': xs) c str) f enc = case runEncoding' @alg1 @nm1 enc1 enc of Right r -> Right $ withUnsafeCoerce id r Left (EncodeEx _ err1) -> case runEncoding' @alg2 @nm2 enc2 enc of Right r -> Right $ withUnsafeCoerce id r Left (EncodeEx _ err2) -> Left $ EncodeEx (Proxy :: Proxy nm) (err1, err2) implEncOr :: forall nm nm1 nm2 c str . (KnownSymbol nm) => Encoding (Either EncodeEx) nm1 nm1 c str -> Encoding (Either EncodeEx) nm2 nm2 c str -> Encoding (Either EncodeEx) nm nm c str implEncOr = implEncOr' @nm @nm1 @nm2 -- | -- -- >>> let tst = _implEncOr @"r-tst:999(9)" @"r-ban:9999" @"r-ban:999" @() @String encFBan encFBan -- -- >>> fmap displ $ _runEncoding tst $ toEncoding () "123" -- Right "Enc '[r-tst:999(9)] () (String 123)" -- -- >>> fmap displ $ _runEncoding tst $ toEncoding () "1234" -- Right "Enc '[r-tst:999(9)] () (String 1234)" -- -- >>> fmap displ $ _runEncoding tst $ toEncoding () "12345" -- Left (EncodeEx "r-tst:999(9)" (("Input list has wrong size expecting 4 but length \"12345\" == 5","Input list has wrong size expecting 3 but length \"12345\" == 5"))) -- -- @since 0.4.2.0 _implEncOr :: forall nm nm1 nm2 c str alg alg1 alg2. ( KnownSymbol nm , Algorithm nm alg , Algorithm nm1 alg1 , Algorithm nm2 alg2 ) => Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm2 alg2 c str -> Encoding (Either EncodeEx) nm alg c str _implEncOr = implEncOr' @alg @alg1 @alg2 -- | Defines new encoding by specifying 2 encodings, both needs to succeed and produce the same payload. -- -- @since 0.4.2.0 implEncAnd' :: forall alg alg1 alg2 nm nm1 nm2 c str . (KnownSymbol nm, Eq str) => Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm2 alg2 c str -> Encoding (Either EncodeEx) nm alg c str implEncAnd' enc1 enc2 = UnsafeMkEncoding Proxy f where f :: forall xs . Enc xs c str -> Either EncodeEx (Enc (nm ': xs) c str) f enc = case (runEncoding' @alg1 @nm1 enc1 enc, runEncoding' @alg2 @nm2 enc2 enc) of (Right r1, Right r2) -> if getPayload r1 == getPayload r2 then Right $ withUnsafeCoerce id r1 else Left $ EncodeEx (Proxy :: Proxy nm) "Non-matching encodings" (Left (EncodeEx _ err1), Left (EncodeEx _ err2)) -> Left $ EncodeEx (Proxy :: Proxy nm) (err1, err2) (Left (EncodeEx _ err), _) -> Left $ EncodeEx (Proxy :: Proxy nm) (err, ()) (_, Left (EncodeEx _ err)) -> Left $ EncodeEx (Proxy :: Proxy nm) ((), err) implEncAnd :: forall nm nm1 nm2 c str . (KnownSymbol nm, Eq str) => Encoding (Either EncodeEx) nm1 nm1 c str -> Encoding (Either EncodeEx) nm2 nm2 c str -> Encoding (Either EncodeEx) nm nm c str implEncAnd = implEncAnd' @nm @nm1 @nm2 -- | -- -- >>> let tst2 = _implEncAnd @"r-tst:99" @"r-ban:9Z" @"r-ban:Z9" @() @String encFBan encFBan -- -- >>> fmap displ $ _runEncoding tst2 $ toEncoding () "99" -- Right "Enc '[r-tst:99] () (String 99)" -- -- >>> fmap displ $ _runEncoding tst2 $ toEncoding () "AB" -- Left (EncodeEx "r-tst:99" (("'A' not bounded by '9'","'B' not bounded by '9'"))) -- -- @since 0.4.2.0 _implEncAnd :: forall nm nm1 nm2 c str alg alg1 alg2. ( KnownSymbol nm , Eq str , Algorithm nm alg , Algorithm nm1 alg1 , Algorithm nm2 alg2 ) => Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm2 alg2 c str -> Encoding (Either EncodeEx) nm alg c str _implEncAnd = implEncAnd' @alg @alg1 @alg2 -- | Defines new encoding which succeeds only if specified encoding fails. -- It that happens, it applies given transformation function. -- -- @since 0.4.2.0 implEncNot' :: forall alg alg1 nm nm1 c str . (KnownSymbol nm) => (str -> str) -> Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm alg c str implEncNot' fn enc1 = UnsafeMkEncoding Proxy f where f :: forall xs . Enc xs c str -> Either EncodeEx (Enc (nm ': xs) c str) f enc = case runEncoding' @alg1 @nm1 enc1 enc of Left _ -> Right $ withUnsafeCoerce fn enc Right _ -> Left $ EncodeEx (Proxy :: Proxy nm) "Negated encoding succeeded" implEncNot :: forall nm nm1 c str . (KnownSymbol nm) => (str -> str) -> Encoding (Either EncodeEx) nm1 nm1 c str -> Encoding (Either EncodeEx) nm nm c str implEncNot = implEncNot' @nm @nm1 _implEncNot :: forall nm nm1 c str alg alg1 . ( KnownSymbol nm , Algorithm nm alg , Algorithm nm1 alg1 ) => (str -> str) -> Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm alg c str _implEncNot = implEncNot' @alg @alg1 -- | Defines restriction encoding that succeeds when specified encoding fails -- -- -- >>> let tst3 = _implREncNot @"r-tstnot:99" @"r-ban:99" @() @String encFBan -- -- >>> fmap displ $ _runEncoding tst3 $ toEncoding () "AA" -- Right "Enc '[r-tstnot:99] () (String AA)" -- -- >>> fmap displ $ _runEncoding tst3 $ toEncoding () "99" -- Left (EncodeEx "r-tstnot:99" ("Negated encoding succeeded")) -- -- @since 0.4.2.0 _implREncNot :: forall nm nm1 c str alg alg1 . ( KnownSymbol nm , Algorithm nm alg , Algorithm nm1 alg1 ) => Encoding (Either EncodeEx) nm1 alg1 c str -> Encoding (Either EncodeEx) nm alg c str _implREncNot = implEncNot' @alg @alg1 id