-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Type safe string transformations -- -- See README.md in the project github repository. @package typed-encoding @version 0.5.2.3 -- | This Module will be removed in the future in favor of classes defined -- in Data.TypedEncoding.Common.Class.Util.StringConstraints -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Class.IsStringR -- | This class will be removed in 0.3.x.x in favor of classes definined in -- Data.TypedEncoding.Common.Class.Util.StringConstraints -- -- Reverses IsString -- -- laws: -- --
-- toString . fromString == id -- fromString . toString == id ---- -- Note: ByteString is not a valid instance, ByteString "r-ASCII", or -- "r-UTF8" would be needed. B.unpack $ B.pack "160688" == "176" class IsStringR a toString :: IsStringR a => a -> String prop_fromStringToString :: forall s. (IsString s, IsStringR s, Eq s) => s -> Bool prop_toStringFromString :: forall s. (IsString s, IsStringR s) => Proxy s -> String -> Bool instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR [GHC.Types.Char] -- | ToStrInj and ToStrIso are future replacement for -- Data.TypedEncoding.Common.Class.IsStringR (currently not used). module Data.TypedEncoding.Common.Class.Util.StringConstraints -- | Reverses IsString -- -- law for types that are also IsString: -- --
-- toString . fromString == id ---- -- Note: ByteString is not a valid instance, ByteString "r-ASCII", or -- "r-UTF8" would be needed. B8.unpack $ B8.pack "160688" == -- "176" -- -- This class is separated from ToStrIso to allow instances from -- smaller types the can inject into the String type. class ToStrInj str from toString :: ToStrInj str from => from -> str prop_toStringFromString :: forall s. (IsString s, ToStrInj String s) => Proxy s -> String -> Bool -- | Same as ToStrInj but with additional -- -- law for types that are also IsString: fromString . -- toString == id class ToStrInj str from => ToStrIso str from prop_fromStringToString :: forall s. (IsString s, ToStrIso String s, Eq s) => s -> Bool -- | Used to find exceptions that violated "r-" encoding Expected to be -- used to check encoding of ASCII-7 so Text and ByteString are -- compatible or to check 0-255 range restrictions. class Char8Find str find :: Char8Find str => (Char -> Bool) -> str -> Maybe Char instance Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find GHC.Base.String instance Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find Data.ByteString.Internal.ByteString instance Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find Data.ByteString.Lazy.Internal.ByteString instance Data.TypedEncoding.Common.Class.Util.StringConstraints.ToStrIso GHC.Base.String Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.Util.StringConstraints.ToStrIso GHC.Base.String Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Common.Class.Util.StringConstraints.ToStrIso GHC.Base.String GHC.Base.String instance Data.TypedEncoding.Common.Class.Util.StringConstraints.ToStrInj GHC.Base.String Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.Util.StringConstraints.ToStrInj GHC.Base.String Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Common.Class.Util.StringConstraints.ToStrInj GHC.Base.String GHC.Base.String -- | Exception types used in typed-encoding -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Types.Exceptions -- | Represents errors in recovery (recreation of encoded types). data RecreateEx [RecreateEx] :: (Show e, KnownSymbol x) => Proxy x -> e -> RecreateEx [RecreateExUnkStep] :: Show e => e -> RecreateEx recreateErrUnknown :: Show e => e -> RecreateEx -- | Represents errors in encoding @since 0.1.0.0 data EncodeEx [EncodeEx] :: (Show a, KnownSymbol x) => Proxy x -> a -> EncodeEx asEncodeEx :: (Show a, KnownSymbol x) => Proxy x -> Either a b -> Either EncodeEx b -- | Useful when manually recreating using recovery @since 0.2.2.0 encToRecrEx :: EncodeEx -> RecreateEx mergeEncodeEx :: KnownSymbol x => Proxy x -> EncodeEx -> Maybe EncodeEx -> EncodeEx emptyEncErr :: KnownSymbol x => Proxy x -> EncodeEx -- | Type safety over encodings makes decoding process safe. However -- failures are still possible due to bugs or unsafe payload -- modifications. UnexpectedDecodeEx represents such errors. data UnexpectedDecodeEx [UnexpectedDecodeEx] :: (Show a, KnownSymbol x) => Proxy x -> a -> UnexpectedDecodeEx mergeErrs :: err -> (err -> Maybe err -> err) -> Either err a -> Either err b -> Either err c instance GHC.Show.Show Data.TypedEncoding.Common.Types.Exceptions.UnexpectedDecodeEx instance GHC.Show.Show Data.TypedEncoding.Common.Types.Exceptions.EncodeEx instance GHC.Show.Show Data.TypedEncoding.Common.Types.Exceptions.RecreateEx -- | TypeLits related utilities. -- -- Lots of this could be avoided by adding singletons as -- dependency. -- -- Uses symbols library for its ToList type family. module Data.TypedEncoding.Common.Util.TypeLits -- | Convenience combinator missing in TypeLits, See -- Examples.TypedEncoding.SomeEnc.SomeAnnotation -- "Examples.TypedEncoding.SomeEnc.someAnnValue" withSomeSymbol :: SomeSymbol -> (forall x. KnownSymbol x => Proxy x -> r) -> r -- | (Moved from previously defined module -- Data.TypedEncoding.Common.Types.SomeAnnotation) proxyCons :: forall (x :: Symbol) (xs :: [Symbol]). Proxy x -> Proxy xs -> Proxy (x : xs) -- | Type level list append -- -- (moved from Data.TypedEncoding.Common.Class.Common) type family Append (xs :: [k]) (ys :: [k]) :: [k] type family AcceptEq (msg :: ErrorMessage) (c :: Ordering) :: Bool type family OrdBool (c :: Ordering) :: Bool type family And (b1 :: Bool) (b2 :: Bool) :: Bool type family Or (b1 :: Bool) (b2 :: Bool) :: Bool type family If (b1 :: Bool) (a :: k) (b :: k) :: k type family Repeat (n :: Nat) (s :: Symbol) :: Symbol type family Fst (s :: (k, h)) :: k type family Dupl (s :: k) :: (k, k) -- |
-- >>> :kind! Concat (LDrop 6 (ToList "bool: \"r-ban:ff-ff\" | \"r-ban:ffff\"")) -- ... -- = "\"r-ban:ff-ff\" | \"r-ban:ffff\"" --type family Concat (s :: [Symbol]) :: Symbol type family Drop (n :: Nat) (s :: Symbol) :: Symbol type family LDrop (n :: Nat) (s :: [k]) :: [k] -- |
-- >>> :kind! Take 3 "123456" -- ... -- = "123" --type family Take (n :: Nat) (s :: Symbol) :: Symbol type family LTake (n :: Nat) (s :: [k]) :: [k] type family TakeUntil (s :: Symbol) (stop :: Symbol) :: Symbol type family LTakeUntil (s :: [Symbol]) (stop :: Symbol) :: [Symbol] type family LTakeUntilHelper (s :: [Symbol]) (o :: Ordering) :: [Symbol] type family Length (s :: Symbol) :: Nat type family LLengh (s :: [k]) :: Nat -- |
-- >>> :kind! LLast '["1","2","3"] -- ... -- = "3" --type family LLast (s :: [Symbol]) :: Symbol -- |
-- >>> :kind! Concat (Snoc '["1","2","3"] "4") -- ... -- = "1234" --type family Snoc (s :: [k]) (t :: k) :: [k] -- | :kind! UnSnoc '["1","2","3"] ... = '( (':) Symbol "1" ((':) Symbol "2" -- ('[] Symbol)), "3") type family UnSnoc (s :: [k]) :: ([k], k) type family UnSnocHelper (s :: k) (t :: ([k], k)) :: ([k], k) -- | Common types and some type families used in typed-encoding -- definitions. -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Types.Common -- | Represents value level (single) annotation. @since 0.2.0.0 type EncAnn = String -- | Constraint for "r-" annotations. type Restriction s = (KnownSymbol s, IsR s ~ 'True) -- | Constraint for "r-" annotations. type EncodingAnn s = (KnownSymbol s, IsEnc s ~ 'True) -- | Constraint for algorithm name. type Algorithm nm alg = AlgNm nm ~ alg -- | Converts encoding name to algorithm name, this assumes the ":" -- delimiter expected by this library. -- -- This allows working with open encoding definitions such as "r-ban" -- --
-- >>> :kind! AlgNm "enc-B64" -- ... -- = "enc-B64" ---- --
-- >>> :kind! AlgNm "r-ban:999-99-9999" -- ... -- = "r-ban" --type family AlgNm (encnm :: Symbol) :: Symbol type family AlgNmMap (nms :: [Symbol]) :: [Symbol] -- |
-- >>> :kind! IsR "r-UPPER" -- ... -- ... 'True ---- --
-- >>> :kind! IsR "do-UPPER" -- ... -- = (TypeError ... --type family IsR (s :: Symbol) :: Bool type family IsROrEmpty (s :: Symbol) :: Bool -- |
-- >>> :kind! RemoveRs '["r-UPPER", "enc-test", "r-lower", "do-UPPER"] -- ... -- = '["enc-test", "do-UPPER"] --type family RemoveRs (s :: [Symbol]) :: [Symbol] -- |
-- >>> :kind! IsEnc "enc-boo" -- ... -- = 'True --type family IsEnc (s :: Symbol) :: Bool -- | This module defines SymbolList and Displ type -- classes using by typed-encoding used for display / testing as -- well as for construction of untyped versions of Enc -- (CheckedEnc and UncheckedEnc) -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Class.Common class SymbolList (xs :: [Symbol]) symbolVals :: SymbolList xs => [String] symbolVals_ :: forall xs. SymbolList xs => Proxy xs -> [String] -- | Human friendly version of Show class Displ x displ :: Displ x => x -> String instance Data.TypedEncoding.Common.Class.Common.Displ [Data.TypedEncoding.Common.Types.Common.EncAnn] instance Data.TypedEncoding.Common.Class.Common.Displ Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.Common.Displ Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Common.Class.Common.Displ Data.ByteString.Internal.ByteString instance Data.TypedEncoding.Common.Class.Common.Displ Data.ByteString.Lazy.Internal.ByteString instance Data.TypedEncoding.Common.Class.Common.Displ GHC.Base.String instance Data.TypedEncoding.Common.Class.Common.SymbolList xs => Data.TypedEncoding.Common.Class.Common.Displ (Data.Proxy.Proxy @{[GHC.Types.Symbol]} xs) instance Data.TypedEncoding.Common.Class.Common.SymbolList ('[] @GHC.Types.Symbol) instance (Data.TypedEncoding.Common.Class.Common.SymbolList xs, GHC.TypeLits.KnownSymbol x) => Data.TypedEncoding.Common.Class.Common.SymbolList ((':) @GHC.Types.Symbol x xs) -- | Defines UncheckedEnc representing not verified encoding and -- basic combinators for using it. -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Types.UncheckedEnc -- | Represents some encoded string where encoding was not validated. -- -- Encoding is not tracked at the type level. -- -- Similar to CheckedEnc but unlike CheckedEnc it can -- contain payloads that have invalid encoding. -- -- See check data UncheckedEnc c str MkUncheckedEnc :: [EncAnn] -> c -> str -> UncheckedEnc c str toUncheckedEnc :: [EncAnn] -> c -> str -> UncheckedEnc c str getUncheckedEncAnn :: UncheckedEnc c str -> [EncAnn] getUncheckedPayload :: forall c str. UncheckedEnc c str -> str verifyAnn :: forall xs c str. SymbolList xs => UncheckedEnc c str -> Either String (UncheckedEnc c str) instance (GHC.Classes.Eq c, GHC.Classes.Eq str) => GHC.Classes.Eq (Data.TypedEncoding.Common.Types.UncheckedEnc.UncheckedEnc c str) instance (GHC.Show.Show c, GHC.Show.Show str) => GHC.Show.Show (Data.TypedEncoding.Common.Types.UncheckedEnc.UncheckedEnc c str) instance (GHC.Show.Show c, Data.TypedEncoding.Common.Class.Common.Displ str) => Data.TypedEncoding.Common.Class.Common.Displ (Data.TypedEncoding.Common.Types.UncheckedEnc.UncheckedEnc c str) -- | Contains main Enc type that carries encoded payload as well -- as Encoding and Encodings types contains encoding -- functions. This module also contains basic combinators for these -- types. -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Types.Enc -- | Contains encoded data annotated by -- --
-- Enc '["r-ASCII"] () ByteString --data Enc nms conf str -- | @since 0.3.0.0 renamed from MkEnc -- -- Use of this constructor should be kept to a minimum. -- -- Use of unsafeSetPayload currently recommended for recovering -- Enc from trusted input sources (if avoiding cost of -- Data.TypedEncoding.Common.Types.Validation is important). [UnsafeMkEnc] :: Proxy nms -> conf -> str -> Enc nms conf str toEncoding :: conf -> str -> Enc ('[] :: [Symbol]) conf str fromEncoding :: Enc '[] conf str -> str getPayload :: Enc enc conf str -> str getContent :: Enc enc conf str -> (conf, str) -- | Wraps the encoding function. Contains type level information about the -- encoding name and the algorithm used. -- -- This type is used by programs implementing encoding instance. Such -- program needs to define a value of this type. It also implements -- Encode instance that simply returns that value. -- -- Programs using encoding can access this type using encoding -- (from the Encode typeclass) but a better (and recommended) -- approach is to use its plural sibling Encodings defined below. -- -- This type has 2 symbol type variables: -- --
-- Encoding (Either EncodeEx) "r-ban:9" "r-ban" () String ---- -- encodes a single character <= 9' -- --
-- Encoding Identity "enc-B64" "enc-B64" () ByteString ---- -- Represents a Base 64 encoder that can operate on any stack of -- previous encodings. (encoding name and algorithm name are "enc-B64", -- there is no additional configuration () needed and it runs in -- the Identity Functor. -- -- Similar boilerplate for Decoding and Validation is -- specified in separate modules. data Encoding f (nm :: Symbol) (alg :: Symbol) conf str -- | Consider this constructor as private or use it with care -- -- Defining constructor like this: MkEncoding :: Proxy nm -> -- (forall (xs :: [Symbol]) . Enc xs conf str -> f (Enc (nm ': xs) -- conf str)) -> Encoding f nm (AlgNm nm) conf str -- -- would make compilation much slower [UnsafeMkEncoding] :: Proxy nm -> (forall (xs :: [Symbol]). Enc xs conf str -> f (Enc (nm : xs) conf str)) -> Encoding f nm alg conf str -- | Type safe smart constructor -- -- Adding the type family (AlgNm nm) mapping to -- Encoding constructor slows down the compilation. Using smart -- constructor does not have that issue. -- -- This approach also provides more future flexibility with possibility -- of future overloads relaxing current limitations on alg -- names. -- -- Notice underscore _ convention, it indicates a use of -- Algorithm AlgNm: compiler figures out alg -- value. These can be slower to compile when used. -- -- Here are other conventions that relate to the existence of -- alg -- --
-- >>> fmap displ (_runEncoding encFBan $ toEncoding () "000" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text)) -- Right "Enc '[r-ban:111] () (Text 000)" --_runEncoding :: forall nm f xs conf str alg. Algorithm nm alg => Encoding f nm alg conf str -> Enc xs conf str -> f (Enc (nm : xs) conf str) -- | HList like construction that defines a list of Encoding -- elements. -- -- This type is used by programs using / manipulating encodings. -- -- Can be easily accessed with EncodeAll constraint using -- encodings. But could also be used by creating -- Encodings list by hand. data Encodings f (nms :: [Symbol]) (algs :: [Symbol]) conf str [ZeroE] :: Encodings f '[] '[] conf str [ConsE] :: Encoding f nm alg conf str -> Encodings f nms algs conf str -> Encodings f (nm : nms) (alg : algs) conf str (-:-) :: Encoding f nm alg conf str -> Encodings f nms algs conf str -> Encodings f (nm : nms) (alg : algs) conf str infixr 5 -:- -- | Runs encodings, requires -XTypeApplication annotation specifying the -- algorithm(s) -- --
-- >>> runEncodings' @'["r-ban"] (encFBan -:- ZeroE) . toEncoding () $ "000" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text) -- Right (UnsafeMkEnc Proxy () "000") ---- -- Polymorphic access to encodings is provided by EncodeAll -- typeclass so we can simply write: -- --
-- >>> runEncodings' @'["r-ban"] encodings . toEncoding () $ "22" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text)
-- Left (EncodeEx "r-ban:111" ("Input list has wrong size expecting 3 but length \"22\" == 2"))
--
--
-- This library also offers backward compatible equivalents
-- encodeFAll to runEncodings functions (see
-- Data.TypedEncoding.Combinators.Encode) which are basically
-- equivalent to something like runEncoding' encoding
--
-- -- >>> encodeFAll' @'["r-ban"] . toEncoding () $ "111" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text) -- Right (UnsafeMkEnc Proxy () "111") ---- --
-- >>> fmap displ . encodeFAll' @'["r-ban"] @'["r-ban:111"] @(Either EncodeEx) @() @T.Text . toEncoding () $ "111" -- Right "Enc '[r-ban:111] () (Text 111)" --runEncodings' :: forall algs nms f c str. Monad f => Encodings f nms algs c str -> Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) -- | At a possibly some compilation cost, have compiler figure out -- algorithm names. -- --
-- >>> _runEncodings encodings . toEncoding () $ ("Hello World") :: Identity (Enc '["enc-B64","enc-B64"] () B.ByteString)
-- Identity (UnsafeMkEnc Proxy () "U0dWc2JHOGdWMjl5YkdRPQ==")
--
--
--
-- >>> _runEncodings encodings . toEncoding () $ ("22") :: Either EncodeEx (Enc '["r-ban:111"] () T.Text)
-- Left (EncodeEx "r-ban:111" ("Input list has wrong size expecting 3 but length \"22\" == 2"))
--
--
-- (see also _runEncoding) @since 0.3.0.0
_runEncodings :: forall nms f c str algs. (Monad f, algs ~ AlgNmMap nms) => Encodings f nms algs c str -> Enc ('[] :: [Symbol]) c str -> f (Enc nms c str)
instance forall k (nms :: k) conf str. (GHC.Classes.Eq conf, GHC.Classes.Eq str) => GHC.Classes.Eq (Data.TypedEncoding.Common.Types.Enc.Enc @{k} nms conf str)
instance forall k (nms :: k) conf str. (GHC.Show.Show conf, GHC.Show.Show str) => GHC.Show.Show (Data.TypedEncoding.Common.Types.Enc.Enc @{k} nms conf str)
instance (Data.TypedEncoding.Common.Class.Common.SymbolList xs, GHC.Show.Show c, Data.TypedEncoding.Common.Class.Common.Displ str) => Data.TypedEncoding.Common.Class.Common.Displ (Data.TypedEncoding.Common.Types.Enc.Enc @{[GHC.Types.Symbol]} xs c str)
-- | Internal definition of types
--
-- Validation types for Enc
--
-- See also
--
--
--
-- Use of unsafeSetPayload currently recommended for recovering
-- Enc from trusted input sources (if avoiding cost of Validation
-- is important).
--
-- This module is re-exported in Data.TypedEncoding and it is best
-- not to import it directly.
module Data.TypedEncoding.Common.Types.Validation
-- | Validation unwraps a layer of encoding and offers payload data down
-- the encoding stack for further verification.
--
-- For "enc-" encodings this will typically be decoding step.
--
-- For "r-" encodings this will typically be encoding step.
data Validation f (nm :: Symbol) (alg :: Symbol) conf str
[UnsafeMkValidation] :: Proxy nm -> (forall (xs :: [Symbol]). Enc (nm : xs) conf str -> f (Enc xs conf str)) -> Validation f nm alg conf str
-- | Type safe smart constructor adding the type family (AlgNm nm)
-- restriction to UnsafeMkValidation slows down compilation, especially
-- in tests.
-- | Deprecated: Use _mkValidation
mkValidation :: forall f (nm :: Symbol) conf str. (forall (xs :: [Symbol]). Enc (nm : xs) conf str -> f (Enc xs conf str)) -> Validation f nm (AlgNm nm) conf str
-- | Type safe smart constructor adding the type family (AlgNm nm)
-- restriction to UnsafeMkValidation slows down compilation, especially
-- in tests.
--
-- This function follows the naming convention of using "_" when the
-- typechecker figures out alg
_mkValidation :: forall f (nm :: Symbol) conf str. (forall (xs :: [Symbol]). Enc (nm : xs) conf str -> f (Enc xs conf str)) -> Validation f nm (AlgNm nm) conf str
runValidation :: forall nm f xs conf str. Validation f nm nm conf str -> Enc (nm : xs) conf str -> f (Enc xs conf str)
runValidation' :: forall alg nm f xs conf str. Validation f nm alg conf str -> Enc (nm : xs) conf str -> f (Enc xs conf str)
-- | Same as 'runValidation" but compiler figures out algorithm name
--
-- Using it can slowdown compilation
_runValidation :: forall nm f xs conf str alg. AlgNm nm ~ alg => Validation f nm alg conf str -> Enc (nm : xs) conf str -> f (Enc xs conf str)
-- | Wraps a list of Validation elements.
--
-- Similarly to Validation it can be used with a typeclass
-- EncodeAll
data Validations f (nms :: [Symbol]) (algs :: [Symbol]) conf str
-- | constructor is to be treated as Unsafe to Encode and Decode instance
-- implementations particular encoding instances may expose smart
-- constructors for limited data types
[ZeroV] :: Validations f '[] '[] conf str
[ConsV] :: Validation f nm alg conf str -> Validations f nms algs conf str -> Validations f (nm : nms) (alg : algs) conf str
-- | This basically puts payload in decoded state. More useful combinators
-- are in Data.TypedEncoding.Combinators.Validate
--
-- (runValidationChecks before v0.5)
runValidationChecks' :: forall algs nms f c str. Monad f => Validations f nms algs c str -> Enc nms c str -> f (Enc ('[] :: [Symbol]) c str)
-- | Decoding types for Enc
--
-- This module is re-exported in Data.TypedEncoding and it is best
-- not to import it directly.
module Data.TypedEncoding.Common.Types.Decoding
-- | Similar to Encoding
--
-- Wraps the decoding function.
--
-- Can be used with Decode type class.
--
-- Examples.TypedEncoding.Instances.DiySignEncoding contains an
-- implementation example.
--
-- Examples.TypedEncoding.Overview shows decoding usage examples.
data Decoding f (nm :: Symbol) (alg :: Symbol) conf str
-- | Consider this constructor as private or use it with care
--
-- Using that constructor: UnsafeMkDecoding :: Proxy nm ->
-- (forall (xs :: [Symbol]) . Enc (nm ': xs) conf str -> f (Enc xs
-- conf str)) -> Decoding f nm (AlgNm nm) conf str
--
-- would make compilation much slower
[UnsafeMkDecoding] :: Proxy nm -> (forall (xs :: [Symbol]). Enc (nm : xs) conf str -> f (Enc xs conf str)) -> Decoding f nm alg conf str
-- | Type safe smart constructor (See also _mkEncoding)
-- | Deprecated: Use _mkDecoding
mkDecoding :: forall f (nm :: Symbol) conf str. (forall (xs :: [Symbol]). Enc (nm : xs) conf str -> f (Enc xs conf str)) -> Decoding f nm (AlgNm nm) conf str
-- | Type safe smart constructor (See also _mkEncoding)
--
-- This function follows the naming convention of using "_" when the
-- typechecker figures out alg @since 0.5.0.0
_mkDecoding :: forall f (nm :: Symbol) conf str. (forall (xs :: [Symbol]). Enc (nm : xs) conf str -> f (Enc xs conf str)) -> Decoding f nm (AlgNm nm) conf str
-- | This function assumes mn ~ alg, making its type different
-- from previous (before v.0.5) versions.
runDecoding :: forall nm f xs conf str. Decoding f nm nm conf str -> Enc (nm : xs) conf str -> f (Enc xs conf str)
runDecoding' :: forall alg nm f xs conf str. Decoding f nm alg conf str -> Enc (nm : xs) conf str -> f (Enc xs conf str)
-- | Same as 'runDecoding" but compiler figures out algorithm name
--
-- Using it can slowdown compilation
_runDecoding :: forall nm f xs conf str alg. AlgNm nm ~ alg => Decoding f nm alg conf str -> Enc (nm : xs) conf str -> f (Enc xs conf str)
-- | Wraps a list of Decoding elements.
--
-- Similarly to Encodings can be used with a typeclass
-- DecodeAll
data Decodings f (nms :: [Symbol]) (algs :: [Symbol]) conf str
-- | constructor is to be treated as Unsafe to Encode and Decode instance
-- implementations particular encoding instances may expose smart
-- constructors for limited data types
[ZeroD] :: Decodings f '[] '[] conf str
[ConsD] :: Decoding f nm alg conf str -> Decodings f nms algs conf str -> Decodings f (nm : nms) (alg : algs) conf str
-- | This function assumes nms ~ algs, making its type different
-- from previous (before v.0.5) versions.
runDecodings :: forall nms f c str. Monad f => Decodings f nms nms c str -> Enc nms c str -> f (Enc ('[] :: [Symbol]) c str)
runDecodings' :: forall algs nms f c str. Monad f => Decodings f nms algs c str -> Enc nms c str -> f (Enc ('[] :: [Symbol]) c str)
-- | At possibly big compilation cost, have compiler figure out algorithm
-- names.
_runDecodings :: forall nms f c str algs. (Monad f, algs ~ AlgNmMap nms) => Decodings f nms algs c str -> Enc nms c str -> f (Enc ('[] :: [Symbol]) c str)
-- | Type classes accompanying decoding types defined in
-- Data.TypedEncoding.Common.Types.Enc
--
-- Examples.TypedEncoding.Instances.DiySignEncoding contains an
-- implementation example.
--
-- Examples.TypedEncoding.Overview shows decoding usage examples.
--
-- This module is re-exported in Data.TypedEncoding and it is best
-- not to import it directly.
module Data.TypedEncoding.Common.Class.Encode
-- | Allows for polymorphic access to encoding, for example
--
-- -- >>> displ (runIdentity . _runEncoding encoding $ toEncoding () "Hello" :: Enc '["enc-B64"] () B.ByteString) -- "Enc '[enc-B64] () (ByteString SGVsbG8=)" ---- -- Using 2 Symbol type variables (nm and alg) creates -- what seems like redundant typing in statically defined instances such -- as "r-ASCII", however it provides future flexibility to -- constrain nm in some interesting way, different than -- AlgNm nm ~ alg. -- -- It also seems to be easier to understand as type variables used in the -- definition of Encoding match with what is on the typeclass. -- -- alg is expected to be very statically defined and is needed -- to support more open instances such as "r-ban". class Encode f nm alg conf str encoding :: Encode f nm alg conf str => Encoding f nm alg conf str -- | Allows for polymorphic access to Encodings -- -- For example -- --
-- >>> displ (runIdentity . _runEncodings encodings $ toEncoding () "Hello" :: (Enc '["enc-B64", "enc-B64"] () B.ByteString)) -- "Enc '[enc-B64,enc-B64] () (ByteString U0dWc2JHOD0=)" ---- -- You can also use convenience functions like encodeAll class EncodeAll f nms algs conf str encodings :: EncodeAll f nms algs conf str => Encodings f nms algs conf str instance Data.TypedEncoding.Common.Class.Encode.EncodeAll f ('[] @GHC.Types.Symbol) ('[] @GHC.Types.Symbol) conf str instance (Data.TypedEncoding.Common.Class.Encode.EncodeAll f nms algs conf str, Data.TypedEncoding.Common.Class.Encode.Encode f nm alg conf str) => Data.TypedEncoding.Common.Class.Encode.EncodeAll f ((':) @GHC.Types.Symbol nm nms) ((':) @GHC.Types.Symbol alg algs) conf str -- | Basic unsafe operations on Enc module Data.TypedEncoding.Combinators.Unsafe -- | Currently this is the recommended way of recreating encoding from -- trusted input, if avoiding cost of -- Data.TypedEncoding.Common.Types.Validation is needed. unsafeSetPayload :: conf -> str -> Enc enc conf str withUnsafeCoerce :: (s1 -> s2) -> Enc e1 c s1 -> Enc e2 c s2 withUnsafeCoerceF :: forall e1 e2 f c s1 s2. Functor f => (s1 -> f s2) -> Enc e1 c s1 -> f (Enc e2 c s2) unsafeChangePayload :: (s1 -> s2) -> Enc e c s1 -> Enc e c s2 -- | Module defines CheckedEnc - untyped ADT version of Enc -- -- A more dependently typed approach would be to define SomeEnc GADT that -- accepts some Enc '[..] in its constructor. The approach here -- turns out to be isomorphic to SomeEnc approach. Both, -- however, yield somewhat different programming. -- -- Post v0.4 typed-encoding does not support SomeEnc and -- it remains only as an Example. -- -- See Examples.TypedEncoding.SomeEnc. -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Types.CheckedEnc -- | Represents some validated encoded string. -- -- CheckedEnc is untyped version of Enc. -- CheckedEnc contains verified encoded data, encoding is -- visible at the value level only. data CheckedEnc conf str -- | Constructor renamed from previous versions This constructor is -- considered unsafe as pattern matching on it and using it allows access -- to the encoded payload. UnsafeMkCheckedEnc :: [EncAnn] -> conf -> str -> CheckedEnc conf str unsafeCheckedEnc :: [EncAnn] -> c -> s -> CheckedEnc c s getCheckedPayload :: CheckedEnc conf str -> str getCheckedEncPayload :: CheckedEnc conf str -> ([EncAnn], str) toCheckedEnc :: forall xs c str. SymbolList xs => Enc xs c str -> CheckedEnc c str fromCheckedEnc :: forall xs c str. SymbolList xs => CheckedEnc c str -> Maybe (Enc xs c str) -- |
-- >>> let encsometest = UnsafeMkCheckedEnc ["TEST"] () $ T.pack "hello" -- -- >>> procToCheckedEncFromCheckedEnc @'["TEST"] encsometest -- True -- -- >>> procToCheckedEncFromCheckedEnc @'["TEST1"] encsometest -- False --procToCheckedEncFromCheckedEnc :: forall xs c str. (SymbolList xs, Eq c, Eq str) => CheckedEnc c str -> Bool -- |
-- >>> let enctest = unsafeSetPayload () "hello" :: Enc '["TEST"] () T.Text -- -- >>> procFromCheckedEncToCheckedEnc enctest -- True --procFromCheckedEncToCheckedEnc :: forall xs c str. (SymbolList xs, Eq c, Eq str) => Enc xs c str -> Bool instance (GHC.Classes.Eq conf, GHC.Classes.Eq str) => GHC.Classes.Eq (Data.TypedEncoding.Common.Types.CheckedEnc.CheckedEnc conf str) instance (GHC.Show.Show conf, GHC.Show.Show str) => GHC.Show.Show (Data.TypedEncoding.Common.Types.CheckedEnc.CheckedEnc conf str) instance (GHC.Show.Show c, Data.TypedEncoding.Common.Class.Common.Displ str) => Data.TypedEncoding.Common.Class.Common.Displ (Data.TypedEncoding.Common.Types.CheckedEnc.CheckedEnc c str) -- | Internal definition of types module Data.TypedEncoding.Common.Types -- | Unsafe ops inside encoding module Data.TypedEncoding.Common.Types.Unsafe -- | Allows to operate within Enc keeping the same list of -- encodings. -- -- These are considered unsafe. newtype Unsafe enc conf str Unsafe :: Enc enc conf str -> Unsafe enc conf str [runUnsafe] :: Unsafe enc conf str -> Enc enc conf str -- | @since 0.1.0. withUnsafe :: (Unsafe e c s1 -> Unsafe e c s2) -> Enc e c s1 -> Enc e c s2 instance forall k (enc :: k) conf str. (GHC.Show.Show conf, GHC.Show.Show str) => GHC.Show.Show (Data.TypedEncoding.Common.Types.Unsafe.Unsafe @{k} enc conf str) instance forall k (enc :: k) conf. GHC.Base.Functor (Data.TypedEncoding.Common.Types.Unsafe.Unsafe @{k} enc conf) instance forall k (enc :: k). GHC.Base.Applicative (Data.TypedEncoding.Common.Types.Unsafe.Unsafe @{k} enc ()) instance forall k (enc :: k). GHC.Base.Monad (Data.TypedEncoding.Common.Types.Unsafe.Unsafe @{k} enc ()) -- | Type classes accompanying decoding types defined in -- Data.TypedEncoding.Common.Types.Validation -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Class.Validate class Validate f nm alg conf str validation :: Validate f nm alg conf str => Validation f nm alg conf str class ValidateAll f nms algs conf str validations :: ValidateAll f nms algs conf str => Validations f nms algs conf str -- | Recovery errors are expected unless Recovery allows Identity instance class RecreateErr f recoveryErr :: RecreateErr f => RecreateEx -> f a asRecreateErr_ :: (RecreateErr f, Applicative f, Show err, KnownSymbol x) => Proxy x -> Either err a -> f a asRecreateErr :: forall x f err a. (RecreateErr f, Applicative f, Show err, KnownSymbol x) => Either err a -> f a instance Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.RecreateEx) instance Data.TypedEncoding.Common.Class.Validate.ValidateAll f ('[] @GHC.Types.Symbol) ('[] @GHC.Types.Symbol) conf str instance (Data.TypedEncoding.Common.Class.Validate.ValidateAll f nms algs conf str, Data.TypedEncoding.Common.Class.Validate.Validate f nm alg conf str) => Data.TypedEncoding.Common.Class.Validate.ValidateAll f ((':) @GHC.Types.Symbol nm nms) ((':) @GHC.Types.Symbol alg algs) conf str -- | Type classes accompanying decoding types defined in -- Data.TypedEncoding.Common.Types.Decoding -- -- Examples.TypedEncoding.Instances.DiySignEncoding contains an -- implementation example. -- -- Examples.TypedEncoding.Overview shows decoding usage examples. -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Class.Decode class Decode f nm alg conf str decoding :: Decode f nm alg conf str => Decoding f nm alg conf str class DecodeAll f nms algs conf str decodings :: DecodeAll f nms algs conf str => Decodings f nms algs conf str -- | With type safety in place decoding errors should be unexpected. This -- class can be used to provide extra info if decoding could fail class UnexpectedDecodeErr f unexpectedDecodeErr :: UnexpectedDecodeErr f => UnexpectedDecodeEx -> f a asUnexpected_ :: (KnownSymbol x, UnexpectedDecodeErr f, Applicative f, Show err) => Proxy x -> Either err a -> f a asUnexpected :: forall x f err a. (KnownSymbol x, UnexpectedDecodeErr f, Applicative f, Show err) => Either err a -> f a instance Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} Data.Functor.Identity.Identity instance Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.UnexpectedDecodeEx) instance Data.TypedEncoding.Common.Class.Decode.DecodeAll f ('[] @GHC.Types.Symbol) ('[] @GHC.Types.Symbol) conf str instance (Data.TypedEncoding.Common.Class.Decode.DecodeAll f nms algs conf str, Data.TypedEncoding.Common.Class.Decode.Decode f nm alg conf str) => Data.TypedEncoding.Common.Class.Decode.DecodeAll f ((':) @GHC.Types.Symbol nm nms) ((':) @GHC.Types.Symbol alg algs) conf str -- | This module contains typeclasses and type families that are used by -- typed-encoding to define subset / superset relationships -- between different encodings. -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Data.TypedEncoding.Common.Class.Superset -- | Replaces previous Superset typeclass. -- -- Subsets are useful for restriction encodings like r-UFT8 but should -- not be used for other encodings as this would be dangerous. For -- example, considering "enc-" encoding as a superset of "r-" encoding -- would permit converting encoded binary "Enc '["enc-"] c -- ByteString to "Enc '["r-ASCII"] c ByteString and then to -- "Enc '["r-ASCII"] c Text, which could result in runtime -- errors. -- -- The requirement is that that the decoding in the superset can replace -- the decoding from injected subset. -- -- IsSuperset bigger smaller reads as bigger is a -- superset of smaller -- -- Note, no IsSuperset "r-UNICODE.D76" "r-CHAR8" even though the numeric -- range of D76 includes all CHAR8 bytes. This is more nominal -- decision that prevents certain unwanted conversions from being -- possible. -- -- This is not fully transitive to conserve compilation cost. @since -- 0.2.2.0 type family IsSuperset (y :: Symbol) (x :: Symbol) :: Bool type family IsSupersetOpen (big :: Symbol) (nm :: Symbol) (alg :: Symbol) (nmltrs :: [Symbol]) :: Bool type Superset big small = (IsSuperset big small ~ 'True) -- |
-- >>> let Right tstAscii = encodeFAll . toEncoding () $ "Hello World" :: Either EncodeEx (Enc '["r-ASCII"] () T.Text) -- -- >>> displ (injectInto @"r-UTF8" tstAscii) -- "Enc '[r-UTF8] () (Text Hello World)" --injectInto :: forall y x xs c str. IsSuperset y x ~ 'True => Enc (x : xs) c str -> Enc (y : xs) c str -- | Deprecated: Use propSupersetCheck or propSuperset_ propSuperset' :: forall algb algs b s str. (Superset b s, Eq str) => Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) s algs () str -> str -> Bool propSuperset_ :: forall b s str algb algs. (Superset b s, Eq str, AlgNm b ~ algb, AlgNm s ~ algs) => Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) s algs () str -> str -> Bool -- | Test for Supersets defined in this module -- -- Actual tests in the project test suite. propSupersetCheck :: forall algb algs b s str. Eq str => Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) s algs () str -> str -> Bool -- | IsSuperset is not intended for "enc-" encodings. This class -- is. -- -- It allows to specify constraints that say, for example, that Base -- 64 encodes into a subset of ASCII. class EncodingSuperset (enc :: Symbol) where { type family EncSuperset enc :: Symbol; } -- | Warning: Using this method at the call site may not be backward -- compatible between minor version upgrades, use _encodesInto -- instead. implEncInto :: forall xs c str. EncodingSuperset enc => Enc (enc : xs) c str -> Enc (EncSuperset enc : (enc : xs)) c str _encodesInto :: forall y enc xs c str r. (IsSuperset y r ~ 'True, EncodingSuperset enc, r ~ EncSuperset enc) => Enc (enc : xs) c str -> Enc (y : (enc : xs)) c str propEncodesInto_ :: forall b r str algb algr. (EncodingSuperset b, r ~ EncSuperset b, Eq str, AlgNm b ~ algb, AlgNm r ~ algr) => Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) r algr () str -> str -> Bool -- | validates superset restriction -- -- Actual tests are in the project test suite. propEncodesIntoCheck :: forall algb algr b r str. Eq str => Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) r algr () str -> str -> Bool -- | Checks if first encoding exceptions less often than second (has bigger -- domain). propCompEncoding :: forall algb algr b r str. Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) r algr () str -> str -> Bool -- | Aggregate version of EncodingSuperset -- -- It is used to assure type safety of conversion functions in -- Data.TypedEncoding.Conv. This approach is not ideal since it -- produces an overly conservative restriction on encoding stack. -- -- The issue is that this enforces restriction on the co-domain or each -- encoding and it does not take into account the fact that the domain is -- already restricted, e.g. it will prevent adding id transformation to -- the stack. class AllEncodeInto (superset :: Symbol) (encnms :: [Symbol]) tstChar8Encodable :: forall nms. AllEncodeInto "r-CHAR8" nms => String tstD76Encodable :: forall nms. AllEncodeInto "r-UNICODE.D76" nms => String tstUTF8Encodable :: forall nms. AllEncodeInto "r-UTF8" nms => String instance Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-CHAR8" ('[] @GHC.Types.Symbol) instance (Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-CHAR8" xs, (Data.TypedEncoding.Common.Class.Superset.IsSuperset "r-CHAR8" r :: GHC.Types.Bool) GHC.Types.~ ('GHC.Types.True :: GHC.Types.Bool), Data.TypedEncoding.Common.Class.Superset.EncodingSuperset enc, (r :: GHC.Types.Symbol) GHC.Types.~ (Data.TypedEncoding.Common.Class.Superset.EncSuperset enc :: GHC.Types.Symbol)) => Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-CHAR8" ((':) @GHC.Types.Symbol enc xs) instance Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-UNICODE.D76" ('[] @GHC.Types.Symbol) instance (Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-UNICODE.D76" xs, (Data.TypedEncoding.Common.Class.Superset.IsSuperset "r-UNICODE.D76" r :: GHC.Types.Bool) GHC.Types.~ ('GHC.Types.True :: GHC.Types.Bool), Data.TypedEncoding.Common.Class.Superset.EncodingSuperset enc, (r :: GHC.Types.Symbol) GHC.Types.~ (Data.TypedEncoding.Common.Class.Superset.EncSuperset enc :: GHC.Types.Symbol)) => Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-UNICODE.D76" ((':) @GHC.Types.Symbol enc xs) instance Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-UTF8" ('[] @GHC.Types.Symbol) instance (Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-UTF8" xs, (Data.TypedEncoding.Common.Class.Superset.IsSuperset "r-UTF8" r :: GHC.Types.Bool) GHC.Types.~ ('GHC.Types.True :: GHC.Types.Bool), Data.TypedEncoding.Common.Class.Superset.EncodingSuperset enc, (r :: GHC.Types.Symbol) GHC.Types.~ (Data.TypedEncoding.Common.Class.Superset.EncSuperset enc :: GHC.Types.Symbol)) => Data.TypedEncoding.Common.Class.Superset.AllEncodeInto "r-UTF8" ((':) @GHC.Types.Symbol enc xs) module Data.TypedEncoding.Common.Class -- | Flatten is a more permissive IsSuperset instance FlattenAs -- "r-ASCII" "enc-B64" where -- -- Now encoded data has form Enc '["r-ASCII"] c str and there is -- no danger of it begin incorrectly decoded. class FlattenAs (y :: Symbol) (x :: Symbol) flattenAs :: FlattenAs y x => Enc (x : xs) c str -> Enc '[y] c str -- | Reverse of ToEncString decodes encoded string back to -- a class (KnownSymbol nm, KnownSymbol ann) => FromEncString f nm ann a str fromEncF :: FromEncString f nm ann a str => Enc '[nm] () str -> f a -- | Generalized Java toString or a type safe version of Haskell's -- Show. -- -- Encodes a as Enc '[xs] specifying algorithm -- alg and using effect f class (KnownSymbol nm, KnownSymbol ann) => ToEncString f nm ann a str toEncF :: ToEncString f nm ann a str => a -> f (Enc '[nm] () str) -- | v0.2 like (backward compatible) combinators for covering to and from -- encoded string. module Data.TypedEncoding.Combinators.ToEncStr toEncStringF :: forall nm f a str. ToEncString f nm nm a str => a -> f (Enc '[nm] () str) toEncStringF' :: forall alg nm f a str. ToEncString f nm alg a str => a -> f (Enc '[nm] () str) toEncString :: forall nm a str. ToEncString Identity nm nm a str => a -> Enc '[nm] () str toEncString' :: forall alg nm a str. ToEncString Identity nm alg a str => a -> Enc '[nm] () str fromEncStringF :: forall nm f a str. FromEncString f nm nm a str => Enc '[nm] () str -> f a fromEncStringF' :: forall alg nm f a str. FromEncString f nm alg a str => Enc '[nm] () str -> f a fromEncString :: forall nm a str. FromEncString Identity nm nm a str => Enc '[nm] () str -> a fromEncString' :: forall alg nm a str. FromEncString Identity nm alg a str => Enc '[nm] () str -> a -- | Combinators allowing to add or remove redundant annotations. Such -- operations are referred to in this package as promoting or demoting. module Data.TypedEncoding.Combinators.Promotion -- | Remove redundant superset right after the top (at second last encoding -- position) -- --
-- >>> displ $ demoteFlattenTop (unsafeSetPayload () "" :: Enc '["r-ASCII", "r-UTF8", "r-boo"] () T.Text) -- "Enc '[r-ASCII,r-boo] () (Text )" --demoteFlattenTop :: forall y x xs c str. IsSuperset y x ~ 'True => Enc (x : (y : xs)) c str -> Enc (x : xs) c str -- | add redundant superset right after -- --
-- >>> displ $ promoteUnFlattenTop @"r-UTF8" (unsafeSetPayload () "" :: Enc '["r-ASCII", "r-boo"] () T.Text) -- "Enc '[r-ASCII,r-UTF8,r-boo] () (Text )" --promoteUnFlattenTop :: forall y x xs c str. IsSuperset y x ~ 'True => Enc (x : xs) c str -> Enc (x : (y : xs)) c str -- | remove redunant superset from the top (at last applied encoding -- position) -- --
-- >>> displ $ demoteRemoveTop (unsafeSetPayload () "" :: Enc '["r-UTF8", "r-ASCII", "r-boo"] () T.Text) -- "Enc '[r-ASCII,r-boo] () (Text )" --demoteRemoveTop :: forall y x xs c str. IsSuperset y x ~ 'True => Enc (y : (x : xs)) c str -> Enc (x : xs) c str -- | add redundant superset at the top -- --
-- >>> displ $ promoteAddTop @"r-UTF8" (unsafeSetPayload () "" :: Enc '["r-ASCII", "r-boo"] () T.Text) -- "Enc '[r-UTF8,r-ASCII,r-boo] () (Text )" --promoteAddTop :: forall y x xs c str. IsSuperset y x ~ 'True => Enc (x : xs) c str -> Enc (y : (x : xs)) c str -- | remove redundant superset at bottom (first encoding) position -- --
-- >>> displ $ demoteRemoveBot (unsafeSetPayload () "" :: Enc '["r-boo", "r-ASCII", "r-UTF8"] () T.Text) -- "Enc '[r-boo,r-ASCII] () (Text )" --demoteRemoveBot :: (UnSnoc xs ~ '(,) ys y, UnSnoc ys ~ '(,) zs x, IsSuperset y x ~ 'True) => Enc xs c str -> Enc ys c str -- | add redundant superset at bottom (first encoding) position -- --
-- >>> displ $ promoteAddBot @"r-UTF8" (unsafeSetPayload () "" :: Enc '["r-boo", "r-ASCII"] () T.Text) -- "Enc '[r-boo,r-ASCII,r-UTF8] () (Text )" --promoteAddBot :: forall y x xs c str ys. (UnSnoc xs ~ '(,) ys x, IsSuperset y x ~ 'True) => Enc xs c str -> Enc (Snoc xs y) c str -- | remove redundant superset at second bottom (second encoding) position -- --
-- >>> displ $ demoteFlattenBot (unsafeSetPayload () "" :: Enc '["r-boo", "r-UTF8", "r-ASCII"] () T.Text) -- "Enc '[r-boo,r-ASCII] () (Text )" --demoteFlattenBot :: (UnSnoc xs ~ '(,) ys x, UnSnoc ys ~ '(,) zs y, IsSuperset y x ~ 'True) => Enc xs c str -> Enc (Snoc zs x) c str -- | add redundant superset at second bottom (second encoding) position -- --
-- >>> displ $ promoteUnFlattenBot @"r-UTF8" (unsafeSetPayload () "" :: Enc '["r-boo", "r-ASCII"] () T.Text) -- "Enc '[r-boo,r-UTF8,r-ASCII] () (Text )" --promoteUnFlattenBot :: forall y x xs c str ys. (UnSnoc xs ~ '(,) ys x, IsSuperset y x ~ 'True) => Enc xs c str -> Enc (Snoc (Snoc ys y) x) c str -- | Common encoding combinators. This module is re-exported in -- Data.TypedEncoding module Data.TypedEncoding.Combinators.Common -- | Any valid transformation of encodings (encoding decoding -- recreation) can be replayed on top of another encoding stack. -- -- This subsumes various encodePart, decodePart, recreatePart -- combinators. aboveF :: forall (ts :: [Symbol]) xs ys f c str. Functor f => (Enc xs c str -> f (Enc ys c str)) -> Enc (Append xs ts) c str -> f (Enc (Append ys ts) c str) above :: forall (ts :: [Symbol]) xs ys c str. (Enc xs c str -> Enc ys c str) -> Enc (Append xs ts) c str -> Enc (Append ys ts) c str getTransformF :: forall e1 e2 f c s1 s2. Functor f => (Enc e1 c s1 -> f (Enc e2 c s2)) -> c -> s1 -> f s2 -- | Validation combinators that are backward compatible to v0.2 versions. -- This module is re-exported in Data.TypedEncoding. module Data.TypedEncoding.Combinators.Validate -- | Maybe signals annotation mismatch, effect f is not evaluated -- unless there is match checkWithValidations :: forall algs (nms :: [Symbol]) f c str. (Monad f, SymbolList nms) => Validations f nms algs c str -> UncheckedEnc c str -> Maybe (f (Enc nms c str)) check :: forall (nms :: [Symbol]) f c str. (Monad f, ValidateAll f nms nms c str, SymbolList nms) => UncheckedEnc c str -> Maybe (f (Enc nms c str)) check' :: forall algs (nms :: [Symbol]) f c str. (Monad f, ValidateAll f nms algs c str, SymbolList nms) => UncheckedEnc c str -> Maybe (f (Enc nms c str)) recreateWithValidations :: forall algs nms f c str. Monad f => Validations f nms algs c str -> Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) recreateFAll :: forall nms f c str. (Monad f, ValidateAll f nms nms c str) => Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) recreateAll :: forall nms c str. ValidateAll Identity nms nms c str => Enc ('[] :: [Symbol]) c str -> Enc nms c str recreateFPart :: forall xs xsf f c str. (Monad f, ValidateAll f xs xs c str) => Enc xsf c str -> f (Enc (Append xs xsf) c str) recreateFAll' :: forall algs nms f c str. (Monad f, ValidateAll f nms algs c str) => Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) recreateAll' :: forall algs nms c str. ValidateAll Identity nms algs c str => Enc ('[] :: [Symbol]) c str -> Enc nms c str recreateFPart' :: forall algs xs xsf f c str. (Monad f, ValidateAll f xs algs c str) => Enc xsf c str -> f (Enc (Append xs xsf) c str) recreatePart' :: forall algs xs xsf c str. ValidateAll Identity xs algs c str => Enc xsf c str -> Enc (Append xs xsf) c str -- | Combinators reexported in Data.TypedEncoding. -- -- Decoding combinators that are backward compatible to v0.2 versions. module Data.TypedEncoding.Combinators.Encode encodeF :: forall nm xs f c str. Encode f nm nm c str => Enc xs c str -> f (Enc (nm : xs) c str) encodeFAll :: forall nms f c str. (Monad f, EncodeAll f nms nms c str) => Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) encodeAll :: forall nms c str. EncodeAll Identity nms nms c str => Enc ('[] :: [Symbol]) c str -> Enc nms c str encodeFPart :: forall xs xsf f c str. (Monad f, EncodeAll f xs xs c str) => Enc xsf c str -> f (Enc (Append xs xsf) c str) encodePart :: forall xs xsf c str. EncodeAll Identity xs xs c str => Enc xsf c str -> Enc (Append xs xsf) c str encodeF' :: forall alg nm xs f c str. Encode f nm alg c str => Enc xs c str -> f (Enc (nm : xs) c str) encodeFAll' :: forall algs nms f c str. (Monad f, EncodeAll f nms algs c str) => Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) encodeAll' :: forall algs nms c str. EncodeAll Identity nms algs c str => Enc ('[] :: [Symbol]) c str -> Enc nms c str encodeFPart' :: forall algs xs xsf f c str. (Monad f, EncodeAll f xs algs c str) => Enc xsf c str -> f (Enc (Append xs xsf) c str) encodePart' :: forall algs xs xsf c str. EncodeAll Identity xs algs c str => Enc xsf c str -> Enc (Append xs xsf) c str -- | Experimental features, slow to compile when used. module Data.TypedEncoding.Combinators.Encode.Experimental _encodeF :: forall nm xs f c str alg. (Encode f nm alg c str, alg ~ AlgNm nm) => Enc xs c str -> f (Enc (nm : xs) c str) _encodeFAll :: forall nms f c str algs. (Monad f, EncodeAll f nms algs c str, algs ~ AlgNmMap nms) => Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) _encodeAll :: forall nms c str algs. (EncodeAll Identity nms algs c str, algs ~ AlgNmMap nms) => Enc ('[] :: [Symbol]) c str -> Enc nms c str _encodeFPart :: forall xs xsf f c str algs. (Monad f, EncodeAll f xs algs c str, algs ~ AlgNmMap xs) => Enc xsf c str -> f (Enc (Append xs xsf) c str) _encodePart :: forall xs xsf c str algs. (EncodeAll Identity xs algs c str, algs ~ AlgNmMap xs) => Enc xsf c str -> Enc (Append xs xsf) c str -- | Combinators reexported in Data.TypedEncoding. -- -- Decoding combinators that are backward compatible to v0.2 versions. module Data.TypedEncoding.Combinators.Decode decodeF :: forall nm xs f c str. Decode f nm nm c str => Enc (nm : xs) c str -> f (Enc xs c str) decodeFAll :: forall nms f c str. (Monad f, DecodeAll f nms nms c str) => Enc nms c str -> f (Enc ('[] :: [Symbol]) c str) decodeAll :: forall nms c str. DecodeAll Identity nms nms c str => Enc nms c str -> Enc ('[] :: [Symbol]) c str decodeFPart :: forall xs xsf f c str. (Monad f, DecodeAll f xs xs c str) => Enc (Append xs xsf) c str -> f (Enc xsf c str) decodePart :: forall xs xsf c str. DecodeAll Identity xs xs c str => Enc (Append xs xsf) c str -> Enc xsf c str decodeF' :: forall alg nm xs f c str. Decode f nm alg c str => Enc (nm : xs) c str -> f (Enc xs c str) decodeFAll' :: forall algs nms f c str. (Monad f, DecodeAll f nms algs c str) => Enc nms c str -> f (Enc ('[] :: [Symbol]) c str) decodeAll' :: forall algs nms c str. DecodeAll Identity nms algs c str => Enc nms c str -> Enc ('[] :: [Symbol]) c str decodeFPart' :: forall algs xs xsf f c str. (Monad f, DecodeAll f xs algs c str) => Enc (Append xs xsf) c str -> f (Enc xsf c str) decodePart' :: forall algs xs xsf c str. DecodeAll Identity xs algs c str => Enc (Append xs xsf) c str -> Enc xsf c str -- |
-- -- Base 64 encoded bytes (could represent binary files) -- Enc '["enc-B64"] () ByteString -- -- -- Base 64 encoded UTF8 bytes -- Enc '["enc-B64", "r-UTF8"] () ByteString -- -- -- Text that contains only ASCII characters -- Enc '["r-ASCII"] () Text ---- -- or to do transformations to strings like -- --
-- upper :: Text -> Enc '["do-UPPER"] c Text -- upper = ... ---- -- or to define precise types to use with toEncString and -- fromEncString -- --
-- date :: Enc '["r-date-%d%b%Y:%X %Z"] () Text -- date = toEncString ... ---- -- Primary focus of type-encodings is to provide type safe -- --
-- Enc '["r-ASCII"] () ByteString --data Enc nms conf str toEncoding :: conf -> str -> Enc ('[] :: [Symbol]) conf str fromEncoding :: Enc '[] conf str -> str getPayload :: Enc enc conf str -> str -- | Wraps the encoding function. Contains type level information about the -- encoding name and the algorithm used. -- -- This type is used by programs implementing encoding instance. Such -- program needs to define a value of this type. It also implements -- Encode instance that simply returns that value. -- -- Programs using encoding can access this type using encoding -- (from the Encode typeclass) but a better (and recommended) -- approach is to use its plural sibling Encodings defined below. -- -- This type has 2 symbol type variables: -- --
-- Encoding (Either EncodeEx) "r-ban:9" "r-ban" () String ---- -- encodes a single character <= 9' -- --
-- Encoding Identity "enc-B64" "enc-B64" () ByteString ---- -- Represents a Base 64 encoder that can operate on any stack of -- previous encodings. (encoding name and algorithm name are "enc-B64", -- there is no additional configuration () needed and it runs in -- the Identity Functor. -- -- Similar boilerplate for Decoding and Validation is -- specified in separate modules. data Encoding f (nm :: Symbol) (alg :: Symbol) conf str -- | Consider this constructor as private or use it with care -- -- Defining constructor like this: MkEncoding :: Proxy nm -> -- (forall (xs :: [Symbol]) . Enc xs conf str -> f (Enc (nm ': xs) -- conf str)) -> Encoding f nm (AlgNm nm) conf str -- -- would make compilation much slower [UnsafeMkEncoding] :: Proxy nm -> (forall (xs :: [Symbol]). Enc xs conf str -> f (Enc (nm : xs) conf str)) -> Encoding f nm alg conf str -- | Type safe smart constructor -- -- Adding the type family (AlgNm nm) mapping to -- Encoding constructor slows down the compilation. Using smart -- constructor does not have that issue. -- -- This approach also provides more future flexibility with possibility -- of future overloads relaxing current limitations on alg -- names. -- -- Notice underscore _ convention, it indicates a use of -- Algorithm AlgNm: compiler figures out alg -- value. These can be slower to compile when used. -- -- Here are other conventions that relate to the existence of -- alg -- --
-- >>> fmap displ (_runEncoding encFBan $ toEncoding () "000" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text)) -- Right "Enc '[r-ban:111] () (Text 000)" --_runEncoding :: forall nm f xs conf str alg. Algorithm nm alg => Encoding f nm alg conf str -> Enc xs conf str -> f (Enc (nm : xs) conf str) -- | Version of runEncoding' function specialized to empty -- encoding runEncoding1' :: forall alg nm f conf str. Encoding f nm alg conf str -> Enc ('[] :: [Symbol]) conf str -> f (Enc '[nm] conf str) -- | HList like construction that defines a list of Encoding -- elements. -- -- This type is used by programs using / manipulating encodings. -- -- Can be easily accessed with EncodeAll constraint using -- encodings. But could also be used by creating -- Encodings list by hand. data Encodings f (nms :: [Symbol]) (algs :: [Symbol]) conf str [ZeroE] :: Encodings f '[] '[] conf str [ConsE] :: Encoding f nm alg conf str -> Encodings f nms algs conf str -> Encodings f (nm : nms) (alg : algs) conf str -- | Runs encodings, requires -XTypeApplication annotation specifying the -- algorithm(s) -- --
-- >>> runEncodings' @'["r-ban"] (encFBan -:- ZeroE) . toEncoding () $ "000" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text) -- Right (UnsafeMkEnc Proxy () "000") ---- -- Polymorphic access to encodings is provided by EncodeAll -- typeclass so we can simply write: -- --
-- >>> runEncodings' @'["r-ban"] encodings . toEncoding () $ "22" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text)
-- Left (EncodeEx "r-ban:111" ("Input list has wrong size expecting 3 but length \"22\" == 2"))
--
--
-- This library also offers backward compatible equivalents
-- encodeFAll to runEncodings functions (see
-- Data.TypedEncoding.Combinators.Encode) which are basically
-- equivalent to something like runEncoding' encoding
--
-- -- >>> encodeFAll' @'["r-ban"] . toEncoding () $ "111" :: Either EncodeEx (Enc '["r-ban:111"] () T.Text) -- Right (UnsafeMkEnc Proxy () "111") ---- --
-- >>> fmap displ . encodeFAll' @'["r-ban"] @'["r-ban:111"] @(Either EncodeEx) @() @T.Text . toEncoding () $ "111" -- Right "Enc '[r-ban:111] () (Text 111)" --runEncodings' :: forall algs nms f c str. Monad f => Encodings f nms algs c str -> Enc ('[] :: [Symbol]) c str -> f (Enc nms c str) -- | At a possibly some compilation cost, have compiler figure out -- algorithm names. -- --
-- >>> _runEncodings encodings . toEncoding () $ ("Hello World") :: Identity (Enc '["enc-B64","enc-B64"] () B.ByteString)
-- Identity (UnsafeMkEnc Proxy () "U0dWc2JHOGdWMjl5YkdRPQ==")
--
--
--
-- >>> _runEncodings encodings . toEncoding () $ ("22") :: Either EncodeEx (Enc '["r-ban:111"] () T.Text)
-- Left (EncodeEx "r-ban:111" ("Input list has wrong size expecting 3 but length \"22\" == 2"))
--
--
-- (see also _runEncoding) @since 0.3.0.0
_runEncodings :: forall nms f c str algs. (Monad f, algs ~ AlgNmMap nms) => Encodings f nms algs c str -> Enc ('[] :: [Symbol]) c str -> f (Enc nms c str)
-- | Main property that encodings are expected to enforce.
--
-- Decoding is safe and can use Identity instance of
-- UnexpectedDecodeErr.
--
-- Errors are handled during the encoding phase.
propSafeDecoding' :: forall alg nm c str. (Eq c, Eq str) => Encoding (Either EncodeEx) nm alg c str -> Decoding (Either UnexpectedDecodeEx) nm alg c str -> c -> str -> Bool
_propSafeDecoding :: forall nm c str alg. (Algorithm nm alg, Eq c, Eq str) => Encoding (Either EncodeEx) nm alg c str -> Decoding (Either UnexpectedDecodeEx) nm alg c str -> c -> str -> Bool
-- | Similar to propSafeDecoding' but Validation based.
-- Validation acts as Decoding recovering original payload
-- value. Recovering with validation keeps the encoded value and that
-- value is supposed to decode without error.
--
-- Expects input of encoded values
propSafeValidatedDecoding' :: forall alg nm c str. (Eq c, Eq str) => Validation (Either RecreateEx) nm alg c str -> Decoding (Either UnexpectedDecodeEx) nm alg c str -> c -> str -> Bool
_propSafeValidatedDecoding :: forall nm c str alg. (Algorithm nm alg, Eq c, Eq str) => Validation (Either RecreateEx) nm alg c str -> Decoding (Either UnexpectedDecodeEx) nm alg c str -> c -> str -> Bool
-- | Allows for polymorphic access to encoding, for example
--
-- -- >>> displ (runIdentity . _runEncoding encoding $ toEncoding () "Hello" :: Enc '["enc-B64"] () B.ByteString) -- "Enc '[enc-B64] () (ByteString SGVsbG8=)" ---- -- Using 2 Symbol type variables (nm and alg) creates -- what seems like redundant typing in statically defined instances such -- as "r-ASCII", however it provides future flexibility to -- constrain nm in some interesting way, different than -- AlgNm nm ~ alg. -- -- It also seems to be easier to understand as type variables used in the -- definition of Encoding match with what is on the typeclass. -- -- alg is expected to be very statically defined and is needed -- to support more open instances such as "r-ban". class Encode f nm alg conf str encoding :: Encode f nm alg conf str => Encoding f nm alg conf str -- | Allows for polymorphic access to Encodings -- -- For example -- --
-- >>> displ (runIdentity . _runEncodings encodings $ toEncoding () "Hello" :: (Enc '["enc-B64", "enc-B64"] () B.ByteString)) -- "Enc '[enc-B64,enc-B64] () (ByteString U0dWc2JHOD0=)" ---- -- You can also use convenience functions like encodeAll class EncodeAll f nms algs conf str encodings :: EncodeAll f nms algs conf str => Encodings f nms algs conf str -- | Conversion combinator module structure is similar to one found in -- text and bytestring packages And can be found nested -- under this module: -- --
-- import qualified Data.Text as T -- import qualified Data.ByteString.Char8 as B8 -- import qualified Data.Text.Encoding as TE -- -- T.pack :: String -> T.Text -- T.unpack :: T.Text -> String -- B8.pack :: String -> B8.ByteString -- B8.unpack :: B8.ByteString -> String -- TE.decodeUtf8 :: B8.ByteString -> T.Text -- TE.encodeUtf8 :: T.Text -> B8.ByteString ---- -- They come in pairs but are not reversible. -- -- Going from A to C depends on B, none of the following 4 diagrams -- commutes: -- --
-- String -> B8.pack -> ByteString -- ^ ^ | -- | | TE.decodeUtf8 -- id | | -- | TE.encodeUtf8 | -- v | v -- String -> T.pack -> Text ---- --
-- String <- B8.unpack <- ByteString -- ^ ^ | -- | | TE.decodeUtf8 -- id | | -- | TE.encodeUtf8 | -- v | v -- String <- T.unpack <- Text ---- -- All of this can lead to bugs that are hard to find and hard to -- troubleshoot. -- -- typed-encoding provides more precise types so that all of this -- goes away. -- -- Here are the type signatures simplified to one single encoding -- annotation: -- --
-- import qualified Data.TypedEncoding.Conv.Text as ET -- import qualified Data.TypedEncoding.Conv.ByteString.Char8 as EB8 -- import qualified Data.TypedEncoding.Conv.Text.Encoding as ETE -- -- ET.pack :: (Superset "r-UNICODE.D76" r) => Enc '[r] c String -> Enc '[r] c T.Text -- ET.unpack :: (Superset "r-UNICODE.D76" r) => Enc '[r] c T.Text -> Enc '[r] c String -- EB8.pack :: (Superset "r-CHAR8" r) => Enc '[r] c String -> Enc '[r] c B8.ByteString -- EB8.unpack :: (Superset "r-CHAR8" r) => Enc '[r] c B8.ByteString -> Enc '[r] c String -- ETE.decodeUtf8 :: (Superset "r-UTF8" r) => Enc '[r] c B8.ByteString -> Enc '[r] c T.Text -- ETE.encodeUtf8 :: (Superset "r-UTF8" r) => Enc '[r] c T.Text -> Enc '[r] c B8.ByteString ---- -- "r-UNICODE.D76" and "r-UTF8" is considered redundant -- for T.Text and can be added or dropped as needed. -- -- (This library currently assumes that "r-UTF8" includes the -- UNICODE.D76 restriction. This works well with assumptions made by -- Text). -- -- Corresponding pairs reverse, this should be clear since the types are -- restricted to what T.Text can store or to how -- B8.Char works. -- -- Now consider any of the above diagrams, for instance, compare -- --
-- ETE.encodeUtf8 . ET.pack :: (Superset "r-UNICODE.D76" r, Superset "r-UTF8" r) => Enc '[r] c String -> Enc '[r] c B8.ByteString -- -- and -- EB8.pack :: (Superset "r-CHAR8" r) => Enc '[r] c String -> Enc '[r] c B8.ByteString ---- -- What is the set of common values allowing us to use any of these 2 -- options? -- -- "r-UNICODE.D76" is not important here (it removes a range of Unicode -- values way above '255'), what is the intersection of -- UTF8 and CHAR8 code point space? -- -- There are many character set encodings that utilize one byte -- (CHAR8) and UTF8 is different from all of them but it -- backward compatible only within the ASCII range of chars -- < 127. So the intersection should be ASCII, let us -- check that: -- --
-- ghci> :t ETE.encodeUtf8 . ET.pack '["r-ASCII"]
-- EncTe.encodeUtf8 . EncT.pack '["r-ASCII"]
-- :: Enc Symbol Symbol "r-ASCII" ('[] Symbol)) c String
-- -> Enc Symbol Symbol "r-ASCII" ('[] Symbol)) c B8.ByteString
--
-- ghci> :t EB8.pack @'["r-ASCII"]
-- :: Enc Symbol Symbol "r-ASCII" ('[] Symbol)) c String
-- -> Enc Symbol Symbol "r-ASCII" ('[] Symbol)) c B8.ByteString
--
--
-- They both accept that common denominator. Now we could run a property
-- test but it is clear that by the design these will match!
--
-- Note, there is no Superset "r-UNICODE.D76" "r-CHAR8" mapping,
-- "r-CHAR8" supersets any 8-bit encoding like ISOIEC 8859/ family
-- of encodings. This is by design even if structurally such definition
-- would made sense.
--
-- This choice effectively prevents anything classified under
-- "r-CHAR8" to end up as a visible encoding annotation in
-- Text (since that would made little sense as Text is
-- UTF encoded). This is just one example of added type level
-- security that type-encoding provides.
--
-- Currently, "r-CHAR8" is intended as upper bound on "r-" encodings
-- only. There is no way to encode to it using provided encoding
-- mechanisms (except for unsafe options). Effectively the types
--
-- -- Enc "r-CHAR8" c str ---- -- can be viewed as uninhabited. -- -- However, Char is often used instead of Word8 for low -- level ByteString programming. This is supported with the -- "r-ByteRep" annotation. -- --
-- Enc "r-ByteRep" c str ---- -- this one can be used as Superset "r-CHAR8" "r-ByteRep"! That -- allows for EncB8 conversions to work on such data. However, -- there is no Superset "r-UNICODE.D76" "r-ByteRep" so these -- cannot be converted to Text, which is exactly what is -- intended. -- --
-- >>> 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")))
--
_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
-- | Defines new encoding by specifying 2 encodings, both needs to succeed
-- and produce the same payload.
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 :: 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
-- | -- >>> 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'")))
--
_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
-- | Defines new encoding which succeeds only if specified encoding fails.
-- It that happens, it applies given transformation function.
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 :: forall nm nm1 c str. KnownSymbol nm => (str -> str) -> Encoding (Either EncodeEx) nm1 nm1 c str -> Encoding (Either EncodeEx) nm nm c str
_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
-- | 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"))
--
_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
-- | Various helper functions. There are mostly for for creating
-- ToEncString and FromEncString instances
module Data.TypedEncoding.Instances.Support.Helpers
-- | allows to fold payload in Enc to create another Enc, assumes
-- homogeneous input encodings. This yields not a type safe code, better
-- implementation code should use fixed size dependently typed Vect
-- n or some HList like foldable.
foldEnc :: forall (xs2 :: [Symbol]) (xs1 :: [Symbol]) f c s1 s2. (Foldable f, Functor f) => c -> (s1 -> s2 -> s2) -> s2 -> f (Enc xs1 c s1) -> Enc xs2 c s2
-- | Similar to foldEnc, works with untyped CheckedEnc
foldCheckedEnc :: forall (xs2 :: [Symbol]) f c s1 s2. (Foldable f, Functor f) => c -> ([EncAnn] -> s1 -> s2 -> s2) -> s2 -> f (CheckedEnc c s1) -> Enc xs2 c s2
-- | Splits composite payload into homogeneous chunks
splitPayload :: forall (xs2 :: [Symbol]) (xs1 :: [Symbol]) c s1 s2. (s1 -> [s2]) -> Enc xs1 c s1 -> [Enc xs2 c s2]
-- | Untyped version of splitPayload
--
-- (renamed from splitCheckedPayload in previous versions)
-- @since 0.5.0.0
splitCheckedPayload :: forall c s1 s2. ([EncAnn] -> s1 -> [([EncAnn], s2)]) -> CheckedEnc c s1 -> [CheckedEnc c s2]
-- | sometimes show . read is not identity, eg. Word8:
--
-- -- >>> read "256" :: Word8 -- 0 ---- --
-- >>> verifyWithRead @Word8 "Word8-decimal" (T.pack "256") -- Left "Payload does not satisfy format Word8-decimal: 256" ---- --
-- >>> verifyWithRead @Word8 "Word8-decimal" (T.pack "123") -- Right "123" --verifyWithRead :: forall a str. (IsStringR str, Read a, Show a) => String -> str -> Either String str -- | Convenience function for checking if str decodes without -- error using dec encoding markers and decoders that can pick -- decoder based on that marker verifyDynEnc :: forall s str err1 err2 dec a. (KnownSymbol s, Show err1, Show err2) => Proxy s -> (Proxy s -> Either err1 dec) -> (dec -> str -> Either err2 a) -> str -> Either EncodeEx str -- | Direct use of these methods is discouraged. Use -- Data.TypedEncoding.Instances.Support.Encode or -- Data.TypedEncoding.Instances.Support.Decode instead. module Data.TypedEncoding.Instances.Support.Unsafe implTranF :: Functor f => (str -> f str) -> Enc enc1 conf str -> f (Enc enc2 conf str) implTranF' :: Functor f => (conf -> str -> f str) -> Enc enc1 conf str -> f (Enc enc2 conf str) implTranP :: Applicative f => (str -> str) -> Enc enc1 conf str -> f (Enc enc2 conf str) implTranP' :: Applicative f => (conf -> str -> str) -> Enc enc1 conf str -> f (Enc enc2 conf str) implChangeAnn :: Functor f => (Enc enc1 conf str -> f (Enc enc2a conf str)) -> Enc enc1 conf str -> f (Enc enc2b conf str) -- | v0.2 style encoding combinators module Data.TypedEncoding.Instances.Support.Encode -- | Create "r-" - like encoding based on fromEncF like -- function. -- -- Useful for small not performance critical encoding since it executed -- provided fromEnc function to verify the encoding -- -- this method does not restrict nm to follow "r-" naming -- convention but is expected to be used to define "r-" -- encoding. _implEncFromString :: forall nm err a c str. (KnownSymbol nm, Show err) => (Enc '[nm] () str -> Either err a) -> Encoding (Either EncodeEx) nm (AlgNm nm) c str _implEncodingP :: forall nm f c str. Applicative f => (str -> str) -> Encoding f nm (AlgNm nm) c str _implEncodingConfP :: forall nm f c str. Applicative f => (c -> str -> str) -> Encoding f nm (AlgNm nm) c str _implEncodingEx :: forall nm err c str. (KnownSymbol nm, Show err) => (str -> Either err str) -> Encoding (Either EncodeEx) nm (AlgNm nm) c str _implEncodingEncodeEx :: forall nm c str. KnownSymbol nm => (str -> Either EncodeEx str) -> Encoding (Either EncodeEx) nm (AlgNm nm) c str _implEncodingConfEx :: forall nm err c str. (KnownSymbol nm, Show err) => (c -> str -> Either err str) -> Encoding (Either EncodeEx) nm (AlgNm nm) c str implEncodingP :: forall nm f c str. Applicative f => (str -> str) -> Encoding f nm nm c str implEncodingEx :: forall nm err c str. (KnownSymbol nm, Show err) => (str -> Either err str) -> Encoding (Either EncodeEx) nm nm c str implEncodingEx' :: forall alg nm err c str. (KnownSymbol nm, Show err) => (str -> Either err str) -> Encoding (Either EncodeEx) nm alg c str implEncodingEncodeEx' :: forall alg nm c str. KnownSymbol nm => (str -> Either EncodeEx str) -> Encoding (Either EncodeEx) nm alg c str implVerifyR :: (a -> Either err b) -> a -> Either err a -- | Common decoding combinators module Data.TypedEncoding.Instances.Support.Decode decAnyR :: forall r f c str. (Restriction r, Applicative f) => Decoding f r r c str decAnyR' :: forall alg r f c str. (Restriction r, Applicative f) => Decoding f r alg c str decAnyR_ :: forall r f c str alg. (Restriction r, Algorithm r alg, Applicative f) => Decoding f r alg c str _implDecodingF :: forall nm f c str. Functor f => (str -> f str) -> Decoding f nm (AlgNm nm) c str _implDecodingConfF :: forall nm f c str. Functor f => (c -> str -> f str) -> Decoding f nm (AlgNm nm) c str implDecodingF :: forall nm f c str. Functor f => (str -> f str) -> Decoding f nm nm c str implDecodingF' :: forall alg nm f c str. Functor f => (str -> f str) -> Decoding f nm alg c str -- | Convenience validation utilities. module Data.TypedEncoding.Instances.Support.Validate validFromDec :: forall nm f c str. (KnownSymbol nm, RecreateErr f, Applicative f) => Decoding (Either UnexpectedDecodeEx) nm nm c str -> Validation f nm nm c str validFromDec' :: forall alg nm f c str. (KnownSymbol nm, RecreateErr f, Applicative f) => Decoding (Either UnexpectedDecodeEx) nm alg c str -> Validation f nm alg c str validR :: forall nm f c str. (Restriction nm, KnownSymbol nm, RecreateErr f, Applicative f) => Encoding (Either EncodeEx) nm nm c str -> Validation f nm nm c str -- | Can cause slow compilation if used -- -- (renamed from validR defined in pre 0.5 versions) _validR :: forall nm f c str alg. (Restriction nm, Algorithm nm alg, KnownSymbol nm, RecreateErr f, Applicative f) => Encoding (Either EncodeEx) nm alg c str -> Validation f nm alg c str -- | This should be used with "r-" validations only -- | Deprecated: Use _validR instead (valid for r- encodings only) validFromEnc' :: forall alg nm f c str. (KnownSymbol nm, RecreateErr f, Applicative f) => Encoding (Either EncodeEx) nm alg c str -> Validation f nm alg c str validRFromEnc' :: forall alg nm f c str. (KnownSymbol nm, RecreateErr f, Applicative f) => Encoding (Either EncodeEx) nm alg c str -> Validation f nm alg c str -- | Exports for instance creation. -- -- Contains typical things needed when implementing encoding, decoding, -- recreate, or type to string conversions. module Data.TypedEncoding.Instances.Support -- | 'UTF-8' encoding with additional assumption of conforming to -- Unicode.D76. -- -- "r-UTF-8" basically defines restriction on -- ByteString that is needed for conversion to Text to -- work. module Data.TypedEncoding.Instances.Restriction.UTF8 prxyUtf8 :: Proxy "r-UTF8" encUTF8B :: Encoding (Either EncodeEx) "r-UTF8" "r-UTF8" c ByteString encUTF8BL :: Encoding (Either EncodeEx) "r-UTF8" "r-UTF8" c ByteString -- | helper function checks that given ByteString, if is encoded as Left is -- must be not Utf8 decodable is is encoded as Right is must be Utf8 -- encodable verEncoding :: ByteString -> Either err ByteString -> Bool implVerifyR :: (a -> Either err b) -> a -> Either err a instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-UTF8" "r-UTF8" c Data.ByteString.Internal.ByteString instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-UTF8" "r-UTF8" c Data.ByteString.Lazy.Internal.ByteString instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Decode.Decode f "r-UTF8" "r-UTF8" c str instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-UTF8" "r-UTF8" c Data.ByteString.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-UTF8" "r-UTF8" c Data.ByteString.Lazy.Internal.ByteString -- | Common restriction "r-" instances -- -- Renamed from Data.TypedEncoding.Instances.Restriction.Common -- (v0.3) module Data.TypedEncoding.Instances.Restriction.Misc encWord8Dec :: IsStringR str => Encoding (Either EncodeEx) "r-Word8-decimal" "r-Word8-decimal" c str encIntDec :: IsStringR str => Encoding (Either EncodeEx) "r-Int-decimal" "r-Int-decimal" c str instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR str => Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-Word8-decimal" "r-Word8-decimal" c str instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Decode.Decode f "r-Word8-decimal" "r-Word8-decimal" c str instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR str => Data.TypedEncoding.Common.Class.Validate.Validate (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.RecreateEx) "r-Word8-decimal" "r-Word8-decimal" c str instance (Data.String.IsString str, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.ToEncString f "r-Word8-decimal" "r-Word8-decimal" GHC.Word.Word8 str instance (Data.TypedEncoding.Common.Class.IsStringR.IsStringR str, Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.FromEncString @{*} f "r-Word8-decimal" "r-Word8-decimal" GHC.Word.Word8 str instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR str => Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-Int-decimal" "r-Int-decimal" c str instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Decode.Decode f "r-Int-decimal" "r-Int-decimal" c str instance Data.TypedEncoding.Common.Class.IsStringR.IsStringR str => Data.TypedEncoding.Common.Class.Validate.Validate (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.RecreateEx) "r-Int-decimal" "r-Int-decimal" c str instance (Data.String.IsString str, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.ToEncString f "r-Int-decimal" "r-Int-decimal" GHC.Types.Int str -- | Restrictions "r-ban:" cover commonly used fixed (short) size -- strings with restricted characters such as GUID, credit card numbers, -- etc. -- -- Alphanumeric chars are ordered: 0-9 followed by A-Z, -- followed by a-z. Annotation specifies upper character bound. -- Any non alpha numeric characters are considered fixed delimiters and -- need to be present exactly as specified. For example -- "r-ban:999-99-9999" could be used to describe SSN numbers, -- @"r-ban:FFFF" would describe strings consisting of 4 hex digits. -- -- This is a simple implementation that converts to String, -- should be used only with short length data. module Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums type family IsBan (s :: Symbol) :: Bool type Ban s = (KnownSymbol s, IsBan s ~ 'True) -- |
-- >>> runEncoding' encFBan . toEncoding () $ "C59F9FB7-4621-44D9-9020-CE37BF6E2BD1" :: Either EncodeEx (Enc '["r-ban:FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"] () T.Text) -- Right (UnsafeMkEnc Proxy () "C59F9FB7-4621-44D9-9020-CE37BF6E2BD1") ---- --
-- >>> recreateFAll' @'["r-ban"] . toEncoding () $ "211-22-9934" :: Either RecreateEx (Enc '["r-ban:999-99-9999"] () T.Text) -- Right (UnsafeMkEnc Proxy () "211-22-9934") --encFBan :: forall s c str. (IsStringR str, Ban s, Algorithm s "r-ban") => Encoding (Either EncodeEx) s "r-ban" c str -- |
-- >>> verifyBoundedAlphaNum (Proxy :: Proxy "r-ban:FF-FF") (T.pack "12-3E") -- Right "12-3E" -- -- >>> verifyBoundedAlphaNum (Proxy :: Proxy "r-ban:FF-FF") (T.pack "1G-3E") -- Left "'G' not bounded by 'F'" -- -- >>> verifyBoundedAlphaNum (Proxy :: Proxy "r-ban:FF-FF") (T.pack "13G3E") -- Left "'G' not matching '-'" -- -- >>> verifyBoundedAlphaNum (Proxy :: Proxy "r-ban:FFяFF") (T.pack "13я234") -- Left "Not ASCII char in annotation '\\1103'" --verifyBoundedAlphaNum :: forall s str. (KnownSymbol s, IsStringR str) => Proxy s -> str -> Either String str instance (Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums.Ban s, Data.TypedEncoding.Common.Types.Common.Algorithm s "r-ban", Data.TypedEncoding.Common.Class.IsStringR.IsStringR str) => Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) s "r-ban" c str instance (GHC.TypeLits.KnownSymbol s, Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums.Ban s, Data.TypedEncoding.Common.Types.Common.Algorithm s "r-ban", Data.TypedEncoding.Common.Class.IsStringR.IsStringR str, Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f s "r-ban" c str instance (GHC.TypeLits.KnownSymbol s, Data.TypedEncoding.Common.Types.Common.Restriction s, Data.TypedEncoding.Common.Types.Common.Algorithm s "r-ban", GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Decode.Decode f s "r-ban" c str -- | Defines Base64 encoding for Text This version has poor -- performance. -- | Warning: Not optimized for performance module Data.TypedEncoding.Instances.Enc.Warn.Base64 -- | This function will likely be removed in future versions (performance -- concerns) (Moved from Data.TypedEncoding.Instances.Enc.Base64) endB64T :: Applicative f => Encoding f "enc-B64" "enc-B64" c Text decB64T :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "enc-B64" "enc-B64" c Text decB64TL :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "enc-B64" "enc-B64" c Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "enc-B64" "enc-B64" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Decode.Decode f "enc-B64" "enc-B64" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Decode.Decode f "enc-B64" "enc-B64" c Data.Text.Internal.Lazy.Text instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "enc-B64" "enc-B64" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "enc-B64" "enc-B64" c Data.Text.Internal.Lazy.Text -- | Lazy version of Data.TypedEncoding.Conv.Text @since 0.2.2.0 module Data.TypedEncoding.Conv.Text.Lazy pack :: (UnSnoc xs ~ '(,) ys y, Superset "r-UNICODE.D76" y, encs ~ RemoveRs ys, AllEncodeInto "r-UNICODE.D76" encs) => Enc xs c String -> Enc xs c Text -- | simplified version of pack that works on single r- -- encodings @since 0.5.2.0 pack1 :: Superset "r-UNICODE.D76" y => Enc '[y] c String -> Enc '[y] c Text unpack :: Enc xs c Text -> Enc xs c String -- | simplified version of unpack that works on single r- -- encodings @since 0.5.2.0 unpack1 :: Superset "r-UNICODE.D76" y => Enc '[y] c Text -> Enc '[y] c String -- | Text is automatically "r-UTF8" encoded utf8Promote :: Enc xs c Text -> Enc (Snoc xs "r-UTF8") c Text -- | For Text "r-UTF8" is redundant utf8Demote :: UnSnoc xs ~ '(,) ys "r-UTF8" => Enc xs c Text -> Enc ys c Text -- | Text encoding combinators specific to Text @since 0.2.2.0 module Data.TypedEncoding.Conv.Text -- | This assumes that each of the encodings in xs work work -- equivalently in String and Text. See discussion in -- Examples.TypedEncoding.Conversions and -- "Data.TypedEncoding.Conv.ByteString.Char8.pack" pack :: (UnSnoc xs ~ '(,) ys y, Superset "r-UNICODE.D76" y, encs ~ RemoveRs ys, AllEncodeInto "r-UNICODE.D76" encs) => Enc xs c String -> Enc xs c Text -- | simplified version of pack that works on single r- -- encodings @since 0.5.2.0 pack1 :: Superset "r-UNICODE.D76" y => Enc '[y] c String -> Enc '[y] c Text -- | This assumes that each of the encodings in xs work work -- equivalently in String and Text. This is similar to -- the assumptions made in pack. unpack :: (UnSnoc xs ~ '(,) ys y, Superset "r-UNICODE.D76" y, encs ~ RemoveRs ys, AllEncodeInto "r-UNICODE.D76" encs) => Enc xs c Text -> Enc xs c String -- | simplified version of unpack that works on single r- -- encodings @since 0.5.2.0 unpack1 :: Superset "r-UNICODE.D76" y => Enc '[y] c Text -> Enc '[y] c String -- | Text is automatically "r-UTF8" encoded -- -- Adding "r-UTF8" annotation simply adds type level -- interpretion requirement that Text is treated as UTF8. -- The internals of Text (currently UTF-16) are not -- relevant and utf8Promote is implemented as id. This is -- not the same as encoding Word8 layouts into Char-s. -- This, in typed-encoding terminology, would be -- "enc-UTF8", not @"r-UTF8". -- --
-- >>> displ $ utf8Promote $ toEncoding () ("text" :: T.Text)
-- "Enc '[r-UTF8] () (Text text)"
--
utf8Promote :: Enc xs c Text -> Enc (Snoc xs "r-UTF8") c Text
-- | For Text "r-UTF8" is redundant
--
-- -- >>> displ . utf8Demote $ (unsafeSetPayload () "Hello" :: Enc '["r-UTF8"] () T.Text) -- "Enc '[] () (Text Hello)" --utf8Demote :: UnSnoc xs ~ '(,) ys "r-UTF8" => Enc xs c Text -> Enc ys c Text d76Promote :: Enc xs c Text -> Enc (Snoc xs "r-UNICODE.D76") c Text d76Demote :: UnSnoc xs ~ '(,) ys "r-UNICODE.D76" => Enc xs c Text -> Enc ys c Text -- | Lazy version of Data.TypedEncoding.Conv.ByteString.Char8 @since -- 0.2.2.0 module Data.TypedEncoding.Conv.ByteString.Lazy.Char8 -- | Lazy version of pack. pack :: (UnSnoc xs ~ '(,) ys y, Superset "r-CHAR8" y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c String -> Enc xs c ByteString -- | Lazy version of unpack. unpack :: (UnSnoc xs ~ '(,) ys y, Superset "r-CHAR8" y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c ByteString -> Enc xs c String -- | Lazy version of pack''. pack'' :: (UnSnoc xs ~ '(,) ys y, EncodingAnn y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c String -> Enc xs c ByteString -- | Lazy version of unpack''. unpack'' :: (UnSnoc xs ~ '(,) ys y, EncodingAnn y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c ByteString -> Enc xs c String -- | Encoding safe(r) version of Data.ByteString.Char8 @since -- 0.2.2.0 module Data.TypedEncoding.Conv.ByteString.Char8 -- | Type safer version of pack. -- -- This assumes that each of the encodings in xs work -- equivalently in String and ByteString. See -- Examples.TypedEncoding.Conversions. -- -- This function also (currently) does not insist that xs is a -- valid encoding stack for ByteString. This will be reexamined -- in the future, possibly offering stricter overloads of pack. -- -- Expected encoding stack xs needs to have "r-" as last -- element and it needs to be more restrictive than "r-CHAR8" (String -- cannot have chars > 255@). Otherwise any encodings other than -- "r-" need to encode into "r-CHAR8". -- -- See Data.TypedEncoding.Conv for more detailed discussion. -- --
-- >>> :t pack (undefined :: Enc '["r-bar", "r-foo"] () String) -- ... -- ... error: -- ... Couldn't match type ... -- ... ---- --
-- >>> displ $ pack (unsafeSetPayload () "Hello" :: Enc '["r-bar", "r-ASCII"] () String) -- "Enc '[r-bar,r-ASCII] () (ByteString Hello)" --pack :: (UnSnoc xs ~ '(,) ys y, Superset "r-CHAR8" y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c String -> Enc xs c ByteString -- | Version of pack that works without first "r-" encoding. -- --
-- >>> displ $ pack'' (unsafeSetPayload () "SGVsbG8gV29ybGQ=" :: Enc '["enc-B64"] () String) -- "Enc '[enc-B64] () (ByteString SGVsbG8gV29ybGQ=)" --pack'' :: (UnSnoc xs ~ '(,) ys y, EncodingAnn y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c String -> Enc xs c ByteString -- | unpack on encoded strings. -- -- See pack -- -- Similarly to pack this makes assumptions on what the encoding -- stack is allowed to do. These are not type checked. Again, this is -- safe with any stack that uses "r-" only encodings. Future versions of -- type-encoding are likely to introduce constraints to guard this -- aspect of the type safety better. unpack :: (UnSnoc xs ~ '(,) ys y, Superset "r-CHAR8" y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c ByteString -> Enc xs c String -- | Version of pack that works without first "r-" encoding -- --
-- >>> displ $ unpack'' (unsafeSetPayload () "SGVsbG8gV29ybGQ=" :: Enc '["enc-B64"] () B8.ByteString) -- "Enc '[enc-B64] () (String SGVsbG8gV29ybGQ=)" --unpack'' :: (UnSnoc xs ~ '(,) ys y, EncodingAnn y, encs ~ RemoveRs ys, AllEncodeInto "r-CHAR8" encs) => Enc xs c ByteString -> Enc xs c String module Data.TypedEncoding.Internal.Util explainBool :: (a -> err) -> (a, Bool) -> Either err a -- | "r-UNICODE.D76" restricts Unicode characters by excluding the range -- U+D800 to U+DFFF. -- -- This is important because the commonly used Text type from -- text package replaces chars that are in range U+D800 to U+DFFF -- (inclusive). -- -- Note, there is no IsSuperset "r-UNICODE.D76" "r-CHAR8" -- mapping even though the numeric range of D76 includes all CHAR8 bytes. -- This is more nominal decision that prevents certain unwanted -- conversions from being possible. -- -- Similarly there is no IsSuperset "r-UNICODE.D76" "r-ByteRep", -- "r-UNICODE.D76" acts as a guard to what can go into Text and -- this prevents some unwanted conversions. module Data.TypedEncoding.Instances.Restriction.D76 newtype NonTextChar NonTextChar :: Char -> NonTextChar encD76Char :: Encoding (Either EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c Char encD76 :: Encoding (Either EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c String -- | No-check version trustMe :: Applicative f => Encoding f "r-UNICODE.D76" "r-UNICODE.D76" c String nonTextChar :: Char -> Bool encImpl :: String -> Either NonTextChar String instance GHC.Show.Show Data.TypedEncoding.Instances.Restriction.D76.NonTextChar instance GHC.Classes.Eq Data.TypedEncoding.Instances.Restriction.D76.NonTextChar instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c GHC.Types.Char instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c GHC.Base.String instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Decode.Decode f "r-UNICODE.D76" "r-UNICODE.D76" c str instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-UNICODE.D76" "r-UNICODE.D76" () GHC.Base.String -- | "r-ByteRep" represents Characters used for Byte -- representations. -- -- It is common to use Char instead of Word8 when low -- level programming on ByteString. -- -- This annotation represents such use of string characters. -- -- Checks if all chars are < '256' -- -- Currently, this should be not used as superset IsSuperset -- -- It is subset of "r-CHAR8": -- -- @Superset "r-CHAR8" ""r-ByteRep" -- -- Currently, is (intentionally not decodable) module Data.TypedEncoding.Instances.Restriction.ByteRep data CharOutOfRange CharOutOfRange :: Int -> Char -> CharOutOfRange encByteChar :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c Char encByteRepB :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c ByteString encByteRepBL :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c ByteString encByteRepS :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c String encImpl :: Char8Find str => Int -> str -> Either CharOutOfRange str instance GHC.Show.Show Data.TypedEncoding.Instances.Restriction.ByteRep.CharOutOfRange instance GHC.Classes.Eq Data.TypedEncoding.Instances.Restriction.ByteRep.CharOutOfRange instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-ByteRep" "r-ByteRep" c GHC.Types.Char instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-ByteRep" "r-ByteRep" c Data.ByteString.Internal.ByteString instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-ByteRep" "r-ByteRep" c Data.ByteString.Lazy.Internal.ByteString instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-ByteRep" "r-ByteRep" c GHC.Base.String instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-ByteRep" "r-ByteRep" () Data.ByteString.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-ByteRep" "r-ByteRep" () Data.ByteString.Lazy.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-ByteRep" "r-ByteRep" () GHC.Base.String -- | "r-CHAR8" should not be used directly, only as superset. -- -- This module includes tests that verify that all chars are < -- '256' -- -- Encoding functions are here for test support only, no instances. module Data.TypedEncoding.Instances.Restriction.CHAR8 testEncChar8Char :: Encoding (Either EncodeEx) "r-CHAR8" "r-CHAR8" c Char testEncCHAR8 :: Char8Find str => Encoding (Either EncodeEx) "r-CHAR8" "r-CHAR8" c str -- | Strings can be encoded as 'Enc "r-ASCII"@ only if they contain only -- ASCII characters (first 128 characters of the Unicode character set). -- -- This is sometimes referred to as ASCII-7 and future versions of -- type-encoding may change "r-ASCII" symbol annotation -- to reflect this. -- --
-- B8.all ((< 128) . ord) . getPayload @'["r-ASCII"] @() @B.ByteString ---- --
-- >>> :set -XOverloadedStrings -XMultiParamTypeClasses -XDataKinds -- -- >>> _runEncodings encodings . toEncoding () $ "Hello World" :: Either EncodeEx (Enc '["r-ASCII"] () T.Text) -- Right (UnsafeMkEnc Proxy () "Hello World") ---- --
-- >>> _runEncodings encodings . toEncoding () $ "\194\160" :: Either EncodeEx (Enc '["r-ASCII"] () T.Text) -- Left (EncodeEx "r-ASCII" (NonAsciiChar '\194')) --module Data.TypedEncoding.Instances.Restriction.ASCII newtype NonAsciiChar NonAsciiChar :: Char -> NonAsciiChar encASCIIChar :: Encoding (Either EncodeEx) "r-ASCII" "r-ASCII" c Char encASCII :: Char8Find str => Encoding (Either EncodeEx) "r-ASCII" "r-ASCII" c str encImpl :: Char8Find str => str -> Either NonAsciiChar str instance GHC.Show.Show Data.TypedEncoding.Instances.Restriction.ASCII.NonAsciiChar instance GHC.Classes.Eq Data.TypedEncoding.Instances.Restriction.ASCII.NonAsciiChar instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-ASCII" "r-ASCII" c GHC.Types.Char instance Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find str => Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-ASCII" "r-ASCII" c str instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Decode.Decode f "r-ASCII" "r-ASCII" c str instance (Data.TypedEncoding.Common.Class.Util.StringConstraints.Char8Find str, Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-ASCII" "r-ASCII" () str -- | 'r-B64' is restricted to values that are valid Base64 encodings of -- some data. For example, Enc '["r-B64"] () T.Text can contain -- encoded binary image. -- -- "enc-B64" can be converted to "r-B64" using flattenAs defined -- in Base64. However, there is no, and there should be no -- conversion general conversion from "r-B64" back to "enc-B64": Enc -- '["r-B64"] () T.Text is not B64 encoded text, it is B64 encoded -- something. module Data.TypedEncoding.Instances.Restriction.Base64 encRB64B :: Encoding (Either EncodeEx) "r-B64" "r-B64" c ByteString encRB64BL :: Encoding (Either EncodeEx) "r-B64" "r-B64" c ByteString -- | Converts text to bytestring using UTF8 decoding and then verify -- encoding in ByteString This is safe without verifying ASCII, any -- non-ASCII text will still convert to ByteString but will fail -- B64.decode (TODO tests would be nice) encRB64T :: Encoding (Either EncodeEx) "r-B64" "r-B64" c Text encRB64TL :: Encoding (Either EncodeEx) "r-B64" "r-B64" c Text encRB64S :: Encoding (Either EncodeEx) "r-B64" "r-B64" c String instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-B64" "r-B64" c Data.ByteString.Internal.ByteString instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-B64" "r-B64" c Data.ByteString.Lazy.Internal.ByteString instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-B64" "r-B64" c Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-B64" "r-B64" c Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Common.Class.Encode.Encode (Data.Either.Either Data.TypedEncoding.Common.Types.Exceptions.EncodeEx) "r-B64" "r-B64" c GHC.Base.String instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Decode.Decode f "r-B64" "r-B64" c str instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-B64" "r-B64" c Data.ByteString.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-B64" "r-B64" c Data.ByteString.Lazy.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-B64" "r-B64" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-B64" "r-B64" c Data.Text.Internal.Lazy.Text instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "r-B64" "r-B64" c GHC.Base.String -- | Defines Base64 encoding module Data.TypedEncoding.Instances.Enc.Base64 acceptLenientS :: Enc ("enc-B64-len" : ys) c ByteString -> Enc ("enc-B64" : ys) c ByteString acceptLenientL :: Enc ("enc-B64-len" : ys) c ByteString -> Enc ("enc-B64" : ys) c ByteString -- | Validated "r-B64" is guaranteed to decode. -- -- Use flattenAs in the other direction. -- -- This would not be safe for Text asEncodingB :: Enc '["r-B64"] c ByteString -> Enc '["enc-B64"] c ByteString -- | Validated "r-B64" is guaranteed to decode. This would not be safe for -- Text asEncodingBL :: Enc '["r-B64"] c ByteString -> Enc '["enc-B64"] c ByteString encB64B :: Applicative f => Encoding f "enc-B64" "enc-B64" c ByteString encB64BL :: Applicative f => Encoding f "enc-B64" "enc-B64" c ByteString -- | Effectful decoding for corruption detection. This protocol is used, -- for example, in emails. It is a well known encoding and hackers will -- have no problem making undetectable changes, but error handling at -- this stage could verify that email was corrupted. -- --
-- _propSafeDecoding @"enc-B64" @() @B.ByteString encB64B decB64B () ---- --
-- _propSafeValidatedDecoding @"enc-B64" @() @B.ByteString validation decB64B () . getUncheckedPayload @() @B.ByteString --decB64B :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "enc-B64" "enc-B64" c ByteString -- |
-- _propSafeDecoding @"enc-B64" @() @BL.ByteString encB64BL decB64BL --decB64BL :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "enc-B64" "enc-B64" c ByteString instance Data.TypedEncoding.Common.Class.FlattenAs "r-ASCII" "enc-B64-nontext" instance Data.TypedEncoding.Common.Class.FlattenAs "r-ASCII" "enc-B64" instance Data.TypedEncoding.Common.Class.FlattenAs "r-B64" "enc-B64" instance Data.TypedEncoding.Common.Class.Superset.EncodingSuperset "enc-B64" instance Data.TypedEncoding.Common.Class.Superset.EncodingSuperset "enc-B64-len" instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "enc-B64" "enc-B64" c Data.ByteString.Internal.ByteString instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "enc-B64" "enc-B64" c Data.ByteString.Lazy.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Decode.Decode f "enc-B64" "enc-B64" c Data.ByteString.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Decode.Decode f "enc-B64" "enc-B64" c Data.ByteString.Lazy.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "enc-B64" "enc-B64" c Data.ByteString.Internal.ByteString instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "enc-B64" "enc-B64" c Data.ByteString.Lazy.Internal.ByteString instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Validate.Validate f "enc-B64-len" "enc-B64-len" c Data.ByteString.Internal.ByteString instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Validate.Validate f "enc-B64-len" "enc-B64-len" c Data.ByteString.Lazy.Internal.ByteString module Data.TypedEncoding.Unsafe -- | Lazy version of Data.TypedEncoding.Conv.Text.Encoding @since -- 0.2.2.0 module Data.TypedEncoding.Conv.Text.Lazy.Encoding -- | Lazy version of decodeUtf8 decodeUtf8 :: forall xs c t y ys encs. (UnSnoc xs ~ '(,) ys y, Superset "r-UTF8" y, encs ~ RemoveRs ys, AllEncodeInto "r-UTF8" encs) => Enc xs c ByteString -> Enc xs c Text -- | simplified version of decodeUtf8 that works on single -- r- encodings @since 0.5.2.0 decodeUtf8_1 :: Superset "r-UTF8" y => Enc '[y] c ByteString -> Enc '[y] c Text -- | Lazy version of encodeUtf8 encodeUtf8 :: forall xs c t y ys encs. (UnSnoc xs ~ '(,) ys y, Superset "r-UTF8" y, encs ~ RemoveRs ys, AllEncodeInto "r-UTF8" encs) => Enc xs c Text -> Enc xs c ByteString -- | simplified version of decodeUtf8 that works on single -- r- encodings @since 0.5.2.0 encodeUtf8_1 :: Superset "r-UTF8" y => Enc '[y] c Text -> Enc '[y] c ByteString module Data.TypedEncoding.Conv.Text.Encoding -- | With given constraints decodeUtf8 and encodeUtf8 can be -- used on subsets of "r-UTF8" -- -- Note: For example, the ByteString encoding of -- "xd800" (11101101 10100000 10000000 ed a0 -- 80) is considered invalid UTF8 by the Text library -- To be consistent we make the same assumption of also restricting -- representable Unicode chars as in Unicode.D76. -- --
-- >>> TE.decodeUtf8 "\237\160\128" -- "*** Exception: Cannot decode byte '\xed': Data.Text.Encoding: Invalid UTF-8 stream ---- -- The "xdfff" case (11101101 10111111 10111111 ed bf -- bf): >>> TE.decodeUtf8 "237191191" "*** Exception: -- Cannot decode byte 'xed': Data.Text.Encoding: Invalid UTF-8 stream -- --
-- >>> displ . decodeUtf8 $ (unsafeSetPayload () "Hello" :: Enc '["r-ASCII"] () B.ByteString) -- "Enc '[r-ASCII] () (Text Hello)" ---- -- "r-UTF8" is redundant: -- --
-- >>> displ . utf8Demote . decodeUtf8 $ (unsafeSetPayload () "Hello" :: Enc '["r-UTF8"] () B.ByteString) -- "Enc '[] () (Text Hello)" ---- -- decodeUtf8 and encodeUtf8 now form isomorphism -- --
-- \x -> getPayload x == (getPayload . encodeUtf8 . decodeUtf8 @'["r-UTF8"] @() $ x) ---- --
-- \x -> getPayload x == (getPayload . decodeUtf8 . encodeUtf8 @'["r-UTF8"] @() $ x) ---- -- These nicely work as iso's for "r-ASCII" subset -- --
-- \x -> getPayload x == (getPayload . encodeUtf8 . decodeUtf8 @'["r-ASCII"] @() $ x) ---- --
-- \x -> getPayload x == (getPayload . decodeUtf8 . encodeUtf8 @'["r-ASCII"] @() $ x) ---- -- Similarly to pack this function makes unverified assumption -- that the encoding stack xs does invalidate UTF8 byte layout. -- This is safe for any "r-" encoding as well as any of the "enc-" and -- "do-" encodings that can be currently found in this library. Future -- versions of this method are likely to introduce constraints that -- guarantee better type safety. -- -- This is technically unsafe (even if we ignore the use of -- unsafeSetPayload) of decodeUtf8 since currently -- "r-ban:999" does not have ByteString instances and -- that violates the assumption of matching encoding/decoding stacks on -- both sides. >>> displ . decodeUtf8 $ (unsafeSetPayload () -- "123" :: Enc '["r-ban:999"] () B.ByteString) "Enc '[r-ban:999] () -- (Text 123)" -- -- See Data.TypedEncoding.Conv for more detailed discussion. -- -- Note: implementation uses the partial decodeUtf8 function but -- provides type level guarantee that it this function will not error out -- unless unsafe combinators were used in constructing the encoded input decodeUtf8 :: forall xs c t y ys encs. (UnSnoc xs ~ '(,) ys y, Superset "r-UTF8" y, encs ~ RemoveRs ys, AllEncodeInto "r-UTF8" encs) => Enc xs c ByteString -> Enc xs c Text -- | simplified version of decodeUtf8 that works on single -- r- encodings @since 0.5.2.0 decodeUtf8_1 :: Superset "r-UTF8" y => Enc '[y] c ByteString -> Enc '[y] c Text -- |
-- >>> displ $ encodeUtf8 $ utf8Promote $ toEncoding () ("text" :: T.Text)
-- "Enc '[r-UTF8] () (ByteString text)"
--
--
-- See decodeUtf8. Similar type safety concerns apply.
--
-- See Data.TypedEncoding.Conv for more detailed discussion.
encodeUtf8 :: forall xs c t y ys encs. (UnSnoc xs ~ '(,) ys y, Superset "r-UTF8" y, encs ~ RemoveRs ys, AllEncodeInto "r-UTF8" encs) => Enc xs c Text -> Enc xs c ByteString
-- | simplified version of decodeUtf8 that works on single
-- r- encodings @since 0.5.2.0
encodeUtf8_1 :: Superset "r-UTF8" y => Enc '[y] c Text -> Enc '[y] c ByteString
-- | Examples or moving between type annotated encodings
--
-- Please also see documentation in Data.TypedEncoding.Conv.
--
-- Haskell programs typically make these imports to do String,
-- ByteString, and Text conversions:
--
-- -- import qualified Data.Text as T (pack, unpack) -- import qualified Data.ByteString.Char8 as B8 (pack, unpack) -- import Data.Text.Encoding (decodeUtf8, encodeUtf8) ---- -- or corresponding Lazy imports (not shown). -- -- Enc-specific equivalents can be found in: -- --
-- import qualified Data.TypedEncoding.Conv.Text as EncT (pack, unpack) -- import qualified Data.TypedEncoding.Conv.ByteString.Char8 as EncB8 (pack, unpack) -- import Data.TypedEncoding.Conv.Text.Encoding (decodeUtf8, encodeUtf8) ---- -- Conversions aim at providing type safety when moving between encoded -- string-like types. -- -- The assumption made by typed-encoding is that -- "enc-" encodings work in an equivalent way independently of -- the payload type. For example, if the following instances exist: -- --
-- EncodeF SomeErr (Enc xs () String) (Enc ("enc-B64" ': xs) () String)
-- EncodeF SomeErr (Enc xs () Text) (Enc ("enc-B64" ': xs) () Text)
--
--
-- Then typed-encoding expects pack encodeF to
-- commute (if encoding instances exist):
--
-- -- str -- EncT.pack --> txt -- | | -- encodeF encodeF -- | | -- v v -- estr -- fmap EncT.pack --> etxt ---- -- (unpack and $decode$ are expected to satisfy similar -- diagrams, not shown) -- -- Basically, it should not matter which type we run the encoding (or -- decoding) on (other than performance cost). -- -- Note that, as a consequence, multi-byte encodings (such as -- enc-UTF8 - available in typed-encoding-encoding -- package) that encode a Unicode characters into several bytes cannot be -- decoded in ByteString as this would violate -- EncB8.pack and EncB8.unpack consistency. -- -- Also note that this requirement is concerned about "enc-" -- encodings, "r-" encodings are much simpler to reason about in -- conversions. -- -- This module also discusses concepts of Superset (for -- "r-" encodings), leniency, and flattening. module Examples.TypedEncoding.Conversions -- | Example value to play with -- --
-- >>> _runEncodings encodings . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-ASCII"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "HeLlo world") --eHelloAsciiB :: Either EncodeEx (Enc '["r-ASCII"] () ByteString) -- | above with either removed helloAsciiB :: Enc '["r-ASCII"] () ByteString -- | We use a tween function of the popular decodeUtf8 from the -- text package. -- -- Notice the encoding annotation is preserved. -- --
-- >>> displ $ EncTe.decodeUtf8 helloAsciiB -- "Enc '[r-ASCII] () (Text HeLlo world)" --helloAsciiT :: Enc '["r-ASCII"] () Text -- | Consider 0-encoding of a String, to move it to Enc '[] () -- ByteString one could try: -- --
-- >>> EncB8.pack helloZero -- ... -- ... error: -- ... Empty list, no last element -- ... ---- -- this does not compile. And it should not. pack from -- Data.ByteString.Char8 is error prone. It is not an injection as -- it only considers first 8 bits of information from each Char. I -- doubt that there are any code examples of its intentional use on a -- String that has chars > '255'. -- -- EncB8.pack will not compile unless the encoding has "r-CHAR8" -- as its superset. This works: -- --
-- >>> fmap (displ . EncB8.pack) . encodeFAll @'["r-ASCII"] @(Either EncodeEx) $ helloZero -- Right "Enc '[r-ASCII] () (ByteString Hello)" ---- -- And the result is a ByteString with bonus annotation -- describing its content. -- -- Similar game is played for Text: -- --
-- >>> fmap (displ . EncT.d76Demote . EncT.pack) . encodeFAll @'["r-UNICODE.D76"] @(Either EncodeEx) $ helloZero -- Right "Enc '[] () (Text Hello)" ---- -- See Data.TypedEncoding.Conv for more information on this. helloZero :: Enc ('[] :: [Symbol]) () String -- | more interestingly EncB8.pack works fine on "r-" encodings -- that are subsets of "r-ASCII" this example "r-ban:zzzzz" -- restricts to 5 alpha-numeric charters all < 'z' -- --
-- >>> displ <$> helloRestricted -- Right "Enc '[r-ban:zzzzz] () (ByteString Hello)" ---- -- Adding "r-ASCII" annotation on this ByteString would have -- been redundant since "r-ban:zzzzz" is more restrictive (see -- Supersets below). -- -- unpack, as expected will put us back in a String keeping the -- annotation -- --
-- >>> fmap (displ . EncB8.unpack) helloRestricted -- Right "Enc '[r-ban:zzzzz] () (String Hello)" --helloRestricted :: Either EncodeEx (Enc '["r-ban:zzzzz"] () ByteString) -- | For low level use of Char instead of Word8, -- "r-ByteRep" represents anything under 256. byteRep :: Either EncodeEx (Enc '["r-ByteRep"] () ByteString) -- | We Base64 encode a ByteString which adheres to UTF8 layout -- --
-- >>> displ $ encodePart @'["enc-B64"] helloUtf8B -- "Enc '[enc-B64,r-UTF8] () (ByteString SGVMbG8gd29ybGQ=)" --helloUtf8B64B :: Enc '["enc-B64", "r-UTF8"] () ByteString -- | .. and copy it over to Text. -- --
-- >>> displ $ EncTe.decodeUtf8 helloUtf8B64B -- "Enc '[enc-B64,r-UTF8] () (Text SGVMbG8gd29ybGQ=)" ---- -- but UTF8 would be redundant in Text so the "r-UTF8" can be dropped: -- --
-- >>> displ . EncT.utf8Demote . EncTe.decodeUtf8 $ helloUtf8B64B -- "Enc '[enc-B64] () (Text SGVMbG8gd29ybGQ=)" ---- -- Conversely moving back to ByteString we need to recover the annotation -- --
-- >>> :t EncTe.encodeUtf8 helloUtf8B64T -- ... -- ... Couldn't match type ... -- ... ---- -- This is not allowed! We need to add the redundant "r-UTF8" back: -- --
-- >>> displ . EncTe.encodeUtf8 . EncT.utf8Promote $ helloUtf8B64T -- "Enc '[enc-B64,r-UTF8] () (ByteString SGVMbG8gd29ybGQ=)" ---- -- To achieve type safety, our encodeUtf8 and -- decodeUtf8 require "r-UTF8" annotation. But since -- Text values can always emit UTF8 layout, we can -- simply add and remove these annotations on Text encodings. -- This approach gives us type level safety over UTF8 encoding/decoding -- errors. helloUtf8B64T :: Enc '["enc-B64"] () Text -- | notTextB a binary, one that does not even represent a valid -- UTF8. -- --
-- >>> encodeAll . toEncoding () $ "\195\177" :: Enc '["enc-B64"] () B.ByteString -- UnsafeMkEnc Proxy () "w7E=" ---- -- Decoding it to Text is prevented by the compiler -- --
-- >>> :t EncTe.decodeUtf8 notTextB -- ... -- ... error: -- ... Couldn't match type ... -- ... ---- -- This is good because having the payload inside of Enc '["enc-B64"] -- () Text would allow us to try to decode it to Text (causing -- runtime errors). -- -- We can move it to Text but to do that we will need to forget the -- "enc-B64" annotation. This can be done, for example, using flattening -- (see below). notTextB :: Enc '["enc-B64"] () ByteString -- | To claim UTF8 on helloAsciiB, instead encoding again: -- --
-- >>> encodeFAll . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-UTF8"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "HeLlo world") ---- -- We should be able to convert the ASCII annotation directly. -- -- This is done using IsSuperset type family. -- -- injectInto method accepts proxy to specify superset to use. -- --
-- >>> displ $ injectInto @"r-UTF8" helloAsciiB -- "Enc '[r-UTF8] () (ByteString HeLlo world)" ---- -- Superset is intended for "r-" annotations only, should not be -- used with general encodings like "enc-B64", it assumes that -- decoding in the superset can replace the decoding from injected -- subset. helloUtf8B :: Enc '["r-UTF8"] () ByteString -- | Base64 encoding represents binary data in an ASCII string -- format. -- -- In Haskell, we should be able to express this in types. -- -- EncodingSuperset class is what specifies this. -- -- We can use it with _encodesInto combinator. -- EncodingSuperset should not be used directly at the calling -- site. -- --
-- >>> displ (_encodesInto @"r-ASCII" $ notTextB) -- "Enc '[r-ASCII,enc-B64] () (ByteString w7E=)" ---- -- _encodesInto can be used with a superset of the encoding -- character set as well making it more backward compatible (the -- definition of @EncodingSuperset "enc-B64" could be made more precise -- without breaking the code). -- --
-- >>> displ (_encodesInto @"r-UTF8" $ notTextB) -- "Enc '[r-UTF8,enc-B64] () (ByteString w7E=)" --notTextBB64Ascii :: Enc '["r-ASCII", "enc-B64"] () ByteString -- | Base64 encoding of a non-text binary data can still be -- converted to Text format Enc '["r-B64"] () T.Text signifies -- that the value is B64 encoding but it cannot be decoded to a Text. notTextB64AsTxt :: Enc '["r-B64"] () Text -- |
-- >>> recreateAll . toEncoding () $ "abc==CB" :: Enc '["enc-B64-len"] () B.ByteString -- UnsafeMkEnc Proxy () "abc==CB" ---- -- The rest of Haskell does lenient decoding, type safety allows this -- library to use it for recovery. lenient algorithms are not partial and -- automatically fix invalid input: -- --
-- >>> recreateFAll . toEncoding () $ "abc==CB" :: Either RecreateEx (Enc '["enc-B64"] () B.ByteString)
-- Left (RecreateEx "enc-B64" ("Base64-encoded bytestring is unpadded or has invalid padding"))
--
--
-- This library allows to recover to "enc-B64-len" which is different
-- than "enc-B64"
--
-- acceptLenientS allows to convert "enc-B64-len" to "enc-B64"
--
-- -- >>> displ $ EnB64.acceptLenientS lenientSomething -- "Enc '[enc-B64] () (ByteString abc=)" ---- -- This is now properly encoded data -- --
-- >>> recreateFAll . toEncoding () $ "abc=" :: Either RecreateEx (Enc '["enc-B64"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "abc=") ---- -- Except the content could be surprising -- --
-- >>> decodeAll $ EnB64.acceptLenientS lenientSomething -- UnsafeMkEnc Proxy () "i\183" --lenientSomething :: Enc '["enc-B64-len"] () ByteString -- | Base 64 encodes binary data as ASCII text. thus, we should be able to -- treat "enc-B64" as "r-ASCII" losing some information. this is done -- using FlattenAs type class -- --
-- >>> :t flattenAs @"r-ASCII" helloUtf8B64B -- flattenAs @"r-ASCII" helloUtf8B64B -- ... :: Enc '["r-ASCII"] () B.ByteString --b64IsAscii :: Enc '["r-ASCII"] () ByteString -- | Simple DIY encoding example that "signs" Text with its length. -- -- Documentation includes discussion of error handling options. -- -- My current thinking: -- -- Stronger type level information about encoding provides type safety -- over decoding process. Decoding cannot fail unless somehow underlying -- data has been corrupted. -- -- Such integrity of data should be enforced at boundaries (JSON -- instances, DB retrievals, etc). This can be accomplished using -- provided support for Validation or using UncheckedEnc. -- -- This still is user decision, the errors during decoding process are -- considered unexpected UnexpectedDecodeErr. In particular user -- can decide to use unsafe operations with the encoded type. See -- Unsafe. module Examples.TypedEncoding.Instances.DiySignEncoding -- | encoding function, typically should be module private encodeSign :: Text -> Text -- | dual purpose decoding and recovery function. -- -- This typically should be module private. -- --
-- >>> decodeSign "3:abc" -- Right "abc" ---- --
-- >>> decodeSign "4:abc" -- Left "Corrupted Signature" --decodeSign :: Text -> Either String Text -- | Encoded hello world example. -- --
-- >>> helloSigned -- UnsafeMkEnc Proxy () "11:Hello World" ---- --
-- >>> fromEncoding . decodeAll $ helloSigned -- "Hello World" --helloSigned :: Enc '["my-sign"] () Text -- | property checks that Text values are expected to decode without -- error after encoding. -- --
-- \t -> propEncDec --propEncDec :: Text -> Bool -- | Hacker example The data was transmitted over a network and got -- corrupted. -- --
-- >>> let payload = getPayload $ helloSigned :: T.Text
--
-- >>> let newpay = payload <> " corruption"
--
-- >>> recreateFAll . toEncoding () $ newpay :: Either RecreateEx (Enc '["my-sign"] () T.Text)
-- Left (RecreateEx "my-sign" ("Corrupted Signature"))
--
--
-- -- >>> recreateFAll . toEncoding () $ payload :: Either RecreateEx (Enc '["my-sign"] () T.Text) -- Right (UnsafeMkEnc Proxy () "11:Hello World") --hacker :: Either RecreateEx (Enc '["my-sign"] () Text) decMySign :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "my-sign" "my-sign" c Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "my-sign" "my-sign" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Decode.Decode f "my-sign" "my-sign" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "my-sign" "my-sign" c Data.Text.Internal.Text -- | Internally used existential type for tracking of annotations -- -- This module is re-exported in Data.TypedEncoding and it is best -- not to import it directly. module Examples.TypedEncoding.SomeEnc.SomeAnnotation data SomeAnnotation [MkSomeAnnotation] :: SymbolList xs => Proxy xs -> SomeAnnotation withSomeAnnotation :: SomeAnnotation -> (forall xs. SymbolList xs => Proxy xs -> r) -> r -- | folds over SomeSymbol list @since 0.2.0.0 someAnnValue :: [EncAnn] -> SomeAnnotation -- | 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 CheckedEnc. -- -- Post v0.4 typed-encoding supports CheckedEnc while -- SomeEnc remains as as example. -- -- (Moved from Data.TypedEncoding.Common.Types.SomeEnc in -- previous versions) module Examples.TypedEncoding.SomeEnc -- | Existentially quantified quantified Enc effectively -- isomorphic to CheckedEnc data SomeEnc conf str [MkSomeEnc] :: SymbolList xs => Enc xs conf str -> SomeEnc conf str withSomeEnc :: SomeEnc conf str -> (forall xs. SymbolList xs => Enc xs conf str -> r) -> r toSome :: SymbolList xs => Enc xs conf str -> SomeEnc conf str -- |
-- >>> let enctest = unsafeSetPayload () "hello" :: Enc '["TEST"] () T.Text -- -- >>> someToChecked . MkSomeEnc $ enctest -- UnsafeMkCheckedEnc ["TEST"] () "hello" --someToChecked :: SomeEnc conf str -> CheckedEnc conf str -- |
-- >>> 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 instance (GHC.Show.Show c, Data.TypedEncoding.Common.Class.Common.Displ str) => Data.TypedEncoding.Common.Class.Common.Displ (Examples.TypedEncoding.SomeEnc.SomeEnc c str) -- | This module shows use of ToEncString and FromEncString -- and demonstrates composite encoding. -- -- Show and Read classes use a very permissive String -- type. This often results in read errors. type-encoding approach -- provides type safety over decoding process. -- -- This module includes a simplified email example. This is a -- non-homogeneous case, email parts do not have the same encoding. -- -- Examples here could be made more type safe with use of dependently -- typed concepts like Vect, HList or variant -- equivalents of these types. -- -- Current version of typed-encoding does not have dependencies on such -- types. -- -- These examples use CheckedEnc when untyped version of -- Enc is needed. Alternatively, an existentially quantified -- SomeEnc type could have been used. Both are isomorphic. module Examples.TypedEncoding.ToEncString type IpV4 = IpV4F Word8 -- | In this example all data fields have the same type. This simplifies -- encoding work as all fields will be encoded the same way. We use IP -- address since all fields are single byte size. data IpV4F a IpV4F :: a -> a -> a -> a -> IpV4F a [oct1] :: IpV4F a -> a [oct2] :: IpV4F a -> a [oct3] :: IpV4F a -> a [oct4] :: IpV4F a -> a tstIp :: IpV4 -- | Simplified Part header type PartHeader = [String] -- | Simplified Email header type EmailHeader = String -- | This section shows a type safe processing of emails. -- -- SimplifiedEmailF is an over-simplified email type, it has parts -- that can be either -- --
-- >>> let part = parts tstEmail L.!! 2 -- -- >>> part -- (["enc-B64","r-UTF8"],"U29tZSBVVEY4IFRleHQ=") -- -- >>> let unchecked = toUncheckedEnc (fst part) () (snd part) -- -- >>> unchecked -- MkUncheckedEnc ["enc-B64","r-UTF8"] () "U29tZSBVVEY4IFRleHQ=" ---- -- We can play Alternative (<|>) game (we acually use -- Maybe) with final option being a RecreateEx error: -- --
-- >>> check @'["enc-B64","r-ASCII"] @(Either RecreateEx) $ unchecked -- Nothing -- -- >>> check @'["enc-B64","r-UTF8"] @(Either RecreateEx) $ unchecked -- Just (Right (UnsafeMkEnc Proxy () "U29tZSBVVEY4IFRleHQ=")) ---- -- Since the data is heterogeneous (each piece has a different encoding -- annotation), we need wrap the result in another plain ADT: -- CheckedEnc. -- -- CheckedEnc is similar to UncheckedEnc with the -- difference that the only (safe) way to get values of this type is from -- properly encoded Enc values. -- -- Using unsafeCheckedEnc would break type safety here. -- -- It is important to handle all cases during encoding so decoding errors -- become impossible. -- -- Again, use of dependently typed variant types that could enumerate all -- possible encodings would made this code nicer. recreateEncoding :: SimplifiedEmail -> Either RecreateEx SimplifiedEmailEncB -- | Example decodes parts of email that are base 64 encoded text and -- nothing else. -- -- This provides a type safety assurance that we do not decode certain -- parts of email (like trying to decode base 64 on a plain text part). -- --
-- >>> decodeB64ForTextOnly <$> recreateEncoding tstEmail
-- Right (SimplifiedEmailF {emailHeader = "Some Header", parts = [UnsafeMkCheckedEnc ["enc-B64"] () "U29tZSBBU0NJSSBUZXh0",UnsafeMkCheckedEnc ["r-ASCII"] () "Some ASCII Text",UnsafeMkCheckedEnc ["r-UTF8"] () "Some UTF8 Text",UnsafeMkCheckedEnc ["r-ASCII"] () "Some ASCII plain text"]})
--
--
-- Combinator fromCheckedEnc @'["enc-B64", "r-UTF8"] acts as a
-- selector and picks only the ["enc-B64", "r-UTF8"] values from
-- our Traversable type.
--
-- We play the (<|>) game on all the selectors we want
-- picking and decoding right pieces only.
--
-- Imagine this is one of the pieces:
--
--
-- >>> let piece = unsafeCheckedEnc ["enc-B64","r-ASCII"] () ("U29tZSBBU0NJSSBUZXh0" :: B.ByteString)
--
-- >>> displ piece
-- "UnsafeMkCheckedEnc [enc-B64,r-ASCII] () (ByteString U29tZSBBU0NJSSBUZXh0)"
--
--
-- This code will not pick it up:
--
-- -- >>> fromCheckedEnc @'["enc-B64", "r-UTF8"] $ piece -- Nothing ---- -- But this one will: -- --
-- >>> fromCheckedEnc @'["enc-B64", "r-ASCII"] $ piece -- Just (UnsafeMkEnc Proxy () "U29tZSBBU0NJSSBUZXh0") ---- -- so we can apply the decoding on the selected piece -- --
-- >>> fmap (toCheckedEnc . decodePart @'["enc-B64"]) . fromCheckedEnc @'["enc-B64", "r-ASCII"] $ piece -- Just (UnsafeMkCheckedEnc ["r-ASCII"] () "Some ASCII Text") --decodeB64ForTextOnly :: SimplifiedEmailEncB -> SimplifiedEmailEncB runAlternatives' :: Alternative f => (f b -> b) -> [a -> f b] -> a -> b runAlternatives :: Alternative f => (a -> f b -> b) -> [a -> f b] -> a -> b alternatives :: Alternative f => [a -> f b] -> a -> f b instance Data.Foldable.Foldable Examples.TypedEncoding.ToEncString.IpV4F instance GHC.Base.Functor Examples.TypedEncoding.ToEncString.IpV4F instance GHC.Show.Show a => GHC.Show.Show (Examples.TypedEncoding.ToEncString.IpV4F a) instance Data.Traversable.Traversable Examples.TypedEncoding.ToEncString.SimplifiedEmailF instance Data.Foldable.Foldable Examples.TypedEncoding.ToEncString.SimplifiedEmailF instance GHC.Base.Functor Examples.TypedEncoding.ToEncString.SimplifiedEmailF instance GHC.Classes.Eq a => GHC.Classes.Eq (Examples.TypedEncoding.ToEncString.SimplifiedEmailF a) instance GHC.Show.Show a => GHC.Show.Show (Examples.TypedEncoding.ToEncString.SimplifiedEmailF a) instance Data.TypedEncoding.Common.Class.Common.Displ a => Data.TypedEncoding.Common.Class.Common.Displ (Examples.TypedEncoding.ToEncString.SimplifiedEmailF a) instance Data.TypedEncoding.Common.Class.ToEncString Data.Functor.Identity.Identity "r-IPv4" "r-IPv4" Examples.TypedEncoding.ToEncString.IpV4 Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Decode.UnexpectedDecodeErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.FromEncString @{*} f "r-IPv4" "r-IPv4" Examples.TypedEncoding.ToEncString.IpV4 Data.Text.Internal.Text instance Data.TypedEncoding.Common.Class.Common.Displ a => Data.TypedEncoding.Common.Class.Common.Displ (Examples.TypedEncoding.ToEncString.IpV4F a) -- | Examples about how to work with encoded data. This topic is (an -- interesting) work-in-progress. -- -- Modifying encoded data would typically corrupt the encoding. Current -- approach is to use Unsafe wrapping class that exposes Functor -- and (limited) Applicative and Monad instances. module Examples.TypedEncoding.Unsafe -- | Starting example exAsciiTE :: Either EncodeEx (Enc '["r-ASCII"] () Text) -- | with either removed exAsciiT :: Enc '["r-ASCII"] () Text -- | recreateFAll is the way to recover encoding in a safe way -- --
-- >>> let payload = getPayload exAsciiT -- -- >>> let newPayload = payload <> " some extra stuff" -- -- >>> recreateFAll . toEncoding () $ newPayload :: Either RecreateEx (Enc '["r-ASCII"] () T.Text) -- Right (UnsafeMkEnc Proxy () "HELLO some extra stuff") ---- -- Alternatively, UncheckedEnc type can be used in recreation, see -- Overview modifiedAsciiT :: Either RecreateEx (Enc '["r-ASCII"] () Text) -- | The issue with recreateFAll is that it may be expensive. -- -- This apprach uses Unsafe to perform (in general risky) -- operation on the internal payload. -- --
-- >>> exAsciiTE -- Right (UnsafeMkEnc Proxy () "HELLO") -- -- >>> exAsciiTE >>= pure . Unsafe.withUnsafe (fmap T.toLower) -- Right (UnsafeMkEnc Proxy () "hello") ---- -- Example uses of toLower within encoded data this operation is -- safe for ASCII restriction but Enc '["r-ASCII"] () T.Text -- does not expose it We use Functor instance of Unsafe wrapper type to -- accomplish this toLowerAscii :: Either EncodeEx (Enc '["r-ASCII"] () Text) -- | Similar example uses applicative instance of Unsafe -- --
-- >>> let Right hELLO = exAsciiTE -- -- >>> let Right hello = toLowerAscii -- -- >>> displ $ Unsafe.runUnsafe ((<>) <$> Unsafe.Unsafe hELLO <*> Unsafe.Unsafe hello) -- "Enc '[r-ASCII] () (Text HELLOhello)" --appendAscii :: Either EncodeEx (Enc '["r-ASCII"] () Text) -- | Some helper definitions used in Examples module Examples.TypedEncoding.Util -- | Polymorphic data payloads used to encode/decode -- -- This class is intended for example use only and will be moved to -- Example modules. -- -- Use your favorite polymorphic records / ad-hock product polymorphism -- library. class HasA a c has :: HasA a c => c -> a instance Examples.TypedEncoding.Util.HasA () c -- | This module defines some example "do-" encodings -- -- See Examples.TypedEncoding.Overview for usage examples. -- -- (moved from Data.TypedEncoding.Instances.Do.Sample) module Examples.TypedEncoding.Instances.Do.Sample newtype SizeLimit SizeLimit :: Int -> SizeLimit [unSizeLimit] :: SizeLimit -> Int instance GHC.Show.Show Examples.TypedEncoding.Instances.Do.Sample.SizeLimit instance GHC.Classes.Eq Examples.TypedEncoding.Instances.Do.Sample.SizeLimit instance (Examples.TypedEncoding.Util.HasA Examples.TypedEncoding.Instances.Do.Sample.SizeLimit c, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Encode.Encode f "do-size-limit" "do-size-limit" c Data.Text.Internal.Text instance (Examples.TypedEncoding.Util.HasA Examples.TypedEncoding.Instances.Do.Sample.SizeLimit c, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Encode.Encode f "do-size-limit" "do-size-limit" c Data.ByteString.Internal.ByteString instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-UPPER" "do-UPPER" c Data.Text.Internal.Text instance (Data.TypedEncoding.Common.Class.Validate.RecreateErr @{*} f, GHC.Base.Applicative f) => Data.TypedEncoding.Common.Class.Validate.Validate f "do-UPPER" "do-UPPER" c Data.Text.Internal.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-UPPER" "do-UPPER" c Data.Text.Internal.Lazy.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-lower" "do-lower" c Data.Text.Internal.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-lower" "do-lower" c Data.Text.Internal.Lazy.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-Title" "do-Title" c Data.Text.Internal.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-Title" "do-Title" c Data.Text.Internal.Lazy.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-reverse" "do-reverse" c Data.Text.Internal.Text instance GHC.Base.Applicative f => Data.TypedEncoding.Common.Class.Encode.Encode f "do-reverse" "do-reverse" c Data.Text.Internal.Lazy.Text -- | type-encoding overview examples. -- -- This library is concerned with 3 main operations done on strings: -- encoding, decoding, and recovery. Examples in -- this module cover all of these base cases. -- -- This module uses encoding instances found in -- --
-- >>> helloB64 -- UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ=" ---- --
-- >>> displ helloB64 -- "Enc '[enc-B64] () (ByteString SGVsbG8gV29ybGQ=)" ---- --
-- >>> encodeAll . toEncoding () $ "Hello World" :: Enc '["enc-B64"] () B.ByteString -- UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ=" --helloB64 :: Enc '["enc-B64"] () ByteString -- | "Hello World" double-Base64 encoded. Notice the same code used as in -- single encoding, the game is played at type level. -- --
-- >>> encodeAll . toEncoding () $ "Hello World" :: Enc '["enc-B64","enc-B64"] () B.ByteString -- UnsafeMkEnc Proxy () "U0dWc2JHOGdWMjl5YkdRPQ==" ---- --
-- >>> displ helloB64B64 -- "Enc '[enc-B64,enc-B64] () (ByteString U0dWc2JHOGdWMjl5YkdRPQ==)" ---- -- An alternative version of the above code is this: -- --
-- >>> fmap displ . runEncodings' @'["enc-B64","enc-B64"] @'["enc-B64","enc-B64"] @Identity encodings . toEncoding () $ ("Hello World" :: B.ByteString)
-- Identity "Enc '[enc-B64,enc-B64] () (ByteString U0dWc2JHOGdWMjl5YkdRPQ==)"
--
--
-- This is how typed-encoding works, the
-- Data.TypedEncoding.Common.Class.Encode.EncodeAll constraint can
-- be used to get access to list to encodings required by the symbol
-- annotation. runEncodings' executes all the necessary
-- transformations.
--
-- Similar story is true for decoding and validation. In
-- these examples we will use shortcut combinators.
helloB64B64 :: Enc '["enc-B64", "enc-B64"] () ByteString
-- | Previous text decoded from Base64
--
-- -- >>> fromEncoding . decodeAll $ helloB64 -- "Hello World" --helloB64Decoded :: ByteString -- | recreateFAll allows for recovering data at program boundaries -- (for example, when parsing JSON input). It makes sure that the content -- satisfies specified encodings. -- --
-- >>> recreateFAll . toEncoding () $ "SGVsbG8gV29ybGQ=" :: Either RecreateEx (Enc '["enc-B64"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ=") ---- --
-- >>> recreateFAll . toEncoding () $ "SGVsbG8gV29ybGQ" :: Either RecreateEx (Enc '["enc-B64"] () B.ByteString)
-- Left (RecreateEx "enc-B64" ("Base64-encoded bytestring is unpadded or has invalid padding"))
--
--
-- The above example start by placing payload in zero-encoded Enc '[]
-- () type and then apply recreateFAll this is a good way to
-- recreate encoded type if encoding is known.
--
-- If is it not, UncheckedEnc type can be used.
--
-- (See ToEncString for better example).
--
-- This module is concerned only with the first approach.
--
--
-- >>> let unchecked = toUncheckedEnc ["enc-B64"] () ("SGVsbG8gV29ybGQ=" :: T.Text)
--
-- >>> check @'["enc-B64"] @(Either RecreateEx) unchecked
-- Just (Right (UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ="))
--
helloB64Recovered :: Either RecreateEx (Enc '["enc-B64"] () ByteString)
-- | Double Base64 encoded "Hello World" with one layer of encoding removed
--
-- -- >>> decodePart @'["enc-B64"] $ helloB64B64 :: Enc '["enc-B64"] () B.ByteString -- UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ=" ---- --
-- >>> helloB64B64PartDecode == helloB64 -- True ---- -- decodePart is a convenience function that simply replies -- decoding above first "enc-B64" -- --
-- >>> above @'["enc-B64"] @'["enc-B64"] @'[] decodeAll $ helloB64B64 -- UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ=" --helloB64B64PartDecode :: Enc '["enc-B64"] () ByteString -- | helloB64B64 all the way to ByteString -- -- Notice a similar polymorphism in decoding. -- --
-- >>> fromEncoding . decodeAll $ helloB64B64 :: B.ByteString -- "Hello World" ---- -- We can also decode all the parts: -- --
-- >>> fromEncoding . decodePart @'["enc-B64","enc-B64"] $ helloB64B64 -- "Hello World" --helloB64B64Decoded :: ByteString -- | what happens when we try to recover encoded once text to Enc -- '["enc-B64", "enc-B64"]. -- -- Again, notice the same expression is used as in previous recovery. -- --
-- >>> recreateFAll . toEncoding () $ "SGVsbG8gV29ybGQ=" :: Either RecreateEx (Enc '["enc-B64", "enc-B64"] () B.ByteString)
-- Left (RecreateEx "enc-B64" ("Base64-encoded bytestring is unpadded or has invalid padding"))
--
helloB64B64RecoveredErr :: Either RecreateEx (Enc '["enc-B64", "enc-B64"] () ByteString)
-- | "do-UPPER" (from Sample module) encoding applied to "Hello
-- World"
--
-- Notice a namespace thing going on, "enc-" is encoding, "do-" is some
-- transformation. These are typically not reversible, some could be
-- recoverable.
--
-- The same code is used as in "enc-" examples to encode (now transform).
--
-- -- >>> encodeAll . toEncoding () $ "Hello World" :: Enc '["do-UPPER"] () T.Text -- UnsafeMkEnc Proxy () "HELLO WORLD" --helloUPP :: Enc '["do-UPPER"] () Text -- | Sample compound transformation -- --
-- >>> encodeAll . toEncoding () $ "HeLLo world" :: Enc '["do-reverse", "do-Title"] () T.Text -- UnsafeMkEnc Proxy () "dlroW olleH" --helloTitleRev :: Enc '["do-reverse", "do-Title"] () Text -- | Example configuration newtype Config Config :: SizeLimit -> Config [sizeLimit] :: Config -> SizeLimit exampleConf :: Config -- | helloTitle' is needed in following examples helloTitle :: Enc '["do-Title"] Config Text -- | Configuration can be used to impact the encoding process. -- -- So far we had used () as configuration of all encodings. But -- since both "do-reverse", "do-Title" are polymorphic in configuration -- we can also do this: -- --
-- >>> encodeAll . toEncoding exampleConf $ "HeLLo world" :: Enc '["do-reverse", "do-Title"] Config T.Text
-- UnsafeMkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "dlroW olleH"
--
--
--
-- >>> encodeAll . toEncoding exampleConf $ "HeLlo world" :: Enc '["do-size-limit", "do-reverse", "do-Title"] Config T.Text
-- UnsafeMkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "dlroW ol"
--
--
-- Instead, encode previously defined helloTitle by reversing it
-- and adding size limit
--
--
-- >>> encodePart @'["do-size-limit", "do-reverse"] helloTitle :: Enc '["do-size-limit", "do-reverse", "do-Title"] Config T.Text
-- UnsafeMkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "dlroW ol"
--
--
-- encodePart is simply encodeAll played above "do-Title"
-- encoding:
--
--
-- >>> above @'["do-Title"] @'[] @'["do-size-limit", "do-reverse"] encodeAll helloTitle
-- UnsafeMkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "dlroW ol"
--
helloRevLimit :: Enc '["do-size-limit", "do-reverse", "do-Title"] Config Text
helloLimitB64 :: Enc '["enc-B64", "do-size-limit"] Config ByteString
-- | ... and we unwrap the B64 part only
--
--
-- >>> decodePart @'["enc-B64"] $ helloLimitB64
-- UnsafeMkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "HeLlo wo"
--
helloRevLimitParDec :: Enc '["do-size-limit"] Config ByteString
-- | ASCII char set ByteStrings are sequences of Bytes (Word8). The
-- type is very permissive, it may contain binary data such as jpeg
-- picture.
--
-- "r-ASCII" encoding acts as partial identity function it does not
-- change any bytes in bytestring but it fails if a byte is outside of
-- ASCII range (in Either monad).
--
-- Note naming thing: "r-" is partial identity ("r-" is from
-- restriction).
--
-- -- >>> _runEncodings encodings . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-ASCII"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "HeLlo world") ---- -- or equivalently -- --
-- >>> encodeFAll . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-ASCII"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "HeLlo world") --helloAscii :: Either EncodeEx (Enc '["r-ASCII"] () ByteString) -- | Arguably the type we used for helloB64 was too permissive. a better -- version is here: -- --
-- >>> encodeFAll . toEncoding () $ "Hello World" :: Either EncodeEx (Enc '["enc-B64", "r-ASCII"] () B.ByteString) -- Right (UnsafeMkEnc Proxy () "SGVsbG8gV29ybGQ=") --helloAsciiB64 :: Either EncodeEx (Enc '["enc-B64", "r-ASCII"] () ByteString) -- |
-- >>> decodePart @'["enc-B64"] <$> helloAsciiB64 -- Right (UnsafeMkEnc Proxy () "Hello World") --helloAsciiB64PartDec :: Either EncodeEx (Enc '["r-ASCII"] () ByteString) instance GHC.Show.Show Examples.TypedEncoding.Overview.Config instance Examples.TypedEncoding.Util.HasA Examples.TypedEncoding.Instances.Do.Sample.SizeLimit Examples.TypedEncoding.Overview.Config module Examples.TypedEncoding