{-# LANGUAGE MultiParamTypeClasses #-} -- {-# LANGUAGE PolyKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ConstraintKinds #-} -- | -- There seems to be no easy ways to verify encoding using the /encoding/ package. -- -- /decode/ functions implemented in /encoding/ are very forgiving and work -- on invalid encoded inputs. This forces this package to resort to checking that -- -- @ -- Encoding.encodeXyz . Encoding.decodeXyz -- @ -- -- acts as the identity. This is obviously quite expensive. -- -- This module provides such implementation and hence the warning. -- -- >>> Encoding.decodeStrictByteStringExplicit EncUTF8.UTF8 "\192\NUL" -- Right "\NUL" -- -- >>> Encoding.encodeStrictByteStringExplicit EncUTF8.UTF8 "\NUL" -- Right "\NUL" module Data.TypedEncoding.Pkg.Encoding.Warn.Instances {-# WARNING "Not optimized for performance" #-} where import qualified Data.TypedEncoding.Instances.Support as Typed import qualified Data.Encoding as Encoding import GHC.TypeLits import Data.Proxy import Data.TypedEncoding.Pkg.Encoding.Conv -- import qualified Data.TypedEncoding as Usage -- import Data.Encoding.UTF8 as EncUTF8 -- $setup -- >>> :set -XOverloadedStrings -XDataKinds -XTypeApplications -XFlexibleContexts -- >>> import Data.Functor.Identity -- >>> import qualified Data.TypedEncoding as Usage -- >>> import Data.Encoding.UTF8 as EncUTF8 -- * Validation Combinators (Slow) data DecodeOrEncodeException = DecErr Encoding.DecodingException | EncErr Encoding.EncodingException | DecEncMismatch deriving (Show, Eq) validatingDecS :: forall s c . ( DynEnc s , Typed.Algorithm s "enc-pkg/encoding" ) => Typed.Decoding (Either Typed.UnexpectedDecodeEx) s "enc-pkg/encoding" c String validatingDecS = Typed._implDecodingF (verifyDynDec (Proxy :: Proxy s) exferDynEncoding slowValidation) where -- see comments in fromDynEncB slowValidation enc str = do dec <- either (Left . DecErr) Right . Encoding.decodeStringExplicit enc $ str res <- either (Left . EncErr) Right . Encoding.encodeStringExplicit enc $ dec if str == res then Right dec else Left DecEncMismatch -- tst = fmap Usage.displ . -- Usage.recreateFAll' -- @'["enc-pkg/encoding"] -- @'["enc-pkg/encoding:cyrillic"] -- @(Either Usage.RecreateEx) -- @() -- @String . Usage.toEncoding () $ "\193\226\208\226\236\239" -- | -- -- >>> :{ -- fmap Usage.displ . -- Usage.recreateFAll' -- @'["enc-pkg/encoding"] -- @'["enc-pkg/encoding:greek"] -- @(Either Usage.RecreateEx) -- @() -- @String . Usage.toEncoding () $ "\193\226\208\226\236\255" -- :} -- Left (RecreateEx "enc-pkg/encoding:greek" (DecErr (IllegalCharacter 255))) -- -- @\"Статья\"@ example: -- -- >>> :{ -- fmap Usage.displ . -- Usage.recreateFAll' -- @'["enc-pkg/encoding"] -- @'["enc-pkg/encoding:cyrillic"] -- @(Either Usage.RecreateEx) -- @() -- @String . Usage.toEncoding () $ "\193\226\208\226\236\239" -- :} -- Right "Enc '[enc-pkg/encoding:cyrillic] () (String \193\226\208\226\236\239)" instance (KnownSymbol s , DynEnc s, Typed.Algorithm s "enc-pkg/encoding", Typed.RecreateErr f, Applicative f) => Typed.Validate f s "enc-pkg/encoding" c String where validation = Typed.validFromDec' @"enc-pkg/encoding" validatingDecS verifyDynDec :: forall s str err1 err2 enc a. (KnownSymbol s, Show err1, Show err2) => Proxy s -- ^ proxy defining encoding annotation -> (Proxy s -> Either err1 enc) -- ^ finds encoding marker @enc@ for given annotation or fails -> (enc -> str -> Either err2 str) -- ^ decoder based on @enc@ marker -> str -> Either Typed.UnexpectedDecodeEx str verifyDynDec p findenc decoder str = do enc <- either (Left . Typed.UnexpectedDecodeEx p) Right . findenc $ p case decoder enc str of Left err -> Left $ Typed.UnexpectedDecodeEx p err Right r -> Right r