-- 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.1.0.0 -- | Internal definition of types module Data.TypedEncoding.Internal.Types data Enc enc 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 [MkEnc] :: Proxy enc -> conf -> str -> Enc enc conf str toEncoding :: conf -> str -> Enc '[] conf str fromEncoding :: Enc '[] conf str -> str implTranF :: Functor f => (str -> f str) -> Enc enc1 conf str -> f (Enc enc2 conf str) implEncodeF :: (Show err, KnownSymbol x) => Proxy x -> (str -> Either err str) -> Enc enc1 conf str -> Either EncodeEx (Enc enc2 conf str) implDecodeF :: Functor f => (str -> f str) -> Enc enc1 conf str -> f (Enc enc2 conf str) implCheckPrevF :: 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) implEncodeF' :: (Show err, KnownSymbol x) => Proxy x -> (conf -> str -> Either err str) -> Enc enc1 conf str -> Either EncodeEx (Enc enc2 conf str) implDecodeF' :: 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) implEncodeP :: 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) implEncodeP' :: Applicative f => (conf -> str -> str) -> Enc enc1 conf str -> f (Enc enc2 conf str) getPayload :: Enc enc conf str -> str unsafeSetPayload :: conf -> str -> Enc enc conf str withUnsafeCoerce :: (s1 -> s2) -> Enc e1 c s1 -> Enc e2 c s2 unsafeChangePayload :: (s1 -> s2) -> Enc e c s1 -> Enc e c s2 -- | Represents errors in recovery (recreation of encoded types). data RecreateEx [RecreateEx] :: (Show e, KnownSymbol x) => Proxy x -> e -> RecreateEx -- | Represents errors in encoding data EncodeEx [EncodeEx] :: (Show a, KnownSymbol x) => Proxy x -> a -> 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 instance forall k (enc :: k) conf str. (GHC.Classes.Eq conf, GHC.Classes.Eq str) => GHC.Classes.Eq (Data.TypedEncoding.Internal.Types.Enc enc conf str) instance forall k (enc :: k) conf str. (GHC.Show.Show conf, GHC.Show.Show str) => GHC.Show.Show (Data.TypedEncoding.Internal.Types.Enc enc conf str) instance GHC.Show.Show Data.TypedEncoding.Internal.Types.UnexpectedDecodeEx instance GHC.Show.Show Data.TypedEncoding.Internal.Types.EncodeEx instance GHC.Show.Show Data.TypedEncoding.Internal.Types.RecreateEx module Data.TypedEncoding.Internal.Class class EncodeF f instr outstr encodeF :: EncodeF f instr outstr => instr -> f outstr class EncodeFAll f (xs :: [k]) c str encodeFAll :: EncodeFAll f xs c str => Enc '[] c str -> f (Enc xs c str) encodeAll :: EncodeFAll Identity (xs :: [k]) c str => Enc '[] c str -> Enc xs c str class DecodeF f instr outstr decodeF :: DecodeF f instr outstr => instr -> f outstr class DecodeFAll f (xs :: [k]) c str decodeFAll :: DecodeFAll f xs c str => Enc xs c str -> f (Enc '[] c str) decodeAll :: DecodeFAll Identity (xs :: [k]) c str => Enc xs c str -> Enc '[] c str -- | Used to safely recover encoded data validating all encodingss class RecreateF f instr outstr checkPrevF :: RecreateF f instr outstr => outstr -> f instr class (Functor f) => RecreateFAll f (xs :: [k]) c str checkFAll :: RecreateFAll f xs c str => Enc xs c str -> f (Enc '[] c str) recreateFAll :: RecreateFAll f xs c str => Enc '[] c str -> f (Enc xs c str) recreateAll :: RecreateFAll Identity (xs :: [k]) c str => Enc '[] c str -> Enc xs c str -- | TODO use singletons definition instead? type family Append (xs :: [k]) (ys :: [k]) :: [k] encodeFPart :: forall f xs xsf c str. (Functor f, EncodeFAll f xs c str) => Proxy xs -> Enc xsf c str -> f (Enc (Append xs xsf) c str) encodePart :: EncodeFAll Identity (xs :: [k]) c str => Proxy xs -> Enc xsf c str -> Enc (Append xs xsf) c str -- | Unsafe implementation guarded by safe type definition decodeFPart :: forall f xs xsf c str. (Functor f, DecodeFAll f xs c str) => Proxy xs -> Enc (Append xs xsf) c str -> f (Enc xsf c str) decodePart :: DecodeFAll Identity (xs :: [k]) c str => Proxy xs -> Enc (Append xs xsf) c str -> Enc xsf c str class Subset (x :: k) (y :: k) inject :: Subset x y => Proxy y -> Enc (x : xs) c str -> Enc (y : xs) c str class FlattenAs (x :: k) (y :: k) flattenAs :: FlattenAs x y => Proxy y -> Enc (x : xs) c str -> Enc '[y] c str -- | Polymorphic data payloads used to encode/decode class HasA c a has :: HasA c a => Proxy a -> c -> a -- | With type safety in pace 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 :: (UnexpectedDecodeErr f, Applicative f, Show err, KnownSymbol x) => Proxy x -> Either err a -> f a -- | 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 -- | Human friendly version of Show class Displ x displ :: Displ x => x -> String errorOnLeft :: Show err => Either err a -> a instance Data.TypedEncoding.Internal.Class.Displ GHC.Base.String instance Data.TypedEncoding.Internal.Class.Displ Data.Text.Internal.Text instance Data.TypedEncoding.Internal.Class.Displ Data.Text.Internal.Lazy.Text instance Data.TypedEncoding.Internal.Class.Displ Data.ByteString.Internal.ByteString instance Data.TypedEncoding.Internal.Class.Displ Data.ByteString.Lazy.Internal.ByteString instance Data.TypedEncoding.Internal.Class.Displ (Data.Proxy.Proxy '[]) instance (pxs Data.Type.Equality.~ Data.Proxy.Proxy xs, Data.TypedEncoding.Internal.Class.Displ pxs, GHC.TypeLits.KnownSymbol x) => Data.TypedEncoding.Internal.Class.Displ (Data.Proxy.Proxy (x : xs)) instance forall k (xs :: k) c str. (Data.TypedEncoding.Internal.Class.Displ (Data.Proxy.Proxy xs), GHC.Show.Show c, Data.TypedEncoding.Internal.Class.Displ str) => Data.TypedEncoding.Internal.Class.Displ (Data.TypedEncoding.Internal.Types.Enc xs c str) instance Data.TypedEncoding.Internal.Class.RecreateErr (Data.Either.Either Data.TypedEncoding.Internal.Types.RecreateEx) instance Data.TypedEncoding.Internal.Class.UnexpectedDecodeErr Data.Functor.Identity.Identity instance Data.TypedEncoding.Internal.Class.UnexpectedDecodeErr (Data.Either.Either Data.TypedEncoding.Internal.Types.UnexpectedDecodeEx) instance Data.TypedEncoding.Internal.Class.HasA a () instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.RecreateFAll f '[] c str instance forall k (f :: * -> *) (xs :: [k]) c str (x :: k). (GHC.Base.Monad f, Data.TypedEncoding.Internal.Class.RecreateFAll f xs c str, Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c str) (Data.TypedEncoding.Internal.Types.Enc (x : xs) c str)) => Data.TypedEncoding.Internal.Class.RecreateFAll f (x : xs) c str instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeFAll f '[] c str instance forall k (f :: * -> *) (xs :: [k]) c str (x :: k). (GHC.Base.Monad f, Data.TypedEncoding.Internal.Class.DecodeFAll f xs c str, Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc (x : xs) c str) (Data.TypedEncoding.Internal.Types.Enc xs c str)) => Data.TypedEncoding.Internal.Class.DecodeFAll f (x : xs) c str instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeFAll f '[] c str instance forall k (f :: * -> *) (xs :: [k]) c str (x :: k). (GHC.Base.Monad f, Data.TypedEncoding.Internal.Class.EncodeFAll f xs c str, Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c str) (Data.TypedEncoding.Internal.Types.Enc (x : xs) c str)) => Data.TypedEncoding.Internal.Class.EncodeFAll f (x : xs) c str -- | Exports for encoding instance creation module Data.TypedEncoding.Instances.Support -- | This module defines some sample "do-" encodings currently for example -- use only. module Data.TypedEncoding.Instances.Encode.Sample newtype SizeLimit SizeLimit :: Int -> SizeLimit [unSizeLimit] :: SizeLimit -> Int instance GHC.Show.Show Data.TypedEncoding.Instances.Encode.Sample.SizeLimit instance GHC.Classes.Eq Data.TypedEncoding.Instances.Encode.Sample.SizeLimit instance (Data.TypedEncoding.Internal.Class.HasA c Data.TypedEncoding.Instances.Encode.Sample.SizeLimit, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-size-limit" : xs) c Data.Text.Internal.Text) instance (Data.TypedEncoding.Internal.Class.HasA c Data.TypedEncoding.Instances.Encode.Sample.SizeLimit, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("do-size-limit" : xs) c Data.ByteString.Internal.ByteString) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-UPPER" : xs) c Data.Text.Internal.Text) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-UPPER" : xs) c Data.Text.Internal.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-UPPER" : xs) c Data.Text.Internal.Lazy.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-lower" : xs) c Data.Text.Internal.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-lower" : xs) c Data.Text.Internal.Lazy.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-Title" : xs) c Data.Text.Internal.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-Title" : xs) c Data.Text.Internal.Lazy.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-reverse" : xs) c Data.Text.Internal.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc ("do-reverse" : xs) c Data.Text.Internal.Lazy.Text) -- | Main Module in typed-encoding. -- --
-- -- 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"] Text -- upper = ... ---- -- Primary focus of type-encodings is to provide type safe -- --
-- >>> displ $ text2ByteStringS $ toEncoding () ("text" :: T.Text)
-- "MkEnc '[r-UTF8] () (ByteString text)"
--
text2ByteStringS :: Enc ys c Text -> Enc ("r-UTF8" : ys) c ByteString
-- | Type-safer version of Data.Text.Encoding.decodeUtf8
--
-- -- >>> let Right tst = encodeFAll . toEncoding () $ "Hello World" :: Either EncodeEx (Enc '["r-UTF8"] () B.ByteString) -- -- >>> displ $ byteString2TextS tst -- "MkEnc '[] () (Text Hello World)" --byteString2TextS :: Enc ("r-UTF8" : ys) c ByteString -> Enc ys c Text -- | Identity property "byteString2TextS . text2ByteStringS == id" prop> -- t -> t == (fromEncoding . txtBsSIdProp (Proxy :: Proxy '[]) . -- toEncoding () $ t) txtBsSIdProp :: Proxy (ys :: [Symbol]) -> Enc ys c Text -> Enc ys c Text -- | Identity property "text2ByteStringS . byteString2TextS == id". -- --
-- \(t :: Enc '["r-UTF8"] () B.ByteString) -> t == (bsTxtIdProp (Proxy :: Proxy '[]) $ t) --bsTxtIdProp :: Proxy (ys :: [Symbol]) -> Enc ("r-UTF8" : ys) c ByteString -> Enc ("r-UTF8" : ys) c ByteString text2ByteStringL :: Enc ys c Text -> Enc ("r-UTF8" : ys) c ByteString byteString2TextL :: Enc ("r-UTF8" : ys) c ByteString -> Enc ys c Text prxyUtf8 :: Proxy "r-UTF8" -- | 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 instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-UTF8" : xs) c Data.ByteString.Internal.ByteString) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-UTF8" : xs) c Data.ByteString.Internal.ByteString) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-UTF8" : xs) c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Lazy.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-UTF8" : xs) c Data.ByteString.Lazy.Internal.ByteString) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Lazy.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-UTF8" : xs) c Data.ByteString.Lazy.Internal.ByteString) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-UTF8" : xs) c Data.ByteString.Lazy.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Lazy.Internal.ByteString) -- | Strings can move to 'Enc "r-ASCII' only if they contain only ascii -- characters. they always decode back >>> :set -- -XOverloadedStrings -XMultiParamTypeClasses -XDataKinds >>> -- encodeFAll . toEncoding () $ "Hello World" :: Either EncodeEx (Enc -- '["r-ASCII"] () T.Text) Right (MkEnc Proxy () "Hello World") -- --
-- >>> encodeFAll . toEncoding () $ "\194\160" :: Either EncodeEx (Enc '["r-ASCII"] () T.Text) -- Left (EncodeEx "r-ASCII" (NonAsciiChar '\194')) --module Data.TypedEncoding.Instances.ASCII byteString2TextS :: Enc ("r-ASCII" : ys) c ByteString -> Enc ("r-ASCII" : ys) c Text byteString2TextL :: Enc ("r-ASCII" : ys) c ByteString -> Enc ("r-ASCII" : ys) c Text text2ByteStringS :: Enc ("r-ASCII" : ys) c Text -> Enc ("r-ASCII" : ys) c ByteString text2ByteStringL :: Enc ("r-ASCII" : ys) c Text -> Enc ("r-ASCII" : ys) c ByteString data NonAsciiChar NonAsciiChar :: Char -> NonAsciiChar prxyAscii :: Proxy "r-ASCII" encodeImpl :: ((Char -> Bool) -> a -> (a, a)) -> (a -> Char) -> (a -> Bool) -> a -> Either NonAsciiChar a instance GHC.Show.Show Data.TypedEncoding.Instances.ASCII.NonAsciiChar instance GHC.Classes.Eq Data.TypedEncoding.Instances.ASCII.NonAsciiChar instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c GHC.Types.Char) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c GHC.Types.Char) instance Data.TypedEncoding.Internal.Class.Subset "r-ASCII" "r-UTF8" instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c GHC.Types.Char) (Data.TypedEncoding.Internal.Types.Enc xs c GHC.Types.Char) instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.Text.Internal.Text) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.Text.Internal.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.Text.Internal.Lazy.Text) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.Text.Internal.Lazy.Text) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.Text.Internal.Lazy.Text) (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Lazy.Text) instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.ByteString.Internal.ByteString) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.ByteString.Internal.ByteString) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.ByteString.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Internal.ByteString) instance Data.TypedEncoding.Internal.Class.EncodeF (Data.Either.Either Data.TypedEncoding.Internal.Types.EncodeEx) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Lazy.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.ByteString.Lazy.Internal.ByteString) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Lazy.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.ByteString.Lazy.Internal.ByteString) instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("r-ASCII" : xs) c Data.ByteString.Lazy.Internal.ByteString) (Data.TypedEncoding.Internal.Types.Enc xs c Data.ByteString.Lazy.Internal.ByteString) -- | Examples or moving between type annotated encodings -- -- Modules that define encoding and decoding instances also provide -- conversion functions. -- -- Currently, these are separate functions, generalization of conversions -- seems hard. -- -- These examples discuss handling of subsets (for character -- sets), leniency, and flattening. module Examples.TypedEncoding.Conversions -- | Example value to play with -- --
-- >>> encodeFAll . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-ASCII"] () B.ByteString) -- Right (MkEnc Proxy () "HeLlo world") --eHelloAsciiB :: Either EncodeEx (Enc '["r-ASCII"] () ByteString) -- | above with either removed helloAsciiB :: Enc ("r-ASCII" : ([] :: [Symbol])) () ByteString -- | When converted to Text the annotation is preserved. -- -- Currently separate function is defined for each allowed conversion. -- --
-- >>> displ $ EnASCII.byteString2TextS helloAsciiB -- "MkEnc '[r-ASCII] () (Text HeLlo world)" --helloAsciiT :: Enc '["r-ASCII"] () Text -- | To get UTF8 annotation, instead of doing this: -- --
-- >>> encodeFAll . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-UTF8"] () B.ByteString) -- Right (MkEnc Proxy () "HeLlo world") ---- -- We should be able to convert the ASCII version. -- -- This is done using Subset typeclass. -- -- inject method accepts proxy to specify superset to use. -- --
-- >>> displ $ inject (Proxy :: Proxy "r-UTF8") helloAsciiB -- "MkEnc '[r-UTF8] () (ByteString HeLlo world)" --helloUtf8B :: Enc '["r-UTF8"] () ByteString -- | We put Base64 on the UFT8 ByteString -- --
-- >>> displ $ encodePart (Proxy :: Proxy '["enc-B64"]) helloUtf8B -- "MkEnc '[enc-B64,r-UTF8] () (ByteString SGVMbG8gd29ybGQ=)" --helloUtf8B64B :: Enc '["enc-B64", "r-UTF8"] () ByteString -- | .. and copy it over to Text. but UTF8 would be redundant in Text so -- the "r-UTF8" is dropped -- --
-- >>> :t EnB64.byteString2TextS helloUtf8B64B -- EnB64.byteString2TextS helloUtf8B64B :: Enc '["enc-B64"] () T.Text ---- -- Conversely moving back to ByteString recovers the annotation. (there -- could be a choice of a UTF annotation to recover in the future) -- --
-- >>> :t EnB64.text2ByteStringS helloUtf8B64T -- EnB64.text2ByteStringS helloUtf8B64T -- ... :: Enc '["enc-B64", "r-UTF8"] () B.ByteString --helloUtf8B64T :: Enc '["enc-B64"] () Text -- | notTextB a binary, one that does not even represent valid UTF8. -- --
-- >>> encodeAll . toEncoding () $ "\195\177" :: Enc '["enc-B64"] () B.ByteString -- MkEnc Proxy () "w7E=" ---- -- byteString2TextS' is a fuction that allows to convert Base 64 -- ByteString that is not UTF8. -- --
-- >>> :t EnB64.byteString2TextS' notTextB -- EnB64.byteString2TextS' notTextB -- ... :: Enc '["enc-B64-nontext"] () T.Text ---- -- The result is annotated as "enc-B64-nontext" which prevents decoding -- it within Text type. We can only move it back to ByteString as -- "enc-B64". notTextB :: Enc '["enc-B64"] () ByteString -- |
-- >>> recreateAll . toEncoding () $ "abc==CB" :: Enc '["enc-B64-len"] () B.ByteString -- MkEnc 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" ("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 -- "MkEnc '[enc-B64] () (ByteString abc=)" ---- -- This is now properly encoded data -- --
-- >>> recreateFAll . toEncoding () $ "abc=" :: Either RecreateEx (Enc '["enc-B64"] () B.ByteString) -- Right (MkEnc Proxy () "abc=") ---- -- Except the content could be surprising -- --
-- >>> decodeAll $ EnB64.acceptLenientS lenientSomething -- MkEnc 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 (Proxy :: Proxy "r-ASCII") helloUtf8B64B -- flattenAs (Proxy :: Proxy "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 RecreateF typeclass. -- -- 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.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 -- MkEnc Proxy () "11:Hello World" ---- --
-- >>> fromEncoding . decodeAll $ helloSigned -- "Hello World" --helloSigned :: Enc '["my-sign"] () Text -- | property checks that Text values are exected 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 (MkEnc Proxy () "11:Hello World") --hacker :: Either RecreateEx (Enc '["my-sign"] () Text) prxyMySign :: Proxy "my-sign" instance GHC.Base.Applicative f => Data.TypedEncoding.Internal.Class.EncodeF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("my-sign" : xs) c Data.Text.Internal.Text) instance (Data.TypedEncoding.Internal.Class.UnexpectedDecodeErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.DecodeF f (Data.TypedEncoding.Internal.Types.Enc ("my-sign" : xs) c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) instance (Data.TypedEncoding.Internal.Class.RecreateErr f, GHC.Base.Applicative f) => Data.TypedEncoding.Internal.Class.RecreateF f (Data.TypedEncoding.Internal.Types.Enc xs c Data.Text.Internal.Text) (Data.TypedEncoding.Internal.Types.Enc ("my-sign" : xs) c Data.Text.Internal.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 -- MkEnc Proxy () "SGVsbG8gV29ybGQ=" ---- --
-- >>> displ helloB64 -- "MkEnc '[enc-B64] () (ByteString SGVsbG8gV29ybGQ=)" ---- --
-- >>> encodeAll . toEncoding () $ "Hello World" :: Enc '["enc-B64"] () B.ByteString -- MkEnc Proxy () "SGVsbG8gV29ybGQ=" --helloB64 :: Enc '["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 (MkEnc Proxy () "SGVsbG8gV29ybGQ=") ---- --
-- >>> recreateFAll . toEncoding () $ "SGVsbG8gV29ybGQ" :: Either RecreateEx (Enc '["enc-B64"] () B.ByteString)
-- Left (RecreateEx "enc-B64" ("invalid padding"))
--
helloB64Recovered :: Either RecreateEx (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 -- MkEnc Proxy () "U0dWc2JHOGdWMjl5YkdRPQ==" ---- --
-- >>> displ helloB64B64 -- "MkEnc '[enc-B64,enc-B64] () (ByteString U0dWc2JHOGdWMjl5YkdRPQ==)" --helloB64B64 :: Enc '["enc-B64", "enc-B64"] () ByteString -- | Double Base64 encoded "Hello World" with one layer of encoding removed -- --
-- >>> decodePart (Proxy :: Proxy '["enc-B64"]) $ helloB64B64 :: Enc '["enc-B64"] () B.ByteString -- MkEnc Proxy () "SGVsbG8gV29ybGQ=" ---- --
-- >>> helloB64B64PartDecode == helloB64 -- True --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 (Proxy :: Proxy '["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" ("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 -- MkEnc Proxy () "HELLO WORLD" --helloUPP :: Enc '["do-UPPER"] () Text -- | Sample compound transformation -- --
-- >>> encodeAll . toEncoding () $ "HeLLo world" :: Enc '["do-reverse", "do-Title"] () T.Text -- MkEnc Proxy () "dlroW olleH" --helloTitleRev :: Enc '["do-reverse", "do-Title"] () Text -- | Example configuration data 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
-- MkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "dlroW olleH"
--
--
--
-- >>> encodeAll . toEncoding exampleConf $ "HeLlo world" :: Enc '["do-size-limit", "do-reverse", "do-Title"] Config T.Text
-- MkEnc Proxy (Config {sizeLimit = SizeLimit {unSizeLimit = 8}}) "dlroW ol"
--
--
-- Instead, encode previously defined helloTitle by reversing it
-- and adding size limit
--
--
-- >>> encodePart (Proxy :: Proxy '["do-size-limit", "do-reverse"]) helloTitle :: Enc '["do-size-limit", "do-reverse", "do-Title"] Config T.Text
-- MkEnc 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 (Proxy :: Proxy '["enc-B64"]) $ helloLimitB64
-- MkEnc 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).
--
-- -- >>> encodeFAll . toEncoding () $ "HeLlo world" :: Either EncodeEx (Enc '["r-ASCII"] () B.ByteString) -- Right (MkEnc 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 (MkEnc Proxy () "SGVsbG8gV29ybGQ=") --helloAsciiB64 :: Either EncodeEx (Enc '["enc-B64", "r-ASCII"] () ByteString) -- |
-- >>> decodePart (Proxy :: Proxy '["enc-B64"]) <$> helloAsciiB64 -- Right (MkEnc Proxy () "Hello World") --helloAsciiB64PartDec :: Either EncodeEx (Enc '["r-ASCII"] () ByteString) instance GHC.Show.Show Examples.TypedEncoding.Overview.Config instance Data.TypedEncoding.Internal.Class.HasA Examples.TypedEncoding.Overview.Config Data.TypedEncoding.Instances.Encode.Sample.SizeLimit -- | 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 (MkEnc Proxy () "HELLO some extra stuff") --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 (MkEnc Proxy () "HELLO") -- -- >>> exAsciiTE >>= pure . Unsafe.withUnsafe (fmap T.toLower) -- Right (MkEnc 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) -- "MkEnc '[r-ASCII] () (Text HELLOhello)" --appendAscii :: Either EncodeEx (Enc '["r-ASCII"] () Text) module Examples.TypedEncoding