packages feed

typed-encoding 0.4.0.0 → 0.4.1.0

raw patch · 21 files changed

+324/−48 lines, 21 files

Files

ChangeLog.md view
@@ -6,7 +6,32 @@ - (post 0.3) "enc-B64" will be moved to a different package (more distant goal) - Improved constrains in `Data.TypedEncoding.Conv` modules -##+## 0.4.1++- Code Changes. Backward compatible+   - changed order in `IsSuperset` definition to speed up compilation of of more common cases (there is a small chance that it impacts GHC error messages)+   - Faster "r-UTF8", possible issue is changed error message in case ByteString is invalid.+   - Deprecated 'validFromEnc' for its confusing name+   - Deprecated `runDecodings` in favor of consistently named `runDecodings'`+   - Deprecated `runDecoding` in favor of consistently named `runDecoding'`+   - Deprecated `runValidation` in favor of consistently named `runValidation'`++- Documentation / code comment fixes and improvements.++- New functionality `validRFromEnc'` replacing 'validFromEnc' confusing name+  - `propCompEncoding` property+  - `propSupersetCheck` property+  - `propSafeDecoding'` properties+  - `propSafeValidatedDecoding` properties+  - `IsEnc` type family and `Encoding` constraint+  - `getUncheckedPayload` function+  - `pack` and `unpack` overloads in `Data.TypedEncoding.Conv.ByteString.Char8`++- Fixes+  - corrected `propEncodesInto'` property test specification+++## 0.4  - Breaking    - IsSupersetOpen type family type arguments have changed
README.md view
@@ -72,6 +72,7 @@  Please see `Examples.TypedEncoding` it the module list. + ## Other encoding packages  My approach will be to write specific encodings (e.g. _HTTP_) or wrap encodings from other packages using separate "bridge" projects.
src/Data/TypedEncoding.hs view
@@ -1,4 +1,8 @@ +{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-} -- | -- = Overview --@@ -149,7 +153,14 @@      -- * @UncheckedEnc@ is an /untyped/ version of Enc that represents not validated encoding           , module Data.TypedEncoding.Common.Types.UncheckedEnc- ++    -- * Laws / properties++    , propSafeDecoding' +    , _propSafeDecoding+    , propSafeValidatedDecoding'+    , _propSafeValidatedDecoding+     -- * Classes     , module Data.TypedEncoding.Common.Class   @@ -187,3 +198,64 @@ import           Data.TypedEncoding.Combinators.Unsafe import           Data.TypedEncoding.Combinators.ToEncStr import           Data.TypedEncoding.Combinators.Promotion+++-- | +-- 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' encf decf c str = Right enc0 == edec+   where +       enc0 = toEncoding c str+       eenc = runEncoding' @alg encf enc0+       edec = case eenc of +           Right enc -> either (Left . show) Right $ runDecoding' @alg decf enc+           Left enc -> Right enc0 -- quick and dirty, magically decode all encoded failures  +++_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+_propSafeDecoding = propSafeDecoding' @(AlgNm nm)++-- |+-- 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' validf decf c str = edec == echeck+   where +       enc0 = toEncoding c str+       valfs = validf `ConsV` ZeroV+       eenc = recreateWithValidations @'[alg] @'[nm] valfs enc0 +       (edec :: Either String str, echeck :: Either String str) = case eenc of +           Right enc -> (either (Left . show) (Right . getPayload) $ runDecoding' @alg decf enc+                         , either (Left . show) (Right . getPayload) $ runValidation' @alg validf enc)+           Left _ -> (Left "not-recovered", Left "not-recovered")  ++_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+_propSafeValidatedDecoding = propSafeValidatedDecoding' @(AlgNm nm)
src/Data/TypedEncoding/Combinators/Decode.hs view
@@ -52,12 +52,12 @@ -- * Convenience combinators which mimic v0.2 type signatures. These do not try to figure out @algs@ or assume much about them  decodeF' :: forall alg nm xs f c str . (Decode f nm alg c str) => Enc (nm ': xs) c str -> f (Enc xs c str)-decodeF' = runDecoding (decoding @f @nm @alg)+decodeF' = runDecoding' (decoding @f @nm @alg)  decodeFAll' :: forall algs nms f c str . (Monad f,  DecodeAll f nms algs c str) =>                 Enc nms c str                -> f (Enc ('[]::[Symbol]) c str)  -decodeFAll' = runDecodings @algs @nms @f decodings +decodeFAll' = runDecodings' @algs @nms @f decodings   -- |  -- 
src/Data/TypedEncoding/Common/Class/Superset.hs view
@@ -54,7 +54,7 @@ -- @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 more /nominal/ decision that prevents certain unwanted conversions from being possible. -- -- @since 0.2.2.0 type family IsSuperset (y :: Symbol) (x :: Symbol) :: Bool where@@ -63,15 +63,15 @@     IsSuperset "r-UTF8"  "r-UTF8" = 'True     IsSuperset "r-CHAR8" "r-ASCII" = 'True  -- "r-CHAR8" is phantom, no explicit instances so it does not need reflexive case     IsSuperset "r-CHAR8" "r-ByteRep" = 'True-    IsSuperset "r-CHAR8" x = Or (IsSuperset "r-ASCII" x) (IsSupersetOpen "r-CHAR8" x (TakeUntil x ":") (ToList x))     IsSuperset "r-UNICODE.D76" "r-UNICODE.D76" = 'True      IsSuperset "r-UNICODE.D76" "r-ASCII" = 'True      IsSuperset "r-UNICODE.D76" x = Or (IsSuperset "r-CHAR8" x) (IsSupersetOpen "r-UNICODE.D76" x (TakeUntil x ":") (ToList x))+    IsSuperset "r-CHAR8" x = Or (IsSuperset "r-ASCII" x) (IsSupersetOpen "r-CHAR8" x (TakeUntil x ":") (ToList x))     IsSuperset y x = IsSupersetOpen y x (TakeUntil x ":") (ToList x) --- backward compatible r-CHAR8--- IsSuperset "r-CHAR8" x = Or (IsSuperset "r-ASCII" x) (IsSupersetOpen "r-CHAR8" (TakeUntil x ":") (ToList x))+-- TODO introduce "r-NODEC" which does not decode + -- | -- @since 0.2.2.0 type family IsSupersetOpen (big :: Symbol) (nm :: Symbol) (alg :: Symbol) (nmltrs :: [Symbol]) :: Bool@@ -101,7 +101,18 @@                  -> Encoding (Either EncodeEx) s algs () str                   -> str                   -> Bool-propSuperset' encb encs str = +propSuperset' = propSupersetCheck @algb @algs+        +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+propSuperset_ = propSupersetCheck @algb @algs++propSupersetCheck :: forall algb algs b s str . (Eq str) +                 => +                 Encoding (Either EncodeEx) b algb () str +                 -> Encoding (Either EncodeEx) s algs () str +                 -> str +                 -> Bool+propSupersetCheck encb encs str =      case (isLeft rb, isLeft rs) of          (True, False) -> False         (False, False) -> pb == ps@@ -112,9 +123,6 @@         rs = runEncoding' @algs encs . toEncoding () $ str          pb = either (const str) id $ getPayload <$> rb         ps = either (const str) id $ getPayload <$> rs-        -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-propSuperset_ = propSuperset' @algb @algs  -- | -- IsSuperset is not intended for @"enc-"@ encodings. This class is.@@ -140,14 +148,12 @@ -- Actual tests in the project /test/ suite. propEncodesInto' :: forall algb algr b r str . (EncodingSuperset b, r ~ EncSuperset b, Eq str) => Encoding (Either EncodeEx) b algb () str -> Encoding (Either EncodeEx) r algr () str -> str -> Bool propEncodesInto' encb encr str = -    case rb of-        Left _ -> True-        Right enc -> case runEncoding' @algr encr . toEncoding () $ getPayload enc of-            Right _ -> True-            Left _ -> False  -    where-        rb = runEncoding' @algb encb . toEncoding () $ str -+   case runEncoding' @algb encb . toEncoding () $ str of+            Right r -> case runEncoding' @algr encr . toEncoding () $ getPayload r of+                Left _ -> False+                Right _ -> True+            Left _ -> True  +  propEncodesInto_ :: forall b r str algb algr. (     EncodingSuperset b     , r ~ EncSuperset b@@ -159,6 +165,19 @@        -> str         -> Bool propEncodesInto_ = propEncodesInto' @algb @algr+++-- | 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+propCompEncoding encb encr str = +    case rr of+        Left _ -> True+        Right _ -> case runEncoding' @algb encb . toEncoding () $ str of+            Right _ -> True+            Left _ -> False  +    where+        rr = runEncoding' @algr encr . toEncoding () $ str +  -- |  -- Aggregate version of 'EncodingSuperset' 
src/Data/TypedEncoding/Common/Types/Common.hs view
@@ -26,14 +26,22 @@ type EncAnn = String      -- | --- Contraint for "r-" annotations.+-- Constraint for "r-" annotations. -- -- @since 0.3.0.0 type Restriction s = (KnownSymbol s, IsR s ~ 'True) + -- | --- Contraint for algorithm name.+-- Constraint for "r-" annotations. --+-- @since 0.4.1.0+type EncodingAnn s = (KnownSymbol s, IsEnc s ~ 'True)+++-- | +-- Constraint for algorithm name.+-- -- @since 0.3.0.0 type Algorithm nm alg = AlgNm nm ~ alg @@ -87,3 +95,13 @@ type family RemoveRs (s :: [Symbol]) :: [Symbol] where     RemoveRs '[] = '[]     RemoveRs (x ': xs) = If (OrdBool (CmpSymbol "r-" (Take 2 x))) (RemoveRs xs) (x ': RemoveRs xs) +++-- | +-- >>> :kind! IsEnc "enc-boo"+-- ...+-- = 'True+--+-- @since 0.4.1.0 +type family IsEnc (s :: Symbol) :: Bool where+    IsEnc s = AcceptEq ('Text "Not enc- encoding " ':<>: ShowType s ) (CmpSymbol "enc-" (Take 4 s))
src/Data/TypedEncoding/Common/Types/Decoding.hs view
@@ -52,6 +52,13 @@ runDecoding :: forall alg nm f xs conf str . Decoding f nm alg conf str -> Enc (nm ': xs) conf str -> f (Enc xs conf str) runDecoding (UnsafeMkDecoding _ fn) = fn +{-# DEPRECATED runDecoding "Use runDecoding'" #-}++-- |+-- @since 0.3.0.0+runDecoding' :: forall alg nm f xs conf str . Decoding f nm alg conf str -> Enc (nm ': xs) conf str -> f (Enc xs conf str)+runDecoding' (UnsafeMkDecoding _ fn) = fn+ -- | Same as 'runDecoding" but compiler figures out algorithm name -- -- Using it can slowdown compilation@@ -76,11 +83,16 @@ -- | -- @since 0.3.0.0 runDecodings :: forall algs nms f c str . (Monad f) => Decodings f nms algs c str -> Enc nms c str -> f (Enc ('[]::[Symbol]) c str)-runDecodings ZeroD enc0 = pure enc0-runDecodings (ConsD fn xs) enc = +runDecodings = runDecodings' @algs @nms++{-# DEPRECATED runDecodings "Use runDecodings'" #-}+++runDecodings' :: forall algs nms f c str . (Monad f) => Decodings f nms algs c str -> Enc nms c str -> f (Enc ('[]::[Symbol]) c str)+runDecodings' ZeroD enc0 = pure enc0+runDecodings' (ConsD fn xs) enc =          let re :: f (Enc _ c str) = runDecoding fn enc         in re >>= runDecodings xs-  -- | At possibly big compilation cost, have compiler figure out algorithm names. --
src/Data/TypedEncoding/Common/Types/UncheckedEnc.hs view
@@ -44,6 +44,10 @@ getUncheckedEncAnn :: UncheckedEnc c str -> [EncAnn] getUncheckedEncAnn (MkUncheckedEnc ann _ _) = ann ++getUncheckedPayload :: forall c str . UncheckedEnc c str -> str+getUncheckedPayload (MkUncheckedEnc _ _ str) = str+ -- | -- @since 0.2.0.0  verifyAnn :: forall xs c str . SymbolList xs => UncheckedEnc c str -> Either String (UncheckedEnc c str)
src/Data/TypedEncoding/Common/Types/Validation.hs view
@@ -54,13 +54,18 @@ runValidation :: forall alg nm f xs conf str . Validation f nm alg conf str -> Enc (nm ': xs) conf str -> f (Enc xs conf str) runValidation (UnsafeMkValidation _ fn) = fn +{-# DEPRECATED runValidation "Use runValidation''" #-}++runValidation' :: forall alg nm f xs conf str . Validation f nm alg conf str -> Enc (nm ': xs) conf str -> f (Enc xs conf str)+runValidation' (UnsafeMkValidation _ fn) = fn+ -- | Same as 'runValidation" but compiler figures out algorithm name -- -- Using it can slowdown compilation -- -- @since 0.3.0.0 _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)-_runValidation = runValidation @(AlgNm nm)+_runValidation = runValidation' @(AlgNm nm)  -- | -- Wraps a list of @Validation@ elements.@@ -82,7 +87,7 @@ runValidationChecks :: forall algs nms f c str . (Monad f) => Validations f nms algs c str -> Enc nms c str -> f (Enc ('[]::[Symbol]) c str) runValidationChecks ZeroV enc0 = pure enc0 runValidationChecks (ConsV fn xs) enc = -        let re :: f (Enc _ c str) = runValidation fn enc+        let re :: f (Enc _ c str) = runValidation' fn enc         in re >>= runValidationChecks xs  
src/Data/TypedEncoding/Conv.hs view
@@ -80,6 +80,9 @@ -- @ -- -- @"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 'T.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.@@ -99,15 +102,16 @@ -- 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 B.ByteString+--     -> Enc [Symbol] ((':) Symbol "r-ASCII" ('[] Symbol)) c B8.ByteString ----- ghci> :t EncB8.pack @'["r-ASCII"]+-- ghci> :t EB8.pack @'["r-ASCII"] --  :: Enc [Symbol] ((':) Symbol "r-ASCII" ('[] Symbol)) c String---    -> Enc [Symbol] ((':) Symbol "r-ASCII" ('[] Symbol)) c B.ByteString+--    -> Enc [Symbol] ((':) Symbol "r-ASCII" ('[] Symbol)) c B8.ByteString -- @   -- -- They both accept that common denominator.  
src/Data/TypedEncoding/Conv/ByteString/Char8.hs view
@@ -14,14 +14,16 @@  -- $setup -- >>> :set -XDataKinds -XTypeApplications -XOverloadedStrings+-- >>> import Data.TypedEncoding.Instances.Enc.Base64 ()  -- |  -- Type safer version of 'Data.ByteString.Char8.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 alternatives with different safety levels.+-- 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 @@ -47,6 +49,21 @@     ) => Enc xs c String -> Enc xs c B8.ByteString pack = unsafeChangePayload B8.pack +-- |+-- Version of pack that works without first "r-" encoding.+--+-- >>> displ $ pack'' (unsafeSetPayload () "SGVsbG8gV29ybGQ=" :: Enc '["enc-B64"] () String)+-- "Enc '[enc-B64] () (ByteString SGVsbG8gV29ybGQ=)"+--+--  @since 0.4.1.0+pack'' :: (+    Knds.UnSnoc xs ~ '(,) ys y+    , EncodingAnn y+    , encs ~ RemoveRs ys+    , AllEncodeInto "r-CHAR8" encs+    ) => Enc xs c String -> Enc xs c B8.ByteString+pack'' = unsafeChangePayload B8.pack+ -- | @unpack@ on encoded strings. -- -- See 'pack'@@ -65,3 +82,18 @@           ) => Enc xs c B8.ByteString -> Enc xs c String unpack = unsafeChangePayload B8.unpack       ++-- |+-- Version of pack that works without first "r-" encoding+--+-- >>> displ $ unpack'' (unsafeSetPayload () "SGVsbG8gV29ybGQ=" :: Enc '["enc-B64"] () B8.ByteString)+-- "Enc '[enc-B64] () (String SGVsbG8gV29ybGQ=)"+--+--  @since 0.4.1.0+unpack'' :: (+          Knds.UnSnoc xs ~ '(,) ys y+         , EncodingAnn y+         , encs ~ RemoveRs ys+         , AllEncodeInto "r-CHAR8" encs+          ) => Enc xs c B8.ByteString -> Enc xs c String+unpack'' = unsafeChangePayload B8.unpack     
src/Data/TypedEncoding/Conv/ByteString/Lazy/Char8.hs view
@@ -34,3 +34,23 @@         , AllEncodeInto "r-CHAR8" encs        ) => Enc xs c BL8.ByteString -> Enc xs c String unpack = unsafeChangePayload BL8.unpack          ++-- | +-- Lazy version of 'Data.TypedEncoding.Conv.ByteString.Char8.pack'''.+pack'' :: (+    Knds.UnSnoc xs ~ '(,) ys y+    , EncodingAnn y+    , encs ~ RemoveRs ys+    , AllEncodeInto "r-CHAR8" encs+    ) => Enc xs c String -> Enc xs c BL8.ByteString+pack'' = unsafeChangePayload BL8.pack++-- | +-- Lazy version of 'Data.TypedEncoding.Conv.ByteString.Char8.unpack'''.+unpack'' :: (+          Knds.UnSnoc xs ~ '(,) ys y+         , EncodingAnn y+         , encs ~ RemoveRs ys+         , AllEncodeInto "r-CHAR8" encs+          ) => Enc xs c BL8.ByteString -> Enc xs c String+unpack'' = unsafeChangePayload BL8.unpack     
src/Data/TypedEncoding/Conv/Text.hs view
@@ -16,7 +16,9 @@ -- >>> :set -XDataKinds -XTypeFamilies -XTypeApplications  --- | This assumes that each of the encodings in @xs@ work work equivalently in @String@ and @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 :: (           Knds.UnSnoc xs ~ '(,) ys y          , Superset "r-UNICODE.D76" y @@ -25,7 +27,8 @@           ) => Enc xs c String -> Enc xs c T.Text pack = unsafeChangePayload T.pack --- | This assumes that each of the encodings in @xs@ work work equivalently in @String@ and @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 :: (           Knds.UnSnoc xs ~ '(,) ys y          , Superset "r-UNICODE.D76" y 
src/Data/TypedEncoding/Conv/Text/Encoding.hs view
@@ -53,6 +53,16 @@ -- | -- 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 'T.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.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream+-- +-- The "\xdfff" case (@11101101 10111111 10111111@ @ed bf bf@):+-- >>> TE.decodeUtf8 "\237\191\191"+-- "*** Exception: Cannot decode byte '\xed': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream+-- -- >>> displ . decodeUtf8 $ (unsafeSetPayload () "Hello" :: Enc '["r-ASCII"] () B.ByteString) -- "Enc '[r-ASCII] () (Text Hello)" --
src/Data/TypedEncoding/Instances/Enc/Base64.hs view
@@ -32,7 +32,15 @@ -- >>> import Test.QuickCheck -- >>> import Test.QuickCheck.Instances.Text() -- >>> import Test.QuickCheck.Instances.ByteString()+-- >>> :{  +-- instance Arbitrary (UncheckedEnc () B.ByteString) where +--      arbitrary = do+--          payload <- frequency [ (5, fmap (getPayload . encodeAll @'["enc-B64"] @(). toEncoding ()) $ arbitrary) +--                             , (1, arbitrary)]+--          pure $ toUncheckedEnc ["enc-B64"] () payload+-- :} + ----------------- -- * Conversions -----------------@@ -92,6 +100,7 @@     encoding = encB64B  -- |+-- -- @since 0.3.0.0  encB64B :: Applicative f => Encoding f "enc-B64" "enc-B64" c B.ByteString encB64B = _implEncodingP B64.encode@@ -130,6 +139,10 @@ -- making undetectable changes, but error handling at this stage -- could verify that email was corrupted. --+-- prop> _propSafeDecoding @"enc-B64" @() @B.ByteString encB64B decB64B ()+-- +-- prop> _propSafeValidatedDecoding @"enc-B64" @() @B.ByteString validation decB64B () . getUncheckedPayload @() @B.ByteString+-- -- @since 0.3.0.0 decB64B :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "enc-B64" "enc-B64" c B.ByteString decB64B = _implDecodingF (asUnexpected @"enc-B64" . B64.decode)@@ -140,6 +153,8 @@     decoding = decB64BL  -- |+-- prop> _propSafeDecoding @"enc-B64" @() @BL.ByteString encB64BL decB64BL+-- -- @since 0.3.0.0  decB64BL :: (UnexpectedDecodeErr f, Applicative f) => Decoding f "enc-B64" "enc-B64" c BL.ByteString decB64BL = _implDecodingF (asUnexpected @"enc-B64" . BL64.decode)
src/Data/TypedEncoding/Instances/Restriction/BoundedAlphaNums.hs view
@@ -85,7 +85,7 @@ -- * Validation  instance (KnownSymbol s , Ban s, Algorithm s "r-ban", IsStringR str, RecreateErr f, Applicative f) => Validate f s "r-ban" c str where-    validation = validFromEnc' @"r-ban" encFBan+    validation = validRFromEnc' @"r-ban" encFBan   -- * Implementation
src/Data/TypedEncoding/Instances/Restriction/D76.hs view
@@ -12,7 +12,7 @@ -- U+D800 to U+DFFF inclusive) -- -- Note, 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.+-- This is more /nominal/ decision that prevents certain unwanted conversions from being possible. -- -- Similarly no IsSuperset "r-UNICODE.D76" "r-ByteRep", this annotation acts as a guard to what can go into @Text@. -- 
src/Data/TypedEncoding/Instances/Restriction/UTF8.hs view
@@ -10,8 +10,11 @@ {-# LANGUAGE PartialTypeSignatures #-} --{-# LANGUAGE TypeApplications #-} --- | 'UTF-8' encoding+-- | '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.+-- -- @since 0.1.0.0 module Data.TypedEncoding.Instances.Restriction.UTF8 where @@ -49,7 +52,6 @@  prxyUtf8 = Proxy :: Proxy "r-UTF8" --- TODO these may need rethinking (performance)  -- | UTF8 encodings are defined for ByteString only as that would not make much sense for Text --@@ -57,7 +59,7 @@ -- Right (UnsafeMkEnc Proxy () "\195\177") -- -- >>> encodeFAll . toEncoding () $ "\xc3\x28" :: Either EncodeEx (Enc '["r-UTF8"] () B.ByteString)--- Left (EncodeEx "r-UTF8" (Cannot decode byte '\xc3': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream))+-- Left (EncodeEx "r-UTF8" (Cannot decode byte '\xc3': ... -- -- Following test uses 'verEncoding' helper that checks that bytes are encoded as Right iff they are valid UTF8 bytes --@@ -77,14 +79,16 @@ instance Encode (Either EncodeEx) "r-UTF8" "r-UTF8" c BL.ByteString where     encoding = encUTF8BL :: Encoding (Either EncodeEx) "r-UTF8" "r-UTF8" c BL.ByteString ++-- using lazy decoding to detect errors seems to be the fastest option that is not super hard to code+-- TODO v0.4.1 test performance+ encUTF8B :: Encoding (Either EncodeEx) "r-UTF8" "r-UTF8" c B.ByteString-encUTF8B = _implEncodingEx (fmap TE.encodeUtf8 . TE.decodeUtf8')-{-# WARNING encUTF8B "This method was not optimized for performance." #-}+encUTF8B = _implEncodingEx (implVerifyR (TEL.decodeUtf8' . BL.fromStrict))    encUTF8BL :: Encoding (Either EncodeEx) "r-UTF8" "r-UTF8" c BL.ByteString-encUTF8BL = _implEncodingEx (fmap TEL.encodeUtf8 . TEL.decodeUtf8')-{-# WARNING encUTF8BL "This method was not optimized for performance." #-}+encUTF8BL = _implEncodingEx (implVerifyR TEL.decodeUtf8')  -- * Decoding @@ -106,3 +110,10 @@ verEncoding :: B.ByteString -> Either err B.ByteString -> Bool verEncoding bs (Left _) = isLeft . TE.decodeUtf8' $ bs verEncoding bs (Right _) = isRight . TE.decodeUtf8' $ bs++-- | private implementation helper+implVerifyR :: (a -> Either err b) -> a -> Either err a+implVerifyR fn a = +     case fn a of +         Left err -> Left err+         Right _ -> Right a
src/Data/TypedEncoding/Instances/Support/Validate.hs view
@@ -42,15 +42,22 @@ -- | -- @since 0.3.0.0 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  -validR = validFromEnc' @nm @nm +validR = validRFromEnc' @nm @nm  ++-- TODO rename for consistency to _+ -- | Can cause slow compilation if used --  -- @since 0.3.0.0 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  -validR' = validFromEnc' @alg @nm +validR' = validRFromEnc' @alg @nm  ++ -- |+-- This should be used with "r-" validations only+-- -- @since 0.3.0.0 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   validFromEnc' (UnsafeMkEncoding p fn) = UnsafeMkValidation p (encAsRecreateErr . rfn) @@ -64,5 +71,17 @@             in  UnsafeMkEnc Proxy conf . getPayload <$> re   +{-# DEPRECATED validFromEnc' "Use validR' instead (valid for r- encodings only)" #-} ++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  +validRFromEnc' (UnsafeMkEncoding p fn) = UnsafeMkValidation p (encAsRecreateErr . rfn) +   where+        encAsRecreateErr :: Either EncodeEx a -> f a+        encAsRecreateErr (Left (EncodeEx p err)) = recoveryErr $ RecreateEx p err+        encAsRecreateErr (Right r) = pure r +        rfn :: forall (xs :: [Symbol]) . Enc (nm ': xs) c str -> Either EncodeEx (Enc xs c str)+        rfn (UnsafeMkEnc _ conf str)  =    +            let re = fn $ UnsafeMkEnc Proxy conf str+            in  UnsafeMkEnc Proxy conf . getPayload <$> re  
src/Examples/TypedEncoding/Conversions.hs view
@@ -30,7 +30,7 @@ -- -- Conversions aim at providing type safety when moving between encoded string-like types. ----- __The assumption__ made by `typed-encoding` is that encodings work in equivalent way independently of the payload type.+-- __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: -- -- @@@ -51,8 +51,14 @@ -- -- (@unpack@ and $decode$ are expected to satisfy similar diagrams, not shown) ----- Basically, it should not matter which type we run the encoding on (other than performance cost).+-- 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 where
typed-encoding.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: b0f10958b977104fdf20e2e9d875921fdf79c64e1c92b5243e8ed86b49519deb+-- hash: 401999e1b4cdce2d71a8bd02cb005f7f4632cd9bb8f1629e5d54b0a5be76f2d4  name:           typed-encoding-version:        0.4.0.0+version:        0.4.1.0 synopsis:       Type safe string transformations description:    See README.md in the project github repository. category:       Data, Text