typed-encoding 0.3.0.2 → 0.4.0.0
raw patch · 21 files changed
+691/−97 lines, 21 files
Files
- ChangeLog.md +25/−0
- README.md +0/−1
- src/Data/TypedEncoding/Common/Class/Superset.hs +104/−6
- src/Data/TypedEncoding/Common/Class/Util/StringConstraints.hs +21/−1
- src/Data/TypedEncoding/Common/Types/Common.hs +7/−0
- src/Data/TypedEncoding/Common/Util/TypeLits.hs +16/−0
- src/Data/TypedEncoding/Conv.hs +127/−41
- src/Data/TypedEncoding/Conv/ByteString/Char8.hs +18/−14
- src/Data/TypedEncoding/Conv/ByteString/Lazy/Char8.hs +12/−2
- src/Data/TypedEncoding/Conv/Text.hs +21/−2
- src/Data/TypedEncoding/Conv/Text/Encoding.hs +15/−4
- src/Data/TypedEncoding/Conv/Text/Lazy.hs +8/−1
- src/Data/TypedEncoding/Conv/Text/Lazy/Encoding.hs +13/−2
- src/Data/TypedEncoding/Instances/Enc/Base64.hs +6/−0
- src/Data/TypedEncoding/Instances/Restriction/BoundedAlphaNums.hs +10/−9
- src/Data/TypedEncoding/Instances/Restriction/ByteRep.hs +99/−0
- src/Data/TypedEncoding/Instances/Restriction/CHAR8.hs +43/−0
- src/Data/TypedEncoding/Instances/Restriction/D76.hs +81/−0
- src/Examples/TypedEncoding/Conversions.hs +17/−12
- test/Test/SupersetSpec.hs +42/−0
- typed-encoding.cabal +6/−2
ChangeLog.md view
@@ -6,6 +6,31 @@ - (post 0.3) "enc-B64" will be moved to a different package (more distant goal) - Improved constrains in `Data.TypedEncoding.Conv` modules +##++- Breaking + - IsSupersetOpen type family type arguments have changed++- Potentially Breaking + (These changes should be backward compatible in almost all cases):+ - Stronger (more precise) constraints on all functions `Data.TypedEncoding.Conv`+ - Compilation errors emitted from `IsSuperset` are different+ - "r-ban" now only allows ASCII chars in annotation name, errors-out otherwise+ +- New+ - `"r-CHAR8"` phantom restriction and `Superset` modified for "r-CHAR8"+ - `"r-UNICODE.D76"` /text/ character set restriction and `Superset` modifications+ - `Superset` constraint added back (different than in 0.2)+ - properties for `Superset` testing+ - `"r-ByteRep"` annotation used as a marker of low level use of `Char` instead of `Word8` for `ByteString` work.++- Improved:+ - `Data.TypedEncoding.Conv` `Text`, `String` and `ByteString` conversions are now more type safe and less error prone.+ Conversion functions are reversible, A to B to C diagrams commute.++- Fixes:+ - `Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums` `"r-ban"` now verifies `Superset "r-ASCII"`+ ## 0.3.0.2 - Added documentation to `Data.TypedEncoding.Conv` outlining current limitations, challenges of conversions.
README.md view
@@ -72,7 +72,6 @@ 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/Common/Class/Superset.hs view
@@ -8,18 +8,26 @@ {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-}--- {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ConstraintKinds #-} module Data.TypedEncoding.Common.Class.Superset where import Data.TypedEncoding.Common.Util.TypeLits -import Data.TypedEncoding.Common.Types (Enc(..) )+import Data.TypedEncoding.Common.Types (Enc(..)+ , EncodeEx(..)+ , Encoding+ , getPayload + , runEncoding'+ , toEncoding+ , AlgNm) import Data.TypedEncoding.Combinators.Unsafe (withUnsafeCoerce) import GHC.TypeLits import Data.Symbol.Ascii+import Data.Either (isLeft) -- $setup@@ -45,17 +53,31 @@ -- -- @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.+-- -- @since 0.2.2.0 type family IsSuperset (y :: Symbol) (x :: Symbol) :: Bool where IsSuperset "r-ASCII" "r-ASCII" = 'True IsSuperset "r-UTF8" "r-ASCII" = 'True IsSuperset "r-UTF8" "r-UTF8" = 'True- IsSuperset y x = IsSupersetOpen y (TakeUntil x ":") (ToList x)+ 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 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))+ -- | -- @since 0.2.2.0-type family IsSupersetOpen (y :: Symbol) (x :: Symbol) (xs :: [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)@@ -68,7 +90,33 @@ -- TODO consider expanding to -- _injectInto ::forall y x xs c str . (IsSuperset y x ~ 'True) => Enc (x ': xs) c str -> Enc (Replace x y xs) c str + -- |+-- Test for Supersets defined in this module+--+-- Actual tests in the project /test/ suite.+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' encb encs str = + case (isLeft rb, isLeft rs) of + (True, False) -> False+ (False, False) -> pb == ps+ _ -> True++ where + rb = runEncoding' @algb encb . toEncoding () $ str + 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. -- -- It allows to specify constraints that say, for example, that /Base 64/ encodes into @@ -86,6 +134,56 @@ _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 _encodesInto = injectInto . implEncInto --- prop_Superset :: forall y x xs c str . (Superset y x, Eq str) => Enc (x ': xs) c str -> Bool--- prop_Superset x = getPayload x == (getPayload . inject @y @x $ x)+-- |+-- validates superset restriction+-- +-- 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 +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+propEncodesInto_ = propEncodesInto' @algb @algr++-- | +-- Aggregate version of 'EncodingSuperset' +--+-- This is not ideal but easy to implement.+-- The issue is that this assumes restricted co-domain which is what often happens+-- but often does not, e.g. it will not work well with id transformation.+--+-- @since 0.4.0.0+class AllEncodeInto (superset :: Symbol) (encnms :: [Symbol]) where+ +instance {-# OVERLAPPING #-} AllEncodeInto "r-CHAR8" '[] +instance (AllEncodeInto "r-CHAR8" xs, IsSuperset "r-CHAR8" r ~ 'True, EncodingSuperset enc, r ~ EncSuperset enc) => AllEncodeInto "r-CHAR8" (enc ': xs)++instance {-# OVERLAPPING #-} AllEncodeInto "r-UNICODE.D76" '[] +instance (AllEncodeInto "r-UNICODE.D76" xs, IsSuperset "r-UNICODE.D76" r ~ 'True, EncodingSuperset enc, r ~ EncSuperset enc) => AllEncodeInto "r-UNICODE.D76" (enc ': xs)++instance {-# OVERLAPPING #-} AllEncodeInto "r-UTF8" '[] +instance (AllEncodeInto "r-UTF8" xs, IsSuperset "r-UTF8" r ~ 'True, EncodingSuperset enc, r ~ EncSuperset enc) => AllEncodeInto "r-UTF8" (enc ': xs)++tstChar8Encodable :: forall nms . AllEncodeInto "r-CHAR8" nms => String+tstChar8Encodable = "I am CHAR8 encodable"++tstD76Encodable :: forall nms . AllEncodeInto "r-UNICODE.D76" nms => String+tstD76Encodable = "I can be a valid text"++tstUTF8Encodable :: forall nms . AllEncodeInto "r-UTF8" nms => String+tstUTF8Encodable = "I am a valid UTF8"
src/Data/TypedEncoding/Common/Class/Util/StringConstraints.hs view
@@ -106,7 +106,8 @@ -- | -- Used to find exceptions that violated "r-" encoding--- Expected to be used to check encoding of ASCII-7 so Text and ByteString are compatible.+-- Expected to be used to check encoding of ASCII-7 so Text and ByteString are compatible+-- or to check 0-255 range restrictions. -- -- @since 0.3.0.0 class Char8Find str where@@ -141,3 +142,22 @@ instance Char8Find BL.ByteString where find = BL8.find ++++-- -- |+-- -- Finds character in @str@.+-- -- @str@ is expected to represent full char range all the way to @'\x10FFFF'@+-- --+-- -- @since 0.3.1.0+-- class CharFind str where+-- findChar :: (Char -> Bool) -> str -> Maybe Char++-- instance CharFind String where+-- findChar = L.find++-- instance CharFind T.Text where+-- findChar = T.find++-- instance CharFind TL.Text where+-- findChar = TL.find
src/Data/TypedEncoding/Common/Types/Common.hs view
@@ -80,3 +80,10 @@ IsROrEmpty "" = True IsROrEmpty x = IsR x +-- | +-- >>> :kind! RemoveRs '["r-UPPER", "enc-test", "r-lower", "do-UPPER"]+-- ...+-- = '["enc-test", "do-UPPER"]+type family RemoveRs (s :: [Symbol]) :: [Symbol] where+ RemoveRs '[] = '[]+ RemoveRs (x ': xs) = If (OrdBool (CmpSymbol "r-" (Take 2 x))) (RemoveRs xs) (x ': RemoveRs xs)
src/Data/TypedEncoding/Common/Util/TypeLits.hs view
@@ -41,6 +41,13 @@ AcceptEq msg _ = TypeError msg -- !+-- @since 0.4.0.0+type family OrdBool (c :: Ordering) :: Bool where+ OrdBool EQ = 'True+ OrdBool _ = 'False+++-- ! -- @since 0.2.1.0 type family And (b1 :: Bool) (b2 :: Bool) :: Bool where And 'True 'True = 'True@@ -54,6 +61,12 @@ -- ! -- @since 0.2.1.0+type family If (b1 :: Bool) (a :: k) (b :: k) :: k where+ If 'True a _ = a+ If 'False _ b = b++-- !+-- @since 0.2.1.0 type family Repeat (n :: Nat) (s :: Symbol) :: Symbol where Repeat 0 s = "" Repeat n s = AppendSymbol s (Repeat (n - 1) s)@@ -166,6 +179,7 @@ LLast (_ ': xs) = LLast xs + -- | -- >>> :kind! Concat (Snoc '["1","2","3"] "4") -- ...@@ -191,3 +205,5 @@ type family UnSnocHelper (s :: k) (t :: ([k], k)) :: ([k], k) where UnSnocHelper y ('(,) xs x) = '(,) (y ': xs) x ++
src/Data/TypedEncoding/Conv.hs view
@@ -11,71 +11,157 @@ -- * "Data.TypedEncoding.Conv.ByteString.Char8" -- * "Data.TypedEncoding.Conv.ByteString.Lazy.Char8" ----- Two goals of conversions are:+-- Two goals of these conversions are: ----- * provide a way to easily convert encoded data directly between /text/ and /bytestring/ types. -- * provide added type safety for string conversions+-- * provide a way to easily convert encoded data directly between /text/ and /bytestring/ types. ----- == Enc conversions --- --- Consider defining a conversion function @:: Enc xs c str1 -> f (Enc xs c str2)@. ----- One challenge is how do we know that @xs@ is a valid encoding stack also for @str2@?--- Should we constrain that? +-- == Type Safety ----- This is made even more difficult because this library plays (has to) games with orphan instances.+-- Haskell has 3 (5 counting lazy versions) popular string types, unfortunately they are all quite different. ----- The other challenge is how to ensure that if the destination decides to partially or fully decode, then--- it will do so without errors and the decoding will be meaningful.+-- Consider these 4 popular conversion functions: ----- Current definition is not optimal, it was selected because it works with a wide range of--- encodings (all @"r-"@ encodings, all non-@"r-"@ encodings available in this version of the library).--- However, future versions should try to improve on this. +-- @+-- import qualified Data.Text as T+-- import qualified Data.ByteString.Char8 as B8+-- import qualified Data.Text.Encoding as TE ----- == Type Safety+-- 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+-- @ ----- Consider the following diagram(s) of popular /text/ and /bytestring/ conversion functions:+-- 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--- ^ ^ |--- | | encodeUtf8--- id | |--- | decodeUtf8 |--- v | v--- String -> T.pack -> Text+-- ^ ^ |+-- | | TE.decodeUtf8+-- id | |+-- | TE.encodeUtf8 |+-- v | v+-- String -> T.pack -> Text -- @ ----- and the reverse of these:--- -- @ -- String <- B8.unpack <- ByteString--- ^ ^ |--- | | encodeUtf8--- id | |--- | decodeUtf8 |--- v | v+-- ^ ^ |+-- | | TE.decodeUtf8+-- id | |+-- | TE.encodeUtf8 |+-- v | v -- String <- T.unpack <- Text -- @ ----- These diagrams actually do not commute. This makes it easy to code bugs--- that are hard to find and hard to troubleshoot.+-- All of this can lead to bugs that are hard to find and hard to troubleshoot. ----- Well, they actually do commute on a subset of @String@ / @Text@ values:+-- /typed-encoding/ provides more precise types so that all of this goes away.+-- +-- Here are the type signatures simplified to one single encoding annotation: -- -- @--- Enc '["r-ASCII"] c String--- Enc '["r-ASCII"] c ByteString--- Enc '["r-ASCII"] c Text--- @ +-- 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 ----- This is because /UTF8/ is backward compatible with /ASCII(-7)/ and we speak /UTF8/ when--- converting and and from @Text@.+-- 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 is the reason why this version of /typed-encoding/ decided on using--- "r-ASCII" to constrain when wrapping @B8.pack@ and @B8.unpack@ in --- "Data.TypedEncoding.Conv.ByteString.Char8"+-- Corresponding pairs reverse, this should be clear since the types are restricted to what @T.Text@ can store or to +-- how @B8.Char@ works. ----- This approach seems to be limiting and future versions will work on relaxing it.+-- 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 B.ByteString+--+-- ghci> :t EncB8.pack @'["r-ASCII"]+-- :: Enc [Symbol] ((':) Symbol "r-ASCII" ('[] Symbol)) c String+-- -> Enc [Symbol] ((':) Symbol "r-ASCII" ('[] Symbol)) c B.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 /ISO/IEC 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. +--+--+-- == @Enc@ conversions +-- +-- Consider defining a conversion function @:: Enc xs c str1 -> f (Enc xs c str2)@.+--+-- One challenge is how do we know that @xs@ is a valid encoding stack also for @str2@?+-- Should we constrain that? +--+-- This is made even more difficult because this library uses (has to) orphan instances.+--+-- The other challenge is how to ensure that, if the destination is partially or fully decoded, then+-- it will decode without errors and the decoding will be meaningful.+--+-- Current version does not impose any instance constraint about existence of the stack for @str2@. +-- It is possible to not have one, in that case @decodeAll@ combinators will not be available.+--+-- This is still useful as the payload could be safely extracted, to save to the database or do other things with it.+--+-- Future versions of /typed-encoding/ may provide ways to ensure validity of the encoding stack for @str2@.+ module Data.TypedEncoding.Conv where
src/Data/TypedEncoding/Conv/ByteString/Char8.hs view
@@ -18,18 +18,14 @@ -- | -- Type safer version of 'Data.ByteString.Char8.pack'. -- --- This assumes that each of the encodings in @xs@ work work equivalently in @String@ and @ByteString@.------ This function assumes that encoding stack @xs@ does not shift characters outside of Char8 range. --- This is obviously true for all "r-" types--- it is also true for any "enc-" and "do-" encodings currently available in this package. However, is possible to define a "do-" or "enc-" encodings that violate that. --- Future versions of /type-encoding/ are likely --- to introduce constraints to guard this aspect of the type safety better. +-- This assumes that each of the encodings in @xs@ work equivalently in @String@ and @ByteString@. -- -- 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. ----- Currently this uses (an over-conservative) @"r-ASCII"@ superset constraint.+-- 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. --@@ -37,14 +33,18 @@ -- ... -- ... error: -- ... Couldn't match type ...--- ... "r-ASCII" "r-foo" ... -- ... -- -- >>> displ $ pack (unsafeSetPayload () "Hello" :: Enc '["r-bar", "r-ASCII"] () String) -- "Enc '[r-bar,r-ASCII] () (ByteString Hello)" ----- @since 0.2.2.0-pack :: (Knds.LLast xs ~ t, IsSuperset "r-ASCII" t ~ 'True) => Enc xs c String -> Enc xs c B8.ByteString+-- @since 0.4.0.0+pack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-CHAR8" 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.@@ -56,8 +56,12 @@ -- Future versions of /type-encoding/ are likely -- to introduce constraints to guard this aspect of the type safety better. ----- @since 0.2.2.0-unpack :: (Knds.LLast xs ~ t, IsSuperset "r-ASCII" t ~ 'True) => Enc xs c B8.ByteString -> Enc xs c String+-- @since 0.4.0.0+unpack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-CHAR8" y+ , encs ~ RemoveRs ys+ , AllEncodeInto "r-CHAR8" encs+ ) => Enc xs c B8.ByteString -> Enc xs c String unpack = unsafeChangePayload B8.unpack --- TODO consider adding "r-CHAR8"
src/Data/TypedEncoding/Conv/ByteString/Lazy/Char8.hs view
@@ -17,10 +17,20 @@ -- | -- Lazy version of 'Data.TypedEncoding.Conv.ByteString.Char8.pack'.-pack :: (Knds.LLast xs ~ t, IsSuperset "r-ASCII" t ~ 'True) => Enc xs c String -> Enc xs c BL8.ByteString+pack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-CHAR8" 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.LLast xs ~ t, IsSuperset "r-ASCII" t ~ 'True) => Enc xs c BL8.ByteString -> Enc xs c String+unpack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-CHAR8" 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
@@ -1,12 +1,14 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE PolyKinds #-} -- removes need to annotate kinds as [Symbol]+{-# LANGUAGE FlexibleContexts #-} -- | Text encoding combinators specific to 'T.Text' -- @since 0.2.2.0 module Data.TypedEncoding.Conv.Text where import qualified Data.Text as T+import qualified Data.TypedEncoding.Common.Util.TypeLits as Knds import Data.TypedEncoding.Instances.Support @@ -15,11 +17,21 @@ -- | This assumes that each of the encodings in @xs@ work work equivalently in @String@ and @Text@. -pack :: Enc xs c String -> Enc xs c T.Text+pack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UNICODE.D76" y + , encs ~ RemoveRs ys+ , AllEncodeInto "r-UNICODE.D76" encs+ ) => 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@. -unpack :: Enc xs c T.Text -> Enc xs c String+unpack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UNICODE.D76" y + , encs ~ RemoveRs ys+ , AllEncodeInto "r-UNICODE.D76" encs+ ) => Enc xs c T.Text -> Enc xs c String unpack = unsafeChangePayload T.unpack -- | @@ -42,3 +54,10 @@ -- "Enc '[] () (Text Hello)" utf8Demote :: (UnSnoc xs ~ '(,) ys "r-UTF8") => Enc xs c T.Text -> Enc ys c T.Text utf8Demote = withUnsafeCoerce id+++d76Promote :: Enc xs c T.Text -> Enc (Snoc xs "r-UNICODE.D76") c T.Text+d76Promote = withUnsafeCoerce id++d76Demote :: (UnSnoc xs ~ '(,) ys "r-UNICODE.D76") => Enc xs c T.Text -> Enc ys c T.Text+d76Demote = withUnsafeCoerce id
src/Data/TypedEncoding/Conv/Text/Encoding.hs view
@@ -14,6 +14,7 @@ import qualified Data.Text.Encoding as TE import Data.TypedEncoding.Instances.Support+import qualified Data.TypedEncoding.Common.Util.TypeLits as Knds import Data.TypedEncoding.Instances.Restriction.UTF8 () import Data.TypedEncoding.Instances.Restriction.ASCII () import Data.TypedEncoding.Unsafe (withUnsafe)@@ -78,8 +79,13 @@ -- -- See "Data.TypedEncoding.Conv" for more detailed discussion. ----- @since 0.2.2.0-decodeUtf8 :: forall xs c t. (LLast xs ~ t, IsSuperset "r-UTF8" t ~ 'True) => Enc xs c B.ByteString -> Enc xs c T.Text +-- @since 0.4.0.0+decodeUtf8 :: forall xs c t y ys encs. (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UTF8" y+ , encs ~ RemoveRs ys+ , AllEncodeInto "r-UTF8" encs+ ) => Enc xs c B.ByteString -> Enc xs c T.Text decodeUtf8 = withUnsafe (fmap TE.decodeUtf8) -- |@@ -90,6 +96,11 @@ -- -- See "Data.TypedEncoding.Conv" for more detailed discussion. ----- @since 0.2.2.0-encodeUtf8 :: forall xs c t. (LLast xs ~ t, IsSuperset "r-UTF8" t ~ 'True) => Enc xs c T.Text -> Enc xs c B.ByteString +-- @since 0.4.0.0+encodeUtf8 :: forall xs c t y ys encs. (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UTF8" y + , encs ~ RemoveRs ys+ , AllEncodeInto "r-UTF8" encs+ ) => Enc xs c T.Text -> Enc xs c B.ByteString encodeUtf8 = withUnsafe (fmap TE.encodeUtf8)
src/Data/TypedEncoding/Conv/Text/Lazy.hs view
@@ -4,13 +4,20 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE PolyKinds #-} -- removes need to annotate kinds as [Symbol]+{-# LANGUAGE FlexibleContexts #-} module Data.TypedEncoding.Conv.Text.Lazy where import qualified Data.Text.Lazy as TL+import qualified Data.TypedEncoding.Common.Util.TypeLits as Knds import Data.TypedEncoding.Instances.Support -pack :: Enc xs c String -> Enc xs c TL.Text+pack :: (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UNICODE.D76" y + , encs ~ RemoveRs ys+ , AllEncodeInto "r-UNICODE.D76" encs+ ) => Enc xs c String -> Enc xs c TL.Text pack = unsafeChangePayload TL.pack unpack :: Enc xs c TL.Text -> Enc xs c String
src/Data/TypedEncoding/Conv/Text/Lazy/Encoding.hs view
@@ -14,15 +14,26 @@ import qualified Data.Text.Lazy.Encoding as TEL import Data.TypedEncoding.Instances.Support+import qualified Data.TypedEncoding.Common.Util.TypeLits as Knds import Data.TypedEncoding.Instances.Restriction.UTF8 () import Data.TypedEncoding.Instances.Restriction.ASCII () import Data.TypedEncoding.Unsafe (withUnsafe) -- | Lazy version of 'Data.TypedEncoding.Conv.Text.Encoding.decodeUtf8'-decodeUtf8 :: forall xs c t. (LLast xs ~ t, IsSuperset "r-UTF8" t ~ 'True) => Enc xs c BL.ByteString -> Enc xs c TL.Text +decodeUtf8 :: forall xs c t y ys encs. (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UTF8" y + , encs ~ RemoveRs ys+ , AllEncodeInto "r-UTF8" encs+ ) => Enc xs c BL.ByteString -> Enc xs c TL.Text decodeUtf8 = withUnsafe (fmap TEL.decodeUtf8) -- | Lazy version of 'Data.TypedEncoding.Conv.Text.Encoding.encodeUtf8'-encodeUtf8 :: forall xs c t. (LLast xs ~ t, IsSuperset "r-UTF8" t ~ 'True) => Enc xs c TL.Text -> Enc xs c BL.ByteString +encodeUtf8 :: forall xs c t y ys encs. (+ Knds.UnSnoc xs ~ '(,) ys y+ , Superset "r-UTF8" y + , encs ~ RemoveRs ys+ , AllEncodeInto "r-UTF8" encs+ ) => Enc xs c TL.Text -> Enc xs c BL.ByteString encodeUtf8 = withUnsafe (fmap TEL.encodeUtf8)
src/Data/TypedEncoding/Instances/Enc/Base64.hs view
@@ -78,6 +78,12 @@ instance EncodingSuperset "enc-B64" where type EncSuperset "enc-B64" = "r-ASCII" +-- |+-- >>> tstChar8Encodable @ '["enc-B64-len", "enc-B64"]+-- "I am CHAR8 encodable"+instance EncodingSuperset "enc-B64-len" where+ type EncSuperset "enc-B64-len" = "r-ASCII"+ -- * Encoders -- |
src/Data/TypedEncoding/Instances/Restriction/BoundedAlphaNums.hs view
@@ -52,7 +52,7 @@ type Ban s = (KnownSymbol s, IsBan s ~ 'True) -type instance IsSupersetOpen "r-ASCII" "r-ban" xs = 'True+type instance IsSupersetOpen "r-ASCII" x "r-ban" xs = 'True instance (Ban s, Algorithm s "r-ban", IsStringR str) => Encode (Either EncodeEx) s "r-ban" c str where@@ -97,15 +97,16 @@ -- Left "'G' not boulded 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 "Input list has wrong size expecting 5 but length \"13-234\" == 6"+-- >>> 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-verifyBoundedAlphaNum p str = - if pattl == inpl - then case lefts match of- (e: _) -> Left e+verifyBoundedAlphaNum p str = + case (lefts match, notAscii, pattl == inpl) of+ (_, Just ch, _) -> Left $ "Not ASCII char in annotation " ++ show ch+ (_, _, False) -> Left $ "Input list has wrong size expecting " ++ show pattl ++ " but length " ++ show input ++ " == " ++ show inpl + (e: _, _, _) -> Left e _ -> Right str- else Left $ "Input list has wrong size expecting " ++ show pattl ++ " but length " ++ show input ++ " == " ++ show inpl where patt = L.drop (L.length ("r-ban:" :: String)) . symbolVal $ p input = toString str@@ -113,7 +114,7 @@ inpl = L.length input match = L.zipWith fn input patt-+ notAscii = L.find (not . isAscii) patt fn ci cp = case (isAlphaNum ci, isAlphaNum cp, ci <= cp, ci == cp) of (True, True, True, _) -> Right ()
+ src/Data/TypedEncoding/Instances/Restriction/ByteRep.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | +-- @"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 'Data.TypedEncoding.Common.Class.Superset.IsSuperset'+--+-- It is subset of "r-CHAR8":+--+-- @Superset "r-CHAR8" ""r-ByteRep" +--+-- Currently, is (intentionally not decodable)+--+-- @since 0.3.1.0+module Data.TypedEncoding.Instances.Restriction.ByteRep where++import Data.TypedEncoding.Instances.Support+import Data.TypedEncoding.Common.Class.Util.StringConstraints++import Data.TypedEncoding.Internal.Util (explainBool)+import Data.Char++import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL++-- $setup+-- >>> :set -XDataKinds -XTypeApplications+++-----------------+-- Encodings --+-----------------++data CharOutOfRange = CharOutOfRange Int Char deriving (Eq, Show)++-- * Encoding @"r-ByteRep"@++instance Encode (Either EncodeEx) "r-ByteRep" "r-ByteRep" c Char where+ encoding = encByteChar ++instance Encode (Either EncodeEx) "r-ByteRep" "r-ByteRep" c B.ByteString where+ encoding = encByteRepB++instance Encode (Either EncodeEx) "r-ByteRep" "r-ByteRep" c BL.ByteString where+ encoding = encByteRepBL++instance Encode (Either EncodeEx) "r-ByteRep" "r-ByteRep" c String where+ encoding = encByteRepS++encByteChar :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c Char +encByteChar = _implEncodingEx (\c -> explainBool (CharOutOfRange 255) (c, (> 255) . ord $ c)) ++encByteRepB :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c B.ByteString+encByteRepB = _implEncodingEx @"r-ByteRep" (encImpl 255)++encByteRepBL :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c BL.ByteString+encByteRepBL = _implEncodingEx @"r-ByteRep" (encImpl 255)++encByteRepS :: Encoding (Either EncodeEx) "r-ByteRep" "r-ByteRep" c String+encByteRepS = _implEncodingEx @"r-ByteRep" (encImpl 255)+++-- * Decoding @"r-ByteRep"@++-- instance (Applicative f) => Decode f "r-ByteRep" "r-ByteRep" c str where+-- decoding = decAnyR+++instance (RecreateErr f, Applicative f) => Validate f "r-ByteRep" "r-ByteRep" () B.ByteString where+ validation = validR encByteRepB++instance (RecreateErr f, Applicative f) => Validate f "r-ByteRep" "r-ByteRep" () BL.ByteString where+ validation = validR encByteRepBL++instance (RecreateErr f, Applicative f) => Validate f "r-ByteRep" "r-ByteRep" () String where+ validation = validR encByteRepS+++-- * Implementation ++-- 255 for CHAR8 / "r-ByteRep"+encImpl :: Char8Find str => Int -> str -> Either CharOutOfRange str+encImpl bound str = case find ((> bound) . ord) str of + Nothing -> Right str+ Just ch -> Left $ CharOutOfRange bound ch+
+ src/Data/TypedEncoding/Instances/Restriction/CHAR8.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | +--+-- Should not be used directly, only as superset+--+-- Checks if all chars are @< \'\256\'@+--+-- Encoding functions are here for test support only, no instances+--+-- @since 0.3.1.0+module Data.TypedEncoding.Instances.Restriction.CHAR8 where++import Data.TypedEncoding.Instances.Support+import Data.TypedEncoding.Common.Class.Util.StringConstraints+import Data.TypedEncoding.Instances.Restriction.ByteRep (encImpl, CharOutOfRange (..))++import Data.TypedEncoding.Internal.Util (explainBool)+import Data.Char+++-- $setup+-- >>> :set -XDataKinds -XTypeApplications+++-----------------+-- Test Encodings --+-----------------++testEncChar8Char :: Encoding (Either EncodeEx) "r-CHAR8" "r-CHAR8" c Char +testEncChar8Char = _implEncodingEx (\c -> explainBool (CharOutOfRange 255) (c, (> 255) . ord $ c)) ++testEncCHAR8 :: Char8Find str => Encoding (Either EncodeEx) "r-CHAR8" "r-CHAR8" c str+testEncCHAR8 = _implEncodingEx @"r-CHAR8" (encImpl 255)++
+ src/Data/TypedEncoding/Instances/Restriction/D76.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | +-- Checks that satisfy D76 Unicode standard (/text/ replaces chars that are in range+-- 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.+--+-- Similarly no IsSuperset "r-UNICODE.D76" "r-ByteRep", this annotation acts as a guard to what can go into @Text@.+-- +-- @since 0.4.0.0+module Data.TypedEncoding.Instances.Restriction.D76 where++import Data.TypedEncoding.Instances.Support+import Data.TypedEncoding.Common.Class.Util.StringConstraints++import Data.TypedEncoding.Internal.Util (explainBool)+import Data.Char+++-- $setup+-- >>> :set -XDataKinds -XTypeApplications+++-----------------+-- Encodings --+-----------------++newtype NonTextChar = NonTextChar Char deriving (Eq, Show)++-- * Encoding @"r-UNICODE.D76"@++instance Encode (Either EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c Char where+ encoding = encD76Char ++instance Encode (Either EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c String where+ encoding = encD76++encD76Char :: Encoding (Either EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c Char +encD76Char = _implEncodingEx (\c -> explainBool NonTextChar (c, nonTextChar c)) ++encD76 :: Encoding (Either EncodeEx) "r-UNICODE.D76" "r-UNICODE.D76" c String+encD76 = _implEncodingEx @"r-UNICODE.D76" encImpl++-- | No-check version+trustMe :: Applicative f => Encoding f "r-UNICODE.D76" "r-UNICODE.D76" c String+trustMe = _implEncodingP id++++-- * Decoding @"r-UNICODE.D76"@++instance (Applicative f) => Decode f "r-UNICODE.D76" "r-UNICODE.D76" c str where+ decoding = decAnyR+ +instance (RecreateErr f, Applicative f) => Validate f "r-UNICODE.D76" "r-UNICODE.D76" () String where+ validation = validR encD76+++-- * Implementation ++-- @'\xd800'@ to @'\xdfff'@ inclusive+nonTextChar :: Char -> Bool+nonTextChar c = x >= 55296 && x <= 57343+ where x = ord c+++-- \ UNICODE.D76+encImpl :: String -> Either NonTextChar String+encImpl str = case find nonTextChar str of + Nothing -> Right str+ Just ch -> Left $ NonTextChar ch+
src/Examples/TypedEncoding/Conversions.hs view
@@ -61,9 +61,11 @@ import Data.TypedEncoding.Instances.Enc.Base64 () import Data.TypedEncoding.Instances.Restriction.ASCII () import Data.TypedEncoding.Instances.Restriction.UTF8 ()+import Data.TypedEncoding.Instances.Restriction.D76 ()+import Data.TypedEncoding.Instances.Restriction.ByteRep () import qualified Data.TypedEncoding.Conv.Text as EncT -import qualified Data.TypedEncoding.Conv.Text.Encoding as EncTe (decodeUtf8)+import qualified Data.TypedEncoding.Conv.Text.Encoding as EncTe -- (decodeUtf8) import qualified Data.Text as T import qualified Data.ByteString as B@@ -110,28 +112,23 @@ -- "Enc '[r-ASCII] () (Text HeLlo world)" --- * pack and unpack+-- * @pack@ from String helloZero :: Enc ('[] :: [Symbol]) () String helloZero = toEncoding () "Hello"--- ^ Consider 0-encoding of a 'String', to move it to @Enc '[] () String@ one could try:------ >>> displ . EncT.pack $ helloZero--- "Enc '[] () (Text Hello)"+-- ^ Consider 0-encoding of a 'String', to move it to @Enc '[] () ByteString@ one could try: ----- this works, but:--- -- >>> EncB8.pack helloZero -- ... -- ... error: --- ... Empty Symbol list not allowed+-- ... 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\'@. ----- Current version of pack @EncB8.pack@ will not compile unless the encoding is ASCII restricted (@< \'\128\'@).+-- @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@@ -139,13 +136,18 @@ -- -- And the result is a @ByteString@ with bonus annotation describing its content. ----- Future versions are likely to relax this restriction to a more permissive "r-" annotation that allows for any char @<= \'\255\'@+-- 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. helloRestricted :: Either EncodeEx (Enc '["r-ban:zzzzz"] () B.ByteString) helloRestricted = fmap EncB8.pack . _runEncodings encodings $ toEncoding () "Hello" -- ^ 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\'@+-- this example @"r-ban:zzzzz"@ restricts to 5 alpha-numeric charters all @< \'z\'@ -- -- >>> displ <$> helloRestricted -- Right "Enc '[r-ban:zzzzz] () (ByteString Hello)"@@ -159,6 +161,9 @@ -- Right "Enc '[r-ban:zzzzz] () (String Hello)" -- +byteRep :: Either EncodeEx (Enc '["r-ByteRep"] () B.ByteString)+byteRep = fmap EncB8.pack . _runEncodings encodings $ toEncoding () "\254"+-- ^ For low level use of @Char@ instead of @Word8@, "r-ByteRep" represents anything under @256@. -- * More complex rules
+ test/Test/SupersetSpec.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fwarn-unused-imports #-}++-- | Verified backward compatibility of ASCII encoder changes in v0.3+module Test.SupersetSpec where+++import Data.TypedEncoding.Instances.Restriction.ASCII ()+import Data.TypedEncoding.Instances.Restriction.UTF8 ()+import Data.TypedEncoding.Instances.Restriction.D76 ()+import Data.TypedEncoding.Instances.Restriction.ByteRep ()+import Data.TypedEncoding.Instances.Enc.Base64 ()+import qualified Data.TypedEncoding.Instances.Restriction.CHAR8 as CHAR8++import Data.TypedEncoding -- .Common.Class.Superset++import Test.QuickCheck.Instances.ByteString ()+import qualified Data.ByteString as B+import Test.QuickCheck+-- import Test.QuickCheck.Property+import Test.Hspec+++spec :: Spec +spec = + describe "Superset tests" $ do+ describe "ByteString based" $ do+ it "r-UTF8 > r-ASCII" $ property $ propSuperset_ @"r-UTF8" @"r-ASCII" @B.ByteString encoding encoding + it "r-CHAR8 > r-ASCII" $ property $ propSuperset_ @"r-CHAR8" @"r-ASCII" @B.ByteString CHAR8.testEncCHAR8 encoding+ it "r-CHAR8 > r-ByteRep" $ property $ propSuperset_ @"r-CHAR8" @"r-ByteRep" @B.ByteString CHAR8.testEncCHAR8 encoding+ describe "String based" $ + it "r-UNICODE.D76 > r-ASCII" $ property $ propSuperset_ @"r-UNICODE.D76" @"r-ASCII" @String encoding encoding+ describe "EncodingSuperset test" $+ it "enc-B64 < r-ASCII" $ property $ propEncodesInto_ @"enc-B64" @"r-ASCII" @B.ByteString encoding encoding+runSpec :: IO ()+runSpec = hspec spec
typed-encoding.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 004e70cb6bb533b5bf1a14ddf696fa82800c2c9416d608734605d3e6103f521e+-- hash: b0f10958b977104fdf20e2e9d875921fdf79c64e1c92b5243e8ed86b49519deb name: typed-encoding-version: 0.3.0.2+version: 0.4.0.0 synopsis: Type safe string transformations description: See README.md in the project github repository. category: Data, Text@@ -70,6 +70,9 @@ Data.TypedEncoding.Instances.Restriction.ASCII Data.TypedEncoding.Instances.Restriction.Bool Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums+ Data.TypedEncoding.Instances.Restriction.ByteRep+ Data.TypedEncoding.Instances.Restriction.CHAR8+ Data.TypedEncoding.Instances.Restriction.D76 Data.TypedEncoding.Instances.Restriction.Misc Data.TypedEncoding.Instances.Restriction.UTF8 Data.TypedEncoding.Instances.Support@@ -127,6 +130,7 @@ other-modules: Test.Bc.IsStringRSpec Test.Bc.ASCIISpec+ Test.SupersetSpec hs-source-dirs: test ghc-options: -threaded -rtsopts -with-rtsopts=-N