typed-encoding 0.5.0.0 → 0.5.1.0
raw patch · 12 files changed
+159/−14 lines, 12 files
Files
- ChangeLog.md +5/−0
- README.md +6/−0
- src/Data/TypedEncoding/Common/Class.hs +1/−1
- src/Data/TypedEncoding/Common/Class/Superset.hs +3/−0
- src/Data/TypedEncoding/Common/Types/Enc.hs +1/−1
- src/Data/TypedEncoding/Instances/Enc/Base64.hs +19/−2
- src/Data/TypedEncoding/Instances/Restriction/Base64.hs +99/−0
- src/Data/TypedEncoding/Instances/Restriction/UTF8.hs +5/−7
- src/Data/TypedEncoding/Instances/Support/Encode.hs +7/−0
- src/Examples/TypedEncoding/Conversions.hs +9/−0
- test/Test/SupersetSpec.hs +1/−1
- typed-encoding.cabal +3/−2
ChangeLog.md view
@@ -7,6 +7,11 @@ - `Data.TypedEncoding.Common.Class.IsStringR` expected to be be changed / replaced - More module renaming to separate internal implementation code and code targeting examples - (post 0.5) "enc-B64" will be moved to a different package (more distant goal)+- (intended as private) @implVerifyR@ will be removed from Data.TypedEncoding.Instances.Restriction.UTF8++## 0.5.1.0+- "r-B64" added+- @implVerifyR@ convenience function added to 'Data.TypedEncoding.Instances.Support.Encode' ## 0.5.0
README.md view
@@ -72,6 +72,12 @@ Please see `Examples.TypedEncoding` it the module list. + ++## Hackage++https://hackage.haskell.org/package/typed-encoding+ ## 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.hs view
@@ -55,7 +55,7 @@ -- | Flatten is more permissive 'IsSuperset' -- @--- instance FlattenAs "r-ASCII" "enc-B64" where -- OK+-- instance FlattenAs "r-ASCII" "enc-B64" where -- @ -- -- Now encoded data has form @Enc '["r-ASCII"] c str@
src/Data/TypedEncoding/Common/Class/Superset.hs view
@@ -64,7 +64,10 @@ -- -- @since 0.2.2.0 type family IsSuperset (y :: Symbol) (x :: Symbol) :: Bool where+ IsSuperset "r-B64" "r-B64" = 'True+ IsSuperset "r-ASCII" "r-B64" = 'True IsSuperset "r-ASCII" "r-ASCII" = 'True+ IsSuperset "r-UTF8" "r-B64" = 'True IsSuperset "r-UTF8" "r-ASCII" = 'True 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
src/Data/TypedEncoding/Common/Types/Enc.hs view
@@ -127,7 +127,7 @@ -- Encoding Identity "enc-B64" "enc-B64" () ByteString -- @ ----- Represents a /Byte 64/ encoder that can operate on any stack of previous encodings.+-- Represents a /Base 64/ encoder that can operate on any stack of previous encodings. -- (encoding name and algorithm name are "enc-B64", there is no -- additional configuration @()@ needed and it runs in the @Identity@ Functor. --
src/Data/TypedEncoding/Instances/Enc/Base64.hs view
@@ -21,6 +21,7 @@ import qualified Data.ByteString.Base64 as B64 import qualified Data.ByteString.Base64.Lazy as BL64+import Data.TypedEncoding.Instances.Restriction.Base64 () @@ -51,6 +52,18 @@ acceptLenientL :: Enc ("enc-B64-len" ': ys) c BL.ByteString -> Enc ("enc-B64" ': ys) c BL.ByteString acceptLenientL = withUnsafeCoerce (BL64.encode . BL64.decodeLenient) +-- |+-- Validated "r-B64" is guaranteed to decode. +-- This would not be safe for Text+asEncodingB :: Enc '["r-B64"] c B.ByteString -> Enc '["enc-B64"] c B.ByteString +asEncodingB = withUnsafeCoerce id++-- |+-- Validated "r-B64" is guaranteed to decode. +-- This would not be safe for Text+asEncodingBL :: Enc '["r-B64"] c BL.ByteString -> Enc '["enc-B64"] c BL.ByteString +asEncodingBL = withUnsafeCoerce id+ -- | allow to treat B64 encodings as ASCII forgetting about B64 encoding -- --@@ -66,6 +79,10 @@ instance FlattenAs "r-ASCII" "enc-B64" where -- |+-- @since 0.5.1.0 +instance FlattenAs "r-B64" "enc-B64" where++-- | -- This is not precise, actually /Base 64/ uses a subset of ASCII -- and that would require a new definition @"r-B64"@. --@@ -80,13 +97,13 @@ -- -- @since 0.3.0.0 instance EncodingSuperset "enc-B64" where- type EncSuperset "enc-B64" = "r-ASCII"+ type EncSuperset "enc-B64" = "r-B64" -- | -- >>> tstChar8Encodable @ '["enc-B64-len", "enc-B64"] -- "I am CHAR8 encodable" instance EncodingSuperset "enc-B64-len" where- type EncSuperset "enc-B64-len" = "r-ASCII"+ type EncSuperset "enc-B64-len" = "r-B64" -- * Encoders
+ src/Data/TypedEncoding/Instances/Restriction/Base64.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE DataKinds #-}+--{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+--{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE PartialTypeSignatures #-}+--{-# LANGUAGE TypeApplications #-}++-- | 'r-B64' is restricted to values that are valid Base64 encodings of some data.+-- For example, @Enc '["r-B64"] () T.Text@ can contain encoded binary image.+--+-- "enc-B64" can be converted to "r-B64" using @flattenAs@ defined in+-- 'Data.TypedEncoding.Instances.Enc.Base64'. +-- However, there is no, and there should be no conversion general conversion from "r-B64" back to "enc-B64":+-- @Enc '["r-B64"] () T.Text@ is not B64 encoded text, it is B64 encoded something.+--+-- @since 0.5.1.0+module Data.TypedEncoding.Instances.Restriction.Base64 where++import Data.TypedEncoding.Instances.Support+++import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Text.Encoding as TE +import qualified Data.Text.Lazy.Encoding as TEL +import qualified Data.ByteString.Base64 as B64+import qualified Data.ByteString.Base64.Lazy as BL64+import qualified Data.ByteString.Char8 as B8+import qualified Data.TypedEncoding.Instances.Restriction.ASCII as RAscii++-- $setup+-- >>> :set -XScopedTypeVariables -XKindSignatures -XMultiParamTypeClasses -XDataKinds -XPolyKinds -XPartialTypeSignatures -XFlexibleInstances -XTypeApplications++++instance Encode (Either EncodeEx) "r-B64" "r-B64" c B.ByteString where+ encoding = encRB64B+ +instance Encode (Either EncodeEx) "r-B64" "r-B64" c BL.ByteString where+ encoding = encRB64BL+ ++instance Encode (Either EncodeEx) "r-B64" "r-B64" c T.Text where+ encoding = encRB64T+ +instance Encode (Either EncodeEx) "r-B64" "r-B64" c TL.Text where+ encoding = encRB64TL++instance Encode (Either EncodeEx) "r-B64" "r-B64" c String where+ encoding = encRB64S++-- using lazy decoding to detect errors seems to be the fastest option that is not super hard to code+++encRB64B :: Encoding (Either EncodeEx) "r-B64" "r-B64" c B.ByteString+encRB64B = _implEncodingEx (implVerifyR (B64.decode)) ++encRB64BL :: Encoding (Either EncodeEx) "r-B64" "r-B64" c BL.ByteString+encRB64BL = _implEncodingEx (implVerifyR (BL64.decode)) ++-- | Converts text to bytestring using UTF8 decoding and then verify encoding in ByteString+-- This is safe without verifying ASCII, any non-ASCII text will still convert to ByteString+-- but will fail B64.decode (TODO tests would be nice)+encRB64T :: Encoding (Either EncodeEx) "r-B64" "r-B64" c T.Text+encRB64T = _implEncodingEx (implVerifyR (B64.decode . TE.encodeUtf8)) ++encRB64TL :: Encoding (Either EncodeEx) "r-B64" "r-B64" c TL.Text+encRB64TL = _implEncodingEx (implVerifyR (BL64.decode . TEL.encodeUtf8)) ++encRB64S :: Encoding (Either EncodeEx) "r-B64" "r-B64" c String+encRB64S = _implEncodingEx (implVerifyR (fmap (B64.decode . B8.pack) . either (Left . show) Right . RAscii.encImpl)) ++-- -- * Decoding++instance (Applicative f) => Decode f "r-B64" "r-B64" c str where+ decoding = decAnyR++instance (RecreateErr f, Applicative f) => Validate f "r-B64" "r-B64" c B.ByteString where+ validation = validR encRB64B++instance (RecreateErr f, Applicative f) => Validate f "r-B64" "r-B64" c BL.ByteString where+ validation = validR encRB64BL++instance (RecreateErr f, Applicative f) => Validate f "r-B64" "r-B64" c T.Text where+ validation = validR encRB64T++instance (RecreateErr f, Applicative f) => Validate f "r-B64" "r-B64" c TL.Text where+ validation = validR encRB64TL++instance (RecreateErr f, Applicative f) => Validate f "r-B64" "r-B64" c String where+ validation = validR encRB64S+
src/Data/TypedEncoding/Instances/Restriction/UTF8.hs view
@@ -16,7 +16,11 @@ -- conversion to @Text@ to work. -- -- @since 0.1.0.0-module Data.TypedEncoding.Instances.Restriction.UTF8 where+module Data.TypedEncoding.Instances.Restriction.UTF8 (+ module Data.TypedEncoding.Instances.Restriction.UTF8+ -- * reexported for backward compatibility, will be removed in the future+ , implVerifyR + ) where import Data.TypedEncoding.Instances.Support @@ -109,9 +113,3 @@ 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/Encode.hs view
@@ -84,3 +84,10 @@ p = Proxy :: Proxy nm +-- |+-- @since 0.5.1.0+implVerifyR :: (a -> Either err b) -> a -> Either err a+implVerifyR fn a = + case fn a of + Left err -> Left err+ Right _ -> Right a
src/Examples/TypedEncoding/Conversions.hs view
@@ -65,6 +65,7 @@ import Data.TypedEncoding import Data.TypedEncoding.Instances.Enc.Base64 () +import Data.TypedEncoding.Instances.Restriction.Base64 () import Data.TypedEncoding.Instances.Restriction.ASCII () import Data.TypedEncoding.Instances.Restriction.UTF8 () import Data.TypedEncoding.Instances.Restriction.D76 ()@@ -278,6 +279,14 @@ -- +notTextB64AsTxt :: Enc '["r-B64"] () T.Text+notTextB64AsTxt = EncTe.decodeUtf8 $ flattenAs $ notTextB+-- ^ /Base64/ encoding of a non-text binary data can still be converted to Text format+-- @Enc '["r-B64"] () T.Text@ signifies that the value is B64 encoding but it cannot be decoded to a Text. +++-- tst = encodeAll . toEncoding () $ "" :: Enc '["enc-B64"] () B.ByteString+-- tst2 = EncTe.decodeUtf8 $ flattenAs $ tst :: Enc '["r-B64"] () T.Text -- * Lenient recovery
test/Test/SupersetSpec.hs view
@@ -37,6 +37,6 @@ 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+ it "enc-B64 < r-ASCII" $ property $ propEncodesInto_ @"enc-B64" @"r-B64" @B.ByteString encoding encoding runSpec :: IO () runSpec = hspec spec
typed-encoding.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 14b481e19f8b924154bf83e2d8d55492f1f8259385026d9dc0c745a2924621fa+-- hash: df1ee6c51c573402710616f718103b1f8d79bc8811d5aa416e628c8f30ad927f name: typed-encoding-version: 0.5.0.0+version: 0.5.1.0 synopsis: Type safe string transformations description: See README.md in the project github repository. category: Data, Text@@ -66,6 +66,7 @@ Data.TypedEncoding.Instances.Enc.Base64 Data.TypedEncoding.Instances.Enc.Warn.Base64 Data.TypedEncoding.Instances.Restriction.ASCII+ Data.TypedEncoding.Instances.Restriction.Base64 Data.TypedEncoding.Instances.Restriction.BoundedAlphaNums Data.TypedEncoding.Instances.Restriction.ByteRep Data.TypedEncoding.Instances.Restriction.CHAR8