packages feed

avro 0.3.3.1 → 0.3.4.0

raw patch · 13 files changed

+907/−220 lines, 13 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.Avro.Decode: instance (Data.Avro.Decode.GetAvro a, GHC.Classes.Ord a) => Data.Avro.Decode.GetAvro (Data.Set.Internal.Set a)
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro Data.Avro.Decode.ContainerHeader
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro Data.ByteString.Internal.ByteString
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro Data.ByteString.Lazy.Internal.ByteString
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro Data.Text.Internal.Text
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro GHC.Base.String
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro GHC.Int.Int32
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro GHC.Int.Int64
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro GHC.Types.Bool
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro GHC.Types.Double
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro GHC.Types.Float
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro a => Data.Avro.Decode.GetAvro (Data.Vector.Vector a)
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro a => Data.Avro.Decode.GetAvro (GHC.Arr.Array GHC.Types.Int a)
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro a => Data.Avro.Decode.GetAvro (GHC.Base.Maybe a)
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro a => Data.Avro.Decode.GetAvro [a]
- Data.Avro.Decode: instance Data.Avro.Decode.GetAvro ty => Data.Avro.Decode.GetAvro (Data.Map.Internal.Map Data.Text.Internal.Text ty)
- Data.Avro.Encode: instance Data.Avro.Encode.EncodeAvro (Data.Avro.Types.Value Data.Avro.Schema.Type)
- Data.Avro.Schema: instance Data.Aeson.Types.ToJSON.ToJSON (Data.Avro.Types.Value Data.Avro.Schema.Type)
- Data.Avro.Types: Array :: (Vector (Value f)) -> Value f
- Data.Avro.Types: Boolean :: !Bool -> Value f
- Data.Avro.Types: Bytes :: {-# UNPACK #-} !ByteString -> Value f
- Data.Avro.Types: Double :: {-# UNPACK #-} !Double -> Value f
- Data.Avro.Types: Enum :: f -> {-# UNPACK #-} !Int -> Text -> Value f
- Data.Avro.Types: Fixed :: f -> {-# UNPACK #-} !ByteString -> Value f
- Data.Avro.Types: Float :: {-# UNPACK #-} !Float -> Value f
- Data.Avro.Types: Int :: {-# UNPACK #-} !Int32 -> Value f
- Data.Avro.Types: Long :: {-# UNPACK #-} !Int64 -> Value f
- Data.Avro.Types: Map :: (HashMap Text (Value f)) -> Value f
- Data.Avro.Types: Null :: Value f
- Data.Avro.Types: Record :: f -> (HashMap Text (Value f)) -> Value f
- Data.Avro.Types: String :: {-# UNPACK #-} !Text -> Value f
- Data.Avro.Types: Union :: (NonEmpty f) -> f -> (Value f) -> Value f
- Data.Avro.Types: data Value f
- Data.Avro.Types: instance GHC.Classes.Eq f => GHC.Classes.Eq (Data.Avro.Types.Value f)
- Data.Avro.Types: instance GHC.Show.Show f => GHC.Show.Show (Data.Avro.Types.Value f)
+ Data.Avro.Decode.Get: ContainerHeader :: !ByteString -> ByteString -> Get ByteString -> !Schema -> ContainerHeader
+ Data.Avro.Decode.Get: [containedSchema] :: ContainerHeader -> !Schema
+ Data.Avro.Decode.Get: [decompress] :: ContainerHeader -> ByteString -> Get ByteString
+ Data.Avro.Decode.Get: [syncBytes] :: ContainerHeader -> !ByteString
+ Data.Avro.Decode.Get: class GetAvro a
+ Data.Avro.Decode.Get: data ContainerHeader
+ Data.Avro.Decode.Get: getArray :: GetAvro ty => Get [ty]
+ Data.Avro.Decode.Get: getAvro :: GetAvro a => Get a
+ Data.Avro.Decode.Get: getBoolean :: Get Bool
+ Data.Avro.Decode.Get: getBytes :: Get ByteString
+ Data.Avro.Decode.Get: getCodec :: Monad m => Maybe ByteString -> m (ByteString -> m ByteString)
+ Data.Avro.Decode.Get: getDouble :: Get Double
+ Data.Avro.Decode.Get: getFloat :: Get Float
+ Data.Avro.Decode.Get: getInt :: Get Int32
+ Data.Avro.Decode.Get: getLong :: Get Int64
+ Data.Avro.Decode.Get: getMap :: GetAvro ty => Get (Map Text ty)
+ Data.Avro.Decode.Get: getString :: Get Text
+ Data.Avro.Decode.Get: getZigZag :: (Bits i, Integral i, DecodeRaw i) => Get i
+ Data.Avro.Decode.Get: instance (Data.Avro.Decode.Get.GetAvro a, GHC.Classes.Ord a) => Data.Avro.Decode.Get.GetAvro (Data.Set.Internal.Set a)
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro Data.Avro.Decode.Get.ContainerHeader
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro Data.ByteString.Internal.ByteString
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro Data.ByteString.Lazy.Internal.ByteString
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro Data.Text.Internal.Text
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro GHC.Base.String
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro GHC.Int.Int32
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro GHC.Int.Int64
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro GHC.Types.Bool
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro GHC.Types.Double
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro GHC.Types.Float
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro a => Data.Avro.Decode.Get.GetAvro (Data.Vector.Vector a)
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro a => Data.Avro.Decode.Get.GetAvro (GHC.Arr.Array GHC.Types.Int a)
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro a => Data.Avro.Decode.Get.GetAvro (GHC.Base.Maybe a)
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro a => Data.Avro.Decode.Get.GetAvro [a]
+ Data.Avro.Decode.Get: instance Data.Avro.Decode.Get.GetAvro ty => Data.Avro.Decode.Get.GetAvro (Data.Map.Internal.Map Data.Text.Internal.Text ty)
+ Data.Avro.Decode.Get: nrSyncBytes :: Integral sb => sb
+ Data.Avro.Decode.Get: sFromIntegral :: forall a b m. (Monad m, Bounded a, Bounded b, Integral a, Integral b) => a -> m b
+ Data.Avro.Decode.Lazy: class GetAvro a
+ Data.Avro.Decode.Lazy: decodeAvro :: Schema -> ByteString -> LazyValue Type
+ Data.Avro.Decode.Lazy: decodeContainer :: forall a. FromAvro a => ByteString -> [Either String a]
+ Data.Avro.Decode.Lazy: decodeContainer' :: forall a. FromAvro a => ByteString -> Either String [[Either String a]]
+ Data.Avro.Decode.Lazy: decodeContainerWithSchema :: FromAvro a => Schema -> ByteString -> [Either String a]
+ Data.Avro.Decode.Lazy: decodeContainerWithSchema' :: FromAvro a => Schema -> ByteString -> Either String [[Either String a]]
+ Data.Avro.Decode.Lazy: getAvro :: GetAvro a => Get a
+ Data.Avro.Decode.Lazy: getAvroOf :: Schema -> ByteString -> (ByteString, LazyValue Type)
+ Data.Avro.Decode.Lazy: getContainerValues :: ByteString -> Either String (Schema, [[LazyValue Type]])
+ Data.Avro.Decode.Lazy: getContainerValuesWith :: (Schema -> ByteString -> (ByteString, LazyValue Type)) -> ByteString -> Either String (Schema, [[LazyValue Type]])
+ Data.Avro.Decode.Lazy.Convert: fromStrictValue :: Value f -> LazyValue f
+ Data.Avro.Decode.Lazy.Convert: toStrictValue :: LazyValue f -> Either String (Value f)
+ Data.Avro.Decode.Lazy.Deconflict: deconflict :: Schema -> Schema -> LazyValue Type -> LazyValue Type
+ Data.Avro.Decode.Lazy.LazyValue: Array :: (Vector (LazyValue f)) -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Boolean :: Bool -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Bytes :: ByteString -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Double :: Double -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Enum :: f -> Int -> Text -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Error :: !String -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Fixed :: f -> ByteString -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Float :: Float -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Int :: Int32 -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Long :: Int64 -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Map :: (HashMap Text (LazyValue f)) -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Null :: LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Record :: f -> (HashMap Text (LazyValue f)) -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: String :: Text -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: Union :: (NonEmpty f) -> f -> (LazyValue f) -> LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: data LazyValue f
+ Data.Avro.Decode.Lazy.LazyValue: instance GHC.Classes.Eq f => GHC.Classes.Eq (Data.Avro.Decode.Lazy.LazyValue.LazyValue f)
+ Data.Avro.Decode.Lazy.LazyValue: instance GHC.Show.Show f => GHC.Show.Show (Data.Avro.Decode.Lazy.LazyValue.LazyValue f)
+ Data.Avro.Deriving.NormSchema: extractDerivables :: Schema -> [Schema]
+ Data.Avro.Deriving.NormSchema: getTypes :: Type -> [(TypeName, Type)]
+ Data.Avro.Deriving.NormSchema: normSchema :: Schema -> State (Map TypeName Schema) Schema
+ Data.Avro.EitherN: E3_1 :: a -> Either3 a b c
+ Data.Avro.EitherN: E3_2 :: b -> Either3 a b c
+ Data.Avro.EitherN: E3_3 :: c -> Either3 a b c
+ Data.Avro.EitherN: E4_1 :: a -> Either4 a b c d
+ Data.Avro.EitherN: E4_2 :: b -> Either4 a b c d
+ Data.Avro.EitherN: E4_3 :: c -> Either4 a b c d
+ Data.Avro.EitherN: E4_4 :: d -> Either4 a b c d
+ Data.Avro.EitherN: E5_1 :: a -> Either5 a b c d e
+ Data.Avro.EitherN: E5_2 :: b -> Either5 a b c d e
+ Data.Avro.EitherN: E5_3 :: c -> Either5 a b c d e
+ Data.Avro.EitherN: E5_4 :: d -> Either5 a b c d e
+ Data.Avro.EitherN: E5_5 :: e -> Either5 a b c d e
+ Data.Avro.EitherN: data Either3 a b c
+ Data.Avro.EitherN: data Either4 a b c d
+ Data.Avro.EitherN: data Either5 a b c d e
+ Data.Avro.EitherN: instance (Data.Avro.FromAvro.FromAvro a, Data.Avro.FromAvro.FromAvro b, Data.Avro.FromAvro.FromAvro c) => Data.Avro.FromAvro.FromAvro (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance (Data.Avro.FromAvro.FromAvro a, Data.Avro.FromAvro.FromAvro b, Data.Avro.FromAvro.FromAvro c, Data.Avro.FromAvro.FromAvro d) => Data.Avro.FromAvro.FromAvro (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance (Data.Avro.FromAvro.FromAvro a, Data.Avro.FromAvro.FromAvro b, Data.Avro.FromAvro.FromAvro c, Data.Avro.FromAvro.FromAvro d, Data.Avro.FromAvro.FromAvro e) => Data.Avro.FromAvro.FromAvro (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.EitherN: instance (Data.Avro.HasAvroSchema.HasAvroSchema a, Data.Avro.HasAvroSchema.HasAvroSchema b, Data.Avro.HasAvroSchema.HasAvroSchema c) => Data.Avro.HasAvroSchema.HasAvroSchema (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance (Data.Avro.HasAvroSchema.HasAvroSchema a, Data.Avro.HasAvroSchema.HasAvroSchema b, Data.Avro.HasAvroSchema.HasAvroSchema c, Data.Avro.HasAvroSchema.HasAvroSchema d) => Data.Avro.HasAvroSchema.HasAvroSchema (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance (Data.Avro.HasAvroSchema.HasAvroSchema a, Data.Avro.HasAvroSchema.HasAvroSchema b, Data.Avro.HasAvroSchema.HasAvroSchema c, Data.Avro.HasAvroSchema.HasAvroSchema d, Data.Avro.HasAvroSchema.HasAvroSchema e) => Data.Avro.HasAvroSchema.HasAvroSchema (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.EitherN: instance (Data.Avro.ToAvro.ToAvro a, Data.Avro.ToAvro.ToAvro b, Data.Avro.ToAvro.ToAvro c) => Data.Avro.ToAvro.ToAvro (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance (Data.Avro.ToAvro.ToAvro a, Data.Avro.ToAvro.ToAvro b, Data.Avro.ToAvro.ToAvro c, Data.Avro.ToAvro.ToAvro d) => Data.Avro.ToAvro.ToAvro (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance (Data.Avro.ToAvro.ToAvro a, Data.Avro.ToAvro.ToAvro b, Data.Avro.ToAvro.ToAvro c, Data.Avro.ToAvro.ToAvro d, Data.Avro.ToAvro.ToAvro e) => Data.Avro.ToAvro.ToAvro (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.EitherN: instance (GHC.Classes.Eq a, GHC.Classes.Eq b, GHC.Classes.Eq c) => GHC.Classes.Eq (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance (GHC.Classes.Eq a, GHC.Classes.Eq b, GHC.Classes.Eq c, GHC.Classes.Eq d) => GHC.Classes.Eq (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance (GHC.Classes.Eq a, GHC.Classes.Eq b, GHC.Classes.Eq c, GHC.Classes.Eq d, GHC.Classes.Eq e) => GHC.Classes.Eq (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.EitherN: instance (GHC.Classes.Ord a, GHC.Classes.Ord b, GHC.Classes.Ord c) => GHC.Classes.Ord (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance (GHC.Classes.Ord a, GHC.Classes.Ord b, GHC.Classes.Ord c, GHC.Classes.Ord d) => GHC.Classes.Ord (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance (GHC.Classes.Ord a, GHC.Classes.Ord b, GHC.Classes.Ord c, GHC.Classes.Ord d, GHC.Classes.Ord e) => GHC.Classes.Ord (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.EitherN: instance (GHC.Show.Show a, GHC.Show.Show b, GHC.Show.Show c) => GHC.Show.Show (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance (GHC.Show.Show a, GHC.Show.Show b, GHC.Show.Show c, GHC.Show.Show d) => GHC.Show.Show (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance (GHC.Show.Show a, GHC.Show.Show b, GHC.Show.Show c, GHC.Show.Show d, GHC.Show.Show e) => GHC.Show.Show (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.EitherN: instance GHC.Generics.Generic (Data.Avro.EitherN.Either3 a b c)
+ Data.Avro.EitherN: instance GHC.Generics.Generic (Data.Avro.EitherN.Either4 a b c d)
+ Data.Avro.EitherN: instance GHC.Generics.Generic (Data.Avro.EitherN.Either5 a b c d e)
+ Data.Avro.Encode: instance Data.Avro.Encode.EncodeAvro (Data.Avro.Types.Value.Value Data.Avro.Schema.Type)
+ Data.Avro.Schema: instance Data.Aeson.Types.ToJSON.ToJSON (Data.Avro.Types.Value.Value Data.Avro.Schema.Type)
+ Data.Avro.Schema: resultToEither :: Result b -> Either String b
+ Data.Avro.Types.Value: Array :: (Vector (Value f)) -> Value f
+ Data.Avro.Types.Value: Boolean :: !Bool -> Value f
+ Data.Avro.Types.Value: Bytes :: {-# UNPACK #-} !ByteString -> Value f
+ Data.Avro.Types.Value: Double :: {-# UNPACK #-} !Double -> Value f
+ Data.Avro.Types.Value: Enum :: f -> {-# UNPACK #-} !Int -> Text -> Value f
+ Data.Avro.Types.Value: Fixed :: f -> {-# UNPACK #-} !ByteString -> Value f
+ Data.Avro.Types.Value: Float :: {-# UNPACK #-} !Float -> Value f
+ Data.Avro.Types.Value: Int :: {-# UNPACK #-} !Int32 -> Value f
+ Data.Avro.Types.Value: Long :: {-# UNPACK #-} !Int64 -> Value f
+ Data.Avro.Types.Value: Map :: (HashMap Text (Value f)) -> Value f
+ Data.Avro.Types.Value: Null :: Value f
+ Data.Avro.Types.Value: Record :: f -> (HashMap Text (Value f)) -> Value f
+ Data.Avro.Types.Value: String :: {-# UNPACK #-} !Text -> Value f
+ Data.Avro.Types.Value: Union :: (NonEmpty f) -> f -> (Value f) -> Value f
+ Data.Avro.Types.Value: data Value f
+ Data.Avro.Types.Value: instance GHC.Classes.Eq f => GHC.Classes.Eq (Data.Avro.Types.Value.Value f)
+ Data.Avro.Types.Value: instance GHC.Show.Show f => GHC.Show.Show (Data.Avro.Types.Value.Value f)

Files

avro.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: fb70ba948e5cb538713c28699ed1af9e5f81d4b7fcc982938ed9b462e7511448+-- hash: 8b98a8b89f40922a3fbe1ab0ebd5a8bef25531bd5d1571b3216bb3b3ed75bed3  name:           avro-version:        0.3.3.1+version:        0.3.4.0 synopsis:       Avro serialization support for Haskell description:    Avro serialization and deserialization support for Haskell category:       Data@@ -51,21 +51,28 @@   exposed-modules:       Data.Avro       Data.Avro.Decode+      Data.Avro.Decode.Get+      Data.Avro.Decode.Lazy+      Data.Avro.Decode.Lazy.Convert+      Data.Avro.Decode.Lazy.Deconflict+      Data.Avro.Decode.Lazy.LazyValue       Data.Avro.DecodeRaw       Data.Avro.Deconflict-      Data.Avro.Encode       Data.Avro.Deriving+      Data.Avro.Deriving.NormSchema+      Data.Avro.EitherN+      Data.Avro.Encode       Data.Avro.EncodeRaw+      Data.Avro.FromAvro+      Data.Avro.HasAvroSchema       Data.Avro.JSON       Data.Avro.Schema+      Data.Avro.ToAvro       Data.Avro.Types+      Data.Avro.Types.Value       Data.Avro.Zag       Data.Avro.Zig-      Data.Avro.HasAvroSchema-      Data.Avro.FromAvro-      Data.Avro.ToAvro   other-modules:-      Data.Avro.Deriving.NormSchema       Paths_avro   hs-source-dirs:       src@@ -113,6 +120,7 @@       Avro.Codec.NestedSpec       Avro.Codec.TextSpec       Avro.Codec.ZigZagSpec+      Avro.Decode.Lazy.ValuesSpec       Avro.Deconflict.Reader       Avro.Deconflict.Writer       Avro.DeconflictSpec
src/Data/Avro/Decode.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances   #-} {-# LANGUAGE MultiWayIf          #-}+{-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE RecordWildCards     #-}-{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections       #-}-{-# LANGUAGE OverloadedStrings   #-}  module Data.Avro.Decode   ( decodeAvro@@ -14,35 +14,36 @@   , GetAvro(..)   ) where -import Prelude as P-import           Control.Monad              (replicateM,when) import qualified Codec.Compression.Zlib     as Z+import           Control.Monad              (replicateM, when) import qualified Data.Aeson                 as A import qualified Data.Array                 as Array+import           Data.Binary.Get            (Get, runGetOrFail) import qualified Data.Binary.Get            as G-import           Data.Binary.Get            (Get,runGetOrFail) import           Data.Binary.IEEE754        as IEEE import           Data.Bits-import qualified Data.ByteString.Lazy       as BL import           Data.ByteString            (ByteString)+import qualified Data.ByteString.Lazy       as BL import qualified Data.ByteString.Lazy.Char8 as BC+import qualified Data.HashMap.Strict        as HashMap import           Data.Int import           Data.List                  (foldl')-import qualified Data.List.NonEmpty as NE-import           Data.Maybe+import qualified Data.List.NonEmpty         as NE import qualified Data.Map                   as Map+import           Data.Maybe import           Data.Monoid                ((<>))-import qualified Data.HashMap.Strict        as HashMap import qualified Data.Set                   as Set import           Data.Text                  (Text) import qualified Data.Text                  as Text import qualified Data.Text.Encoding         as Text import qualified Data.Vector                as V+import           Prelude                    as P +import           Data.Avro.Decode.Get import           Data.Avro.DecodeRaw+import           Data.Avro.Schema           as S+import qualified Data.Avro.Types            as T import           Data.Avro.Zag-import           Data.Avro.Schema as S-import qualified Data.Avro.Types as T  -- |Decode bytes into a 'Value' as described by Schema. decodeAvro :: Schema -> BL.ByteString -> Either String (T.Value Type)@@ -62,39 +63,6 @@     Left (_,_,s)  -> Left s {-# INLINABLE decodeContainerWith #-} -data ContainerHeader = ContainerHeader-                      { syncBytes       :: !BL.ByteString-                      , decompress      :: BL.ByteString -> Get BL.ByteString-                      , containedSchema :: !Schema-                      }--nrSyncBytes :: Integral sb => sb-nrSyncBytes = 16--instance GetAvro ContainerHeader where-  getAvro =-   do magic <- getFixed avroMagicSize-      when (BL.fromStrict magic /= avroMagicBytes)-           (fail "Invalid magic number at start of container.")-      metadata <- getMap :: Get (Map.Map Text BL.ByteString) -- avro.schema, avro.codec-      sync  <- BL.fromStrict <$> getFixed nrSyncBytes-      codec <- getCodec (Map.lookup "avro.codec" metadata)-      schema <- case Map.lookup "avro.schema" metadata of-                  Nothing -> fail "Invalid container object: no schema."-                  Just s  -> case A.eitherDecode' s of-                                Left e  -> fail ("Can not decode container schema: " <> e)-                                Right x -> return x-      return ContainerHeader { syncBytes = sync, decompress = codec, containedSchema = schema }-   where avroMagicSize :: Integral a => a-         avroMagicSize = 4--         avroMagicBytes :: BL.ByteString-         avroMagicBytes = BC.pack "Obj" <> BL.pack [1]--         getFixed :: Int -> Get ByteString-         getFixed = G.getByteString-- getContainerWith :: (Schema -> Get a) -> Get (Schema, [[a]]) getContainerWith schemaToGet =    do ContainerHeader {..} <- getAvro@@ -180,145 +148,3 @@       else do vs <- replicateM (fromIntegral blockLength) (go t)               (vs:) <$> getBlocksOf t  {-# INLINE getBlocksOf #-}--class GetAvro a where-  getAvro :: Get a--instance GetAvro ty => GetAvro (Map.Map Text ty) where-  getAvro = getMap-instance GetAvro Bool where-  getAvro = getBoolean-instance GetAvro Int32 where-  getAvro = getInt-instance GetAvro Int64 where-  getAvro = getLong-instance GetAvro BL.ByteString where-  getAvro = BL.fromStrict <$> getBytes-instance GetAvro ByteString where-  getAvro = getBytes-instance GetAvro Text where-  getAvro = getString-instance GetAvro Float where-  getAvro = getFloat-instance GetAvro Double where-  getAvro = getDouble-instance GetAvro String where-  getAvro = Text.unpack <$> getString-instance GetAvro a => GetAvro [a] where-  getAvro = getArray-instance GetAvro a => GetAvro (Maybe a) where-  getAvro =-    do t <- getLong-       case t of-        0 -> return Nothing-        1 -> Just <$> getAvro-        n -> fail $ "Invalid tag for expected {null,a} Avro union, received: " <> show n--instance GetAvro a => GetAvro (Array.Array Int a) where-  getAvro =-    do ls <- getAvro-       return $ Array.listArray (0,length ls - 1) ls-instance GetAvro a => GetAvro (V.Vector a) where-  getAvro = V.fromList <$> getAvro-instance (GetAvro a, Ord a) => GetAvro (Set.Set a) where-  getAvro = Set.fromList <$> getAvro-------------------------------------------------------------------------------------  Specialized Getters--getBoolean :: Get Bool-getBoolean =- do w <- G.getWord8-    return (w == 0x01)---- |Get a 32-bit int (zigzag encoded, max of 5 bytes)-getInt :: Get Int32-getInt = getZigZag---- |Get a 64 bit int (zigzag encoded, max of 10 bytes)-getLong :: Get Int64-getLong = getZigZag---- |Get an zigzag encoded integral value consuming bytes till the msb is 0.-getZigZag :: (Bits i, Integral i, DecodeRaw i) => Get i-getZigZag = decodeRaw--getBytes :: Get ByteString-getBytes =- do w <- getLong-    G.getByteString (fromIntegral w)--getString :: Get Text-getString = Text.decodeUtf8 <$> getBytes---- a la Java:---  Bit 31 (the bit that is selected by the mask 0x80000000) represents the---  sign of the floating-point number. Bits 30-23 (the bits that are---  selected by the mask 0x7f800000) represent the exponent. Bits 22-0 (the---  bits that are selected by the mask 0x007fffff) represent the---  significand (sometimes called the mantissa) of the floating-point---  number.------  If the argument is positive infinity, the result is 0x7f800000.------  If the argument is negative infinity, the result is 0xff800000.------  If the argument is NaN, the result is 0x7fc00000.-getFloat :: Get Float-getFloat = IEEE.wordToFloat <$> G.getWord32le---- As in Java:---  Bit 63 (the bit that is selected by the mask 0x8000000000000000L)---  represents the sign of the floating-point number. Bits 62-52 (the bits---  that are selected by the mask 0x7ff0000000000000L) represent the---  exponent. Bits 51-0 (the bits that are selected by the mask---  0x000fffffffffffffL) represent the significand (sometimes called the---  mantissa) of the floating-point number.------  If the argument is positive infinity, the result is---  0x7ff0000000000000L.------  If the argument is negative infinity, the result is---  0xfff0000000000000L.------  If the argument is NaN, the result is 0x7ff8000000000000L-getDouble :: Get Double-getDouble = IEEE.wordToDouble <$> G.getWord64le-------------------------------------------------------------------------------------  Complex AvroValue Getters---- getRecord :: GetAvro ty => Get (AvroValue ty)--- getRecord = getAvro--getArray :: GetAvro ty => Get [ty]-getArray =-  do nr <- getLong-     if-      | nr == 0 -> return []-      | nr < 0  ->-          do _len <- getLong-             rs <- replicateM (fromIntegral (abs nr)) getAvro-             (rs <>) <$> getArray-      | otherwise ->-          do rs <- replicateM (fromIntegral nr) getAvro-             (rs <>) <$> getArray--getMap :: GetAvro ty => Get (Map.Map Text ty)-getMap = go Map.empty- where- go acc =-  do nr <- getLong-     if nr == 0-       then return acc-       else do m <- Map.fromList <$> replicateM (fromIntegral nr) getKVs-               go (Map.union m acc)- getKVs = (,) <$> getString <*> getAvro---- Safe-ish from integral-sFromIntegral :: forall a b m. (Monad m, Bounded a, Bounded b, Integral a, Integral b) => a -> m b-sFromIntegral a-  | aI > fromIntegral (maxBound :: b) ||-    aI < fromIntegral (minBound :: b)   = fail "Integral overflow."-  | otherwise                           = return (fromIntegral a)- where aI = fromIntegral a :: Integer
+ src/Data/Avro/Decode/Get.hs view
@@ -0,0 +1,222 @@+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE MultiWayIf          #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Data.Avro.Decode.Get+where++import qualified Codec.Compression.Zlib     as Z+import           Control.Monad              (foldM, replicateM, when)+import qualified Data.Aeson                 as A+import qualified Data.Array                 as Array+import           Data.Binary.Get            (Get, runGetOrFail)+import qualified Data.Binary.Get            as G+import           Data.Binary.IEEE754        as IEEE+import           Data.Bits+import           Data.ByteString            (ByteString)+import qualified Data.ByteString.Lazy       as BL+import qualified Data.ByteString.Lazy.Char8 as BC+import qualified Data.HashMap.Strict        as HashMap+import           Data.Int+import           Data.List                  (foldl')+import qualified Data.List.NonEmpty         as NE+import qualified Data.Map                   as Map+import           Data.Maybe+import           Data.Monoid                ((<>))+import qualified Data.Set                   as Set+import           Data.Text                  (Text)+import qualified Data.Text                  as Text+import qualified Data.Text.Encoding         as Text+import qualified Data.Vector                as V+import           Prelude                    as P++import           Data.Avro.DecodeRaw+import           Data.Avro.Schema           as S+import           Data.Avro.Zag++class GetAvro a where+  getAvro :: Get a++instance GetAvro ty => GetAvro (Map.Map Text ty) where+  getAvro = getMap+instance GetAvro Bool where+  getAvro = getBoolean+instance GetAvro Int32 where+  getAvro = getInt+instance GetAvro Int64 where+  getAvro = getLong+instance GetAvro BL.ByteString where+  getAvro = BL.fromStrict <$> getBytes+instance GetAvro ByteString where+  getAvro = getBytes+instance GetAvro Text where+  getAvro = getString+instance GetAvro Float where+  getAvro = getFloat+instance GetAvro Double where+  getAvro = getDouble+instance GetAvro String where+  getAvro = Text.unpack <$> getString+instance GetAvro a => GetAvro [a] where+  getAvro = getArray+instance GetAvro a => GetAvro (Maybe a) where+  getAvro =+    do t <- getLong+       case t of+        0 -> return Nothing+        1 -> Just <$> getAvro+        n -> fail $ "Invalid tag for expected {null,a} Avro union, received: " <> show n++instance GetAvro a => GetAvro (Array.Array Int a) where+  getAvro =+    do ls <- getAvro+       return $ Array.listArray (0,length ls - 1) ls+instance GetAvro a => GetAvro (V.Vector a) where+  getAvro = V.fromList <$> getAvro+instance (GetAvro a, Ord a) => GetAvro (Set.Set a) where+  getAvro = Set.fromList <$> getAvro+++data ContainerHeader = ContainerHeader+  { syncBytes       :: !BL.ByteString+  , decompress      :: BL.ByteString -> Get BL.ByteString+  , containedSchema :: !Schema+  }++nrSyncBytes :: Integral sb => sb+nrSyncBytes = 16++instance GetAvro ContainerHeader where+  getAvro =+   do magic <- getFixed avroMagicSize+      when (BL.fromStrict magic /= avroMagicBytes)+           (fail "Invalid magic number at start of container.")+      metadata <- getMap :: Get (Map.Map Text BL.ByteString) -- avro.schema, avro.codec+      sync  <- BL.fromStrict <$> getFixed nrSyncBytes+      codec <- getCodec (Map.lookup "avro.codec" metadata)+      schema <- case Map.lookup "avro.schema" metadata of+                  Nothing -> fail "Invalid container object: no schema."+                  Just s  -> case A.eitherDecode' s of+                                Left e  -> fail ("Can not decode container schema: " <> e)+                                Right x -> return x+      return ContainerHeader { syncBytes = sync, decompress = codec, containedSchema = schema }+   where avroMagicSize :: Integral a => a+         avroMagicSize = 4++         avroMagicBytes :: BL.ByteString+         avroMagicBytes = BC.pack "Obj" <> BL.pack [1]++         getFixed :: Int -> Get ByteString+         getFixed = G.getByteString+++getCodec :: Monad m => Maybe BL.ByteString -> m (BL.ByteString -> m BL.ByteString)+getCodec code | Just "null"    <- code =+                     return return+              | Just "deflate" <- code =+                     return (either (fail . show) return . Z.decompress)+              | Just x <- code =+                     fail ("Unrecognized codec: " <> BC.unpack x)+              | otherwise = return return+++--------------------------------------------------------------------------------+--  Specialized Getters++getBoolean :: Get Bool+getBoolean =+ do w <- G.getWord8+    return (w == 0x01)++-- |Get a 32-bit int (zigzag encoded, max of 5 bytes)+getInt :: Get Int32+getInt = getZigZag++-- |Get a 64 bit int (zigzag encoded, max of 10 bytes)+getLong :: Get Int64+getLong = getZigZag++-- |Get an zigzag encoded integral value consuming bytes till the msb is 0.+getZigZag :: (Bits i, Integral i, DecodeRaw i) => Get i+getZigZag = decodeRaw++getBytes :: Get ByteString+getBytes =+ do w <- getLong+    G.getByteString (fromIntegral w)++getString :: Get Text+getString = Text.decodeUtf8 <$> getBytes++-- a la Java:+--  Bit 31 (the bit that is selected by the mask 0x80000000) represents the+--  sign of the floating-point number. Bits 30-23 (the bits that are+--  selected by the mask 0x7f800000) represent the exponent. Bits 22-0 (the+--  bits that are selected by the mask 0x007fffff) represent the+--  significand (sometimes called the mantissa) of the floating-point+--  number.+--+--  If the argument is positive infinity, the result is 0x7f800000.+--+--  If the argument is negative infinity, the result is 0xff800000.+--+--  If the argument is NaN, the result is 0x7fc00000.+getFloat :: Get Float+getFloat = IEEE.wordToFloat <$> G.getWord32le++-- As in Java:+--  Bit 63 (the bit that is selected by the mask 0x8000000000000000L)+--  represents the sign of the floating-point number. Bits 62-52 (the bits+--  that are selected by the mask 0x7ff0000000000000L) represent the+--  exponent. Bits 51-0 (the bits that are selected by the mask+--  0x000fffffffffffffL) represent the significand (sometimes called the+--  mantissa) of the floating-point number.+--+--  If the argument is positive infinity, the result is+--  0x7ff0000000000000L.+--+--  If the argument is negative infinity, the result is+--  0xfff0000000000000L.+--+--  If the argument is NaN, the result is 0x7ff8000000000000L+getDouble :: Get Double+getDouble = IEEE.wordToDouble <$> G.getWord64le++--------------------------------------------------------------------------------+--  Complex AvroValue Getters++-- getRecord :: GetAvro ty => Get (AvroValue ty)+-- getRecord = getAvro++getArray :: GetAvro ty => Get [ty]+getArray =+  do nr <- getLong+     if+      | nr == 0 -> return []+      | nr < 0  ->+          do _len <- getLong+             rs <- replicateM (fromIntegral (abs nr)) getAvro+             (rs <>) <$> getArray+      | otherwise ->+          do rs <- replicateM (fromIntegral nr) getAvro+             (rs <>) <$> getArray++getMap :: GetAvro ty => Get (Map.Map Text ty)+getMap = go Map.empty+ where+ go acc =+  do nr <- getLong+     if nr == 0+       then return acc+       else do m <- Map.fromList <$> replicateM (fromIntegral nr) getKVs+               go (Map.union m acc)+ getKVs = (,) <$> getString <*> getAvro++-- Safe-ish from integral+sFromIntegral :: forall a b m. (Monad m, Bounded a, Bounded b, Integral a, Integral b) => a -> m b+sFromIntegral a+  | aI > fromIntegral (maxBound :: b) ||+    aI < fromIntegral (minBound :: b)   = fail "Integral overflow."+  | otherwise                           = return (fromIntegral a)+ where aI = fromIntegral a :: Integer
+ src/Data/Avro/Decode/Lazy.hs view
@@ -0,0 +1,283 @@+{-# LANGUAGE ConstraintKinds     #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE MultiWayIf          #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections       #-}++module Data.Avro.Decode.Lazy+  ( decodeAvro+  , decodeContainer+  , decodeContainer'+  , decodeContainerWithSchema+  , decodeContainerWithSchema'++  -- * Lower level interface+  , getContainerValues+  , getContainerValuesWith+  , getAvroOf+  , GetAvro(..)+  ) where++import qualified Codec.Compression.Zlib           as Z+import           Control.Monad                    (foldM, replicateM, when)+import qualified Data.Aeson                       as A+import qualified Data.Array                       as Array+import           Data.Binary.Get                  (Get, runGetOrFail)+import qualified Data.Binary.Get                  as G+import           Data.Binary.IEEE754              as IEEE+import           Data.Bits+import           Data.ByteString                  (ByteString)+import qualified Data.ByteString.Lazy             as BL+import qualified Data.ByteString.Lazy.Char8       as BC+import           Data.Either                      (isRight)+import qualified Data.HashMap.Strict              as HashMap+import           Data.Int+import           Data.List                        (foldl')+import qualified Data.List.NonEmpty               as NE+import qualified Data.Map                         as Map+import           Data.Maybe+import           Data.Monoid                      ((<>))+import qualified Data.Set                         as Set+import           Data.Tagged                      (Tagged, untag)+import           Data.Text                        (Text)+import qualified Data.Text                        as Text+import qualified Data.Text.Encoding               as Text+import qualified Data.Vector                      as V+import           Prelude                          as P++import qualified Data.Avro.Decode.Lazy.LazyValue  as T+import           Data.Avro.DecodeRaw+import           Data.Avro.HasAvroSchema          (schema)+import           Data.Avro.Schema                 as S+import           Data.Avro.Zag++import           Data.Avro.Decode.Get+import           Data.Avro.Decode.Lazy.Convert    (toStrictValue)+import           Data.Avro.Decode.Lazy.Deconflict as C+import           Data.Avro.FromAvro++-- | Decodes the container as a lazy list of values of the requested type.+--+-- The schema for the requested type will be de-conflicted with the schema+-- embedded with the container.+--+-- Errors are reported as a part of the list and the list will stop at first+-- error. This means that the consumer will get all the "good" content from+-- the container until the error is detected, then this error and then the list+-- is finished.+decodeContainer :: forall a. FromAvro a => BL.ByteString -> [Either String a]+decodeContainer bs =+  let vals = either (\err -> [Left err]) concat (decodeContainer' bs)+  in takeWhileInclusive isRight vals++-- | Decodes the container as a lazy list of values of the requested type.+--+-- The schema for the requested type will be de-conflicted with the schema+-- embedded with the container.+--+-- The content of the container is returned as a list of "blocks" of values+-- inside this container, so the notion of blocks in the container is preserved.+-- Since decoding is lazy it should be safe to concat these values into one lazy list.+--+-- The "outer" error represents the error in opening the container itself+-- (including problems like reading schemas embedded into the container.)+--+-- The "inner" errors represent problems in decoding individual values.+--+-- Note that this function will not stop decoding at the first occurance of the "inner"+-- error, and will continue attempting decoding values, so it is possible to+-- get 'Right' after 'Left'. It is up to the user to decide whether it is correct or not to+-- continue after errors (most likely it will not be correct).+--+-- 'decodeContainer' function makes a choice to stop after the first error.+decodeContainer' :: forall a. FromAvro a => BL.ByteString -> Either String [[Either String a]]+decodeContainer' = decodeContainerWithSchema' (untag (schema :: Tagged a Schema))++-- | Same as 'decodeContainer' but uses provided schema as a reader schema for the container+-- instead of the schema obtained from the type of 'a'.+--+-- It is up to the user to make sure that the provided schema is compatible with 'a'+-- and with the container's writer schema.+decodeContainerWithSchema :: FromAvro a => Schema -> BL.ByteString -> [Either String a]+decodeContainerWithSchema s bs =+  either (\err -> [Left err]) concat (decodeContainerWithSchema' s bs)++-- | Same as 'decodeContainer'' but uses provided schema as a reader schema for the container+-- instead of the schema obtained from the type of 'a'.+--+-- It is up to the user to make sure that the provided schema is compatible with 'a'+-- and with the container's writer schema.+decodeContainerWithSchema' :: FromAvro a => Schema -> BL.ByteString -> Either String [[Either String a]]+decodeContainerWithSchema' readerSchema bs = do+  (writerSchema, vals) <- getContainerValues bs+  pure $ (fmap . fmap) (convertValue writerSchema) vals+  where+    convertValue w v = toStrictValue (C.deconflict w readerSchema v) >>= (resultToEither . fromAvro)++-- |Decode bytes into a 'Value' as described by Schema.+decodeAvro :: Schema -> BL.ByteString -> T.LazyValue Type+decodeAvro s = snd . getAvroOf s+{-# INLINABLE decodeAvro #-}++-- | Decodes the container into a list of blocks of raw Avro values.+--+-- The content of the container is returned as a list of "blocks" of values+-- inside this container, so the notion of blocks in the container is preserved.+-- Since decoding is lazy it should be safe to concat these values into one lazy list.+--+-- Each 'LazyValue' can be an `Error' and this function doesn't make any attempts+-- of dealing with them leaving it up to the user.+--+-- The "outer" error represents the error in opening the container itself+-- (including problems like reading schemas embedded into the container.)+getContainerValues :: BC.ByteString -> Either String (Schema, [[T.LazyValue Type]])+getContainerValues = getContainerValuesWith getAvroOf+{-# INLINABLE getContainerValues #-}++getContainerValuesWith :: (Schema -> BL.ByteString -> (BL.ByteString, T.LazyValue Type))+                 -> BL.ByteString+                 -> Either String (Schema, [[T.LazyValue Type]])+getContainerValuesWith schemaToGet bs =+  case runGetOrFail getAvro bs of+    Left (bs', _, err) -> Left err+    Right (bs', _, ContainerHeader {..}) ->+      Right (containedSchema, snd $ getBlocks (schemaToGet containedSchema) syncBytes bs' decompress)+  where+    getRawBlock :: (BL.ByteString -> Get BL.ByteString) -> Get (Int, BC.ByteString)+    getRawBlock decompress = do+      nrObj    <- getLong >>= sFromIntegral+      nrBytes  <- getLong+      bytes    <- G.getLazyByteString nrBytes >>= decompress+      pure (nrObj, bytes)++    checkMarker :: BL.ByteString -> BL.ByteString -> Either String BL.ByteString+    checkMarker sync bs =+      case BL.splitAt nrSyncBytes bs of+        (marker, _) | marker /= sync -> Left "Invalid marker, does not match sync bytes."+        (_, rest) -> Right rest++    getBlocks :: (BL.ByteString -> (BL.ByteString, T.LazyValue Type))+              -> BL.ByteString+              -> BL.ByteString+              -> (BL.ByteString -> Get BL.ByteString)+              -> (BL.ByteString, [[T.LazyValue Type]])+    getBlocks getValue sync bs decompress =+      case runGetOrFail (getRawBlock decompress) bs of+        Left (bs', _, err) -> (bs', [[T.Error err]])+        Right (bs', _, (nrObj, bytes)) ->+          let (_, vs) = consumeN (fromIntegral nrObj) getValue bytes+          in case checkMarker sync bs' of+            Left err -> (bs', [[T.Error err]])+            Right bs'' | BL.null bs'' -> (bs'', [vs])+            Right bs'' ->+              let (rest, vs') = getBlocks getValue bs'' sync decompress+              in (rest, vs : vs')++decodeGet :: GetAvro a => (a -> T.LazyValue Type) -> BL.ByteString -> (BL.ByteString, T.LazyValue Type)+decodeGet f bs =+  let res = runGetOrFail (f <$> getAvro) bs+  in either (\(rest,_,s) -> (rest, T.Error s)) (\(rest,_,a) -> (rest, a)) res+{-# INLINE decodeGet #-}++consumeN :: Int64 -> (a -> (a, b)) -> a -> (a, [b])+consumeN n f a =+  if n == 0+    then (a, [])+    else+      let (a', b) = f a+          (r, bs) = consumeN (n-1) f a'+      in (r, b:bs)+{-# INLINE consumeN #-}++getAvroOf :: Schema -> BL.ByteString -> (BL.ByteString, T.LazyValue Type)+getAvroOf ty0 bs = go ty0 bs+  where+  env = S.buildTypeEnvironment envFail ty0+  envFail t = fail $ "Named type not in schema: " <> show t++  go :: Type -> BL.ByteString -> (BL.ByteString, T.LazyValue Type)+  go ty bs =+    case ty of+      Null    -> (bs, T.Null)+      Boolean -> decodeGet T.Boolean  bs+      Int     -> decodeGet T.Int      bs+      Long    -> decodeGet T.Long     bs+      Float   -> decodeGet T.Float    bs+      Double  -> decodeGet T.Double   bs+      Bytes   -> decodeGet T.Bytes    bs+      String  -> decodeGet T.String   bs+      Array t -> T.Array . V.fromList . mconcat <$> getElements bs (go t)+      Map t   -> T.Map . HashMap.fromList . mconcat <$> getKVPairs bs (go t)+      NamedType tn ->+        case runGetOrFail (env tn) bs of+          Left (bs', _, err) -> (bs', T.Error err)+          Right (bs', _, v)  -> go v bs'++      Record {..} -> do+        let getField bs' Field {..} = (fldName,) <$> go fldType bs'+        let flds = foldl' (\(bs', as) fld -> (:as) <$> getField bs' fld ) (bs, []) fields+        T.Record ty . HashMap.fromList <$> flds++      Enum {..} ->+        case runGetOrFail getLong bs of+          Left (bs', _, err) -> (bs', T.Error err)+          Right (bs', _, i)  ->+            case symbolLookup i of+              Nothing -> (bs', T.Error ("Unknown value {" <> show i <> "} for enum " <> Text.unpack (typeName ty) ))+              Just sym -> (bs', T.Enum ty (fromIntegral i) sym)++      Union ts unionLookup ->+        case runGetOrFail getLong bs of+          Left (bs', _, err) -> (bs', T.Error err)+          Right (bs', _, i)  ->+            case unionLookup i of+              Nothing -> (bs', T.Error $ "Decoded Avro tag is outside the expected range for a Union. Tag: " <> show i <> " union of: " <> show (P.map typeName $ NE.toList ts))+              Just t  -> T.Union ts t <$> go t bs'++      Fixed {..} ->+        case runGetOrFail (G.getByteString (fromIntegral size)) bs of+          Left (bs', _, err) -> (bs', T.Error err)+          Right (bs', _, v)  -> (bs', T.Fixed ty v)+{-# INLINABLE getAvroOf #-}++getKVPair getElement bs =+  case runGetOrFail getString bs of+    Left (bs'', _, err) -> (bs'', ("", T.Error err))+    Right (bs'', _, v)  -> (v,) <$> getElement bs''+{-# INLINE getKVPair #-}++getKVPairs :: BL.ByteString+           -> (BL.ByteString -> (BL.ByteString, T.LazyValue Type))+           -> (BL.ByteString, [[(Text, T.LazyValue Type)]])+getKVPairs bs getElement =+  case runGetOrFail (abs <$> getLong) bs of+    Left (bs', _, err) -> (bs', [[("", T.Error err)]])+    Right (bs', _, l)  | l == 0 -> (bs', [])+    Right (bs', _, l)  ->+      let (bs'', vs) = consumeN l (getKVPair getElement) bs'+          (rest, vs') = getKVPairs bs'' getElement+      in (rest, vs : vs')+{-# INLINE getKVPairs #-}+++getElements :: BL.ByteString+            -> (BL.ByteString -> (BL.ByteString, T.LazyValue Type))+            -> (BL.ByteString, [[T.LazyValue Type]])+getElements bs getElement  =+  case runGetOrFail (abs <$> getLong) bs of+    Left (bs', _, err) -> (bs', [[T.Error err]])+    Right (bs', _, l)  | l == 0 -> (bs', [])+    Right (bs', _, l)  ->+      let (bs'', vs) = consumeN l getElement bs'+          (rest, vs') = getElements bs'' getElement+      in (rest, vs : vs')+{-# INLINE getElements #-}++--+takeWhileInclusive :: (a -> Bool) -> [a] -> [a]+takeWhileInclusive _ [] = []+takeWhileInclusive p (x:xs) =+  x : if p x then takeWhileInclusive p xs else []+{-# INLINE takeWhileInclusive #-}
+ src/Data/Avro/Decode/Lazy/Convert.hs view
@@ -0,0 +1,45 @@+module Data.Avro.Decode.Lazy.Convert+where++import           Data.Avro.Decode.Lazy.LazyValue (LazyValue)+import qualified Data.Avro.Decode.Lazy.LazyValue as D+import           Data.Avro.Types.Value           (Value)+import qualified Data.Avro.Types.Value           as V+import           Data.Text                       (Text)++toStrictValue :: LazyValue f -> Either String (Value f)+toStrictValue d = case d of+  D.Null         -> Right V.Null+  D.Boolean v    -> Right $ V.Boolean v+  D.Int v        -> Right $ V.Int v+  D.Long v       -> Right $ V.Long v+  D.Float v      -> Right $ V.Float v+  D.Double v     -> Right $ V.Double v+  D.Bytes v      -> Right $ V.Bytes v+  D.String v     -> Right $ V.String v+  D.Array vs     -> V.Array <$> traverse toStrictValue vs+  D.Map vs       -> V.Map <$> traverse toStrictValue vs+  D.Record f vs  -> V.Record f <$> traverse toStrictValue vs+  D.Union fs f v -> V.Union fs f <$> toStrictValue v+  D.Fixed f v    -> Right $ V.Fixed f v+  D.Enum f i v   -> Right $ V.Enum f i v+  D.Error v      -> Left v+{-# INLINE toStrictValue #-}++fromStrictValue :: Value f -> LazyValue f+fromStrictValue d = case d of+  V.Null         -> D.Null+  V.Boolean v    -> D.Boolean v+  V.Int v        -> D.Int v+  V.Long v       -> D.Long v+  V.Float v      -> D.Float v+  V.Double v     -> D.Double v+  V.Bytes v      -> D.Bytes v+  V.String v     -> D.String v+  V.Array vs     -> D.Array $ fromStrictValue <$> vs+  V.Map vs       -> D.Map $ fromStrictValue <$> vs+  V.Record f vs  -> D.Record f $ fromStrictValue <$> vs+  V.Union fs f v -> D.Union fs f $ fromStrictValue v+  V.Fixed f v    -> D.Fixed f v+  V.Enum f i v   -> D.Enum f i v+{-# INLINE fromStrictValue #-}
+ src/Data/Avro/Decode/Lazy/Deconflict.hs view
@@ -0,0 +1,117 @@+module Data.Avro.Decode.Lazy.Deconflict+  ( deconflict+  ) where++import           Control.Applicative             ((<|>))+import           Data.Avro.Decode.Lazy.Convert   (fromStrictValue)+import           Data.Avro.Decode.Lazy.LazyValue as T+import           Data.Avro.Schema                as S+import           Data.HashMap.Strict             (HashMap)+import qualified Data.HashMap.Strict             as HashMap+import           Data.List                       (find)+import           Data.List.NonEmpty              (NonEmpty (..))+import qualified Data.List.NonEmpty              as NE+import qualified Data.Map                        as M+import           Data.Semigroup                  ((<>))+import qualified Data.Set                        as Set+import           Data.Text                       (Text)+import qualified Data.Text                       as Text+import qualified Data.Text.Encoding              as Text++-- | @deconflict writer reader val@ will convert a value that was+-- encoded/decoded with the writer's schema into the form specified by the+-- reader's schema.+deconflict :: Schema        -- ^ Writer schema+           -> Schema        -- ^ Reader schema+           -> T.LazyValue Type+           -> T.LazyValue Type+deconflict = resolveSchema++resolveSchema :: Type -> Type -> T.LazyValue Type -> T.LazyValue Type+resolveSchema writerSchema readerSchema v+  | writerSchema == readerSchema    = v+  | otherwise = go writerSchema readerSchema v+  where+    go :: Type -> Type -> T.LazyValue Type -> T.LazyValue Type+    go _ _ val@(T.Error _) = val+    go (S.Array aTy) (S.Array bTy) (T.Array vec) =+        T.Array $ fmap (go aTy bTy) vec+    go (S.Map aTy) (S.Map bTy) (T.Map mp)    =+        T.Map $ fmap (go aTy bTy) mp+    go a@S.Enum {} b@S.Enum {} val+        | name a == name b = resolveEnum a b val+    go a@S.Fixed {} b@S.Fixed {} val+        | name a == name b && size a == size b = val+    go a@S.Record {} b@S.Record {} val+        | name a == name b = resolveRecord a b val+    go (S.Union _ _) (S.Union ys _) val =+        resolveTwoUnions ys val+    go nonUnion (S.Union ys _) val =+        resolveReaderUnion nonUnion ys val+    go (S.Union _xs _) nonUnion val =+        resolveWriterUnion nonUnion val+    go eTy dTy val =+      case val of+        T.Int i32 | dTy == S.Long    -> T.Long   (fromIntegral i32)+                  | dTy == S.Float   -> T.Float  (fromIntegral i32)+                  | dTy == S.Double  -> T.Double (fromIntegral i32)+        T.Long i64 | dTy == S.Float  -> T.Float (fromIntegral i64)+                  | dTy == S.Double -> T.Double (fromIntegral i64)+        T.Float f | dTy == S.Double  -> T.Double (realToFrac f)+        T.String s | dTy == S.Bytes  -> T.Bytes (Text.encodeUtf8 s)+        T.Bytes bs | dTy == S.String -> T.String (Text.decodeUtf8 bs)+        _                            -> T.Error $ "Can not resolve differing writer and reader schemas: " ++ show (eTy, dTy)++-- The writer's symbol must be present in the reader's enum+resolveEnum :: Type -> Type -> T.LazyValue Type -> T.LazyValue Type+resolveEnum e d val@(T.Enum _ _ _txt) = val+  -- --  | txt `elem` symbols d = Right val+  -- --  | otherwise = Left "Decoded enum does not appear in reader's symbol list."++resolveTwoUnions :: NonEmpty Type -> T.LazyValue Type -> T.LazyValue Type+resolveTwoUnions ds (T.Union _ eTy val) =+  resolveReaderUnion eTy ds val++resolveReaderUnion :: Type -> NonEmpty Type -> T.LazyValue Type -> T.LazyValue Type+resolveReaderUnion e ds val =+  let hdl [] = T.Error $ "No corresponding union value for " <> Text.unpack (typeName e)+      hdl (d:rest) =+            case resolveSchema e d val of+              T.Error _ -> hdl rest+                -- Right (T.Union ds d v)+              v         -> T.Union ds d v+  in hdl (NE.toList ds)++resolveWriterUnion :: Type -> T.LazyValue Type -> T.LazyValue Type+resolveWriterUnion reader (T.Union _ ty val) = resolveSchema ty reader val++resolveRecord :: Type -> Type -> T.LazyValue Type -> T.LazyValue Type+resolveRecord writerSchema readerSchema (T.Record ty fldVals)  =+  T.Record ty . HashMap.fromList $ fmap (resolveFields fldVals (fields writerSchema)) (fields readerSchema)++-- For each field of the decoders, lookup the field in the hash map+--  1) If the field exists, call 'resolveSchema'+--  2) If the field is missing use the reader's default+--  3) If there is no default, fail.+--+-- XXX: Consider aliases in the writer schema, use those to retry on failed lookup.+resolveFields :: HashMap Text (T.LazyValue Type) -> [Field] -> Field -> (Text,T.LazyValue Type)+resolveFields hm writerFields readerField =+  let+    mbWriterField = findField readerField writerFields+    mbValue = HashMap.lookup (fldName readerField) hm+  in case (mbWriterField, mbValue, fldDefault readerField) of+    (Just w, Just x,_)   -> (fldName readerField, resolveSchema (fldType w) (fldType readerField) x)+    (_, Just x,_)  -> (fldName readerField, x)+    (_, _,Just def)      -> (fldName readerField, fromStrictValue def)+    (_,Nothing,Nothing)  -> (fldName readerField, T.Error ("No field and no default for " ++ show (fldName readerField)))++findField :: Field -> [Field] -> Maybe Field+findField f fs =+  let+    byName = find (\x -> fldName x == fldName f) fs+    allNames fld = Set.fromList (fldName fld : fldAliases fld)+    fNames = allNames f+    sameField = not . Set.null . Set.intersection fNames . allNames+    byAliases = find sameField fs+  in byName <|> byAliases
+ src/Data/Avro/Decode/Lazy/LazyValue.hs view
@@ -0,0 +1,27 @@+module Data.Avro.Decode.Lazy.LazyValue+where++import           Data.ByteString+import           Data.HashMap.Strict (HashMap)+import           Data.Int+import           Data.List.NonEmpty  (NonEmpty)+import           Data.Text+import           Data.Vector++data LazyValue f+      = Null+      | Boolean Bool+      | Int Int32+      | Long Int64+      | Float Float+      | Double Double+      | Bytes ByteString+      | String Text+      | Array (Vector (LazyValue f))       -- ^ Dynamically enforced monomorphic type.+      | Map (HashMap Text (LazyValue f))   -- ^ Dynamically enforced monomorphic type+      | Record f (HashMap Text (LazyValue f)) -- Order and a map+      | Union (NonEmpty f) f (LazyValue f) -- ^ Set of union options, schema for selected option, and the actual value.+      | Fixed f ByteString+      | Enum f Int Text  -- ^ An enum is a set of the possible symbols (the schema) and the selected symbol+      | Error !String+  deriving (Eq, Show)
src/Data/Avro/Deriving.hs view
@@ -45,6 +45,7 @@ import           Language.Haskell.TH.Syntax  import           Data.Avro.Deriving.NormSchema+import           Data.Avro.EitherN  import qualified Data.ByteString               as BS import qualified Data.ByteString.Lazy          as LBS@@ -233,6 +234,7 @@ genFromAvro _                             = pure []  genFromAvroFieldsExp :: Name -> [Field] -> Q Exp+genFromAvroFieldsExp n []     = [| (return . return) $(conE n) |] genFromAvroFieldsExp n (x:xs) =   [| \r ->     $(let extract fld = [| r .: T.pack $(mkTextLit (fldName fld))|]@@ -424,7 +426,10 @@   S.Union (Null :| [x]) _       -> [t| Maybe $(mkFieldTypeName x) |] -- AppT (ConT $ mkName "Maybe") (mkFieldTypeName x)   S.Union (x :| [Null]) _       -> [t| Maybe $(mkFieldTypeName x) |] --AppT (ConT $ mkName "Maybe") (mkFieldTypeName x)   S.Union (x :| [y]) _          -> [t| Either $(mkFieldTypeName x) $(mkFieldTypeName y) |] -- AppT (AppT (ConT (mkName "Either")) (mkFieldTypeName x)) (mkFieldTypeName y)-  S.Union (_ :| _) _            -> error "Unions with more than 2 elements are not yet supported"+  S.Union (a :| [b, c]) _       -> [t| Either3 $(mkFieldTypeName a) $(mkFieldTypeName b) $(mkFieldTypeName c) |]+  S.Union (a :| [b, c, d]) _    -> [t| Either4 $(mkFieldTypeName a) $(mkFieldTypeName b) $(mkFieldTypeName c) $(mkFieldTypeName d) |]+  S.Union (a :| [b, c, d, e]) _ -> [t| Either5 $(mkFieldTypeName a) $(mkFieldTypeName b) $(mkFieldTypeName c) $(mkFieldTypeName d) $(mkFieldTypeName e) |]+  S.Union _ _                   -> error "Unions with more than 5 elements are not yet supported"   S.Record n _ _ _ _ _          -> [t| $(conT $ mkDataTypeName n) |]   S.Map x                       -> [t| Map Text $(mkFieldTypeName x) |] --AppT (AppT (ConT (mkName "Map")) (ConT $ mkName "Text")) (mkFieldTypeName x)   S.Array x                     -> [t| [$(mkFieldTypeName x)] |]--AppT (ConT $ Text "[]") (mkFieldTypeName x)
+ src/Data/Avro/EitherN.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE DeriveGeneric  #-}+{-# LANGUAGE ScopedTypeVariables  #-}++module Data.Avro.EitherN where++import           Data.Avro+import           Data.Avro.Schema+import qualified Data.Avro.Types    as T+import           Data.Tagged+import           Data.List.NonEmpty+import           GHC.Generics       (Generic)++data Either3 a b c = E3_1 a | E3_2 b | E3_3 c deriving (Eq, Ord, Show, Generic)++data Either4 a b c d = E4_1 a | E4_2 b | E4_3 c | E4_4 d deriving (Eq, Ord, Show, Generic)++data Either5 a b c d e = E5_1 a | E5_2 b | E5_3 c | E5_4 d | E5_5 e deriving (Eq, Ord, Show, Generic)++instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c) => HasAvroSchema (Either3 a b c) where+  schema = Tagged $ mkUnion (untag (schema :: Tagged a Type) :| [+                             untag (schema :: Tagged b Type),+                             untag (schema :: Tagged c Type)+                            ])++instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d) => HasAvroSchema (Either4 a b c d) where+  schema = Tagged $ mkUnion (untag (schema :: Tagged a Type) :| [+                             untag (schema :: Tagged b Type),+                             untag (schema :: Tagged c Type),+                             untag (schema :: Tagged d Type)+                            ])++instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d, HasAvroSchema e) => HasAvroSchema (Either5 a b c d e) where+  schema = Tagged $ mkUnion (untag (schema :: Tagged a Type) :| [+                             untag (schema :: Tagged b Type),+                             untag (schema :: Tagged c Type),+                             untag (schema :: Tagged d Type),+                             untag (schema :: Tagged e Type)+                            ])++instance (FromAvro a, FromAvro b, FromAvro c) => FromAvro (Either3 a b c) where+  fromAvro e@(T.Union _ branch x)+    | matches branch schemaA = E3_1 <$> fromAvro x+    | matches branch schemaB = E3_2 <$> fromAvro x+    | matches branch schemaC = E3_3 <$> fromAvro x+    | otherwise              = badValue e "either3"+    where Tagged schemaA = schema :: Tagged a Type+          Tagged schemaB = schema :: Tagged b Type+          Tagged schemaC = schema :: Tagged c Type+  fromAvro x = badValue x "either3"++instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d) => FromAvro (Either4 a b c d) where+  fromAvro e@(T.Union _ branch x)+    | matches branch schemaA = E4_1 <$> fromAvro x+    | matches branch schemaB = E4_2 <$> fromAvro x+    | matches branch schemaC = E4_3 <$> fromAvro x+    | matches branch schemaD = E4_4 <$> fromAvro x+    | otherwise              = badValue e "either4"+    where Tagged schemaA = schema :: Tagged a Type+          Tagged schemaB = schema :: Tagged b Type+          Tagged schemaC = schema :: Tagged c Type+          Tagged schemaD = schema :: Tagged d Type+  fromAvro x = badValue x "either4"++instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d, FromAvro e) => FromAvro (Either5 a b c d e) where+  fromAvro e@(T.Union _ branch x)+    | matches branch schemaA = E5_1 <$> fromAvro x+    | matches branch schemaB = E5_2 <$> fromAvro x+    | matches branch schemaC = E5_3 <$> fromAvro x+    | matches branch schemaD = E5_4 <$> fromAvro x+    | matches branch schemaE = E5_5 <$> fromAvro x+    | otherwise              = badValue e "either5"+    where Tagged schemaA = schema :: Tagged a Type+          Tagged schemaB = schema :: Tagged b Type+          Tagged schemaC = schema :: Tagged c Type+          Tagged schemaD = schema :: Tagged d Type+          Tagged schemaE = schema :: Tagged e Type+  fromAvro x = badValue x "either5"++instance (ToAvro a, ToAvro b, ToAvro c) => ToAvro (Either3 a b c) where+  toAvro e =+    let sch@(one :| [two, three]) = options (schemaOf e)+    in case e of+      E3_1 a -> T.Union sch one   (toAvro a)+      E3_2 b -> T.Union sch two   (toAvro b)+      E3_3 c -> T.Union sch three (toAvro c)++instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d) => ToAvro (Either4 a b c d) where+  toAvro e =+    let sch@(one :| [two, three, four]) = options (schemaOf e)+    in case e of+      E4_1 a -> T.Union sch one   (toAvro a)+      E4_2 b -> T.Union sch two   (toAvro b)+      E4_3 c -> T.Union sch three (toAvro c)+      E4_4 d -> T.Union sch four  (toAvro d)++instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e) => ToAvro (Either5 a b c d e) where+  toAvro e =+    let sch@(one :| [two, three, four, five]) = options (schemaOf e)+    in case e of+      E5_1 a -> T.Union sch one   (toAvro a)+      E5_2 b -> T.Union sch two   (toAvro b)+      E5_3 c -> T.Union sch three (toAvro c)+      E5_4 d -> T.Union sch four  (toAvro d)+      E5_5 e -> T.Union sch five  (toAvro e)
src/Data/Avro/Schema.hs view
@@ -25,6 +25,7 @@   , typeName   , buildTypeEnvironment   , Result(..)+  , resultToEither    , matches @@ -349,7 +350,14 @@       Ty.Enum _ _ txt      -> A.String txt  data Result a = Success a | Error String-  deriving (Eq,Ord,Show)+  deriving (Eq, Ord, Show)++resultToEither :: Result b -> Either String b+resultToEither r =+  case r of+    Success v -> Right v+    Error err -> Left err+{-# INLINE resultToEither #-}  instance Monad Result where   return = pure
src/Data/Avro/Types.hs view
@@ -1,25 +1,6 @@-module Data.Avro.Types where--import Data.ByteString-import Data.HashMap.Strict (HashMap)-import Data.Int-import Data.List.NonEmpty (NonEmpty)-import Data.Text-import Data.Vector+module Data.Avro.Types+( module X+)+where -data Value f-      = Null-      | Boolean !Bool-      | Int {-# UNPACK #-} !Int32-      | Long {-# UNPACK #-} !Int64-      | Float {-# UNPACK #-} !Float-      | Double {-# UNPACK #-} !Double-      | Bytes {-# UNPACK #-} !ByteString-      | String {-# UNPACK #-} !Text-      | Array (Vector (Value f))       -- ^ Dynamically enforced monomorphic type.-      | Map (HashMap Text (Value f))   -- ^ Dynamically enforced monomorphic type-      | Record f (HashMap Text (Value f)) -- Order and a map-      | Union (NonEmpty f) f (Value f) -- ^ Set of union options, schema for selected option, and the actual value.-      | Fixed f {-# UNPACK #-} !ByteString-      | Enum f {-# UNPACK #-} !Int Text  -- ^ An enum is a set of the possible symbols (the schema) and the selected symbol-  deriving (Eq, Show)+import           Data.Avro.Types.Value as X
+ src/Data/Avro/Types/Value.hs view
@@ -0,0 +1,25 @@+module Data.Avro.Types.Value where++import           Data.ByteString+import           Data.HashMap.Strict (HashMap)+import           Data.Int+import           Data.List.NonEmpty  (NonEmpty)+import           Data.Text+import           Data.Vector++data Value f+      = Null+      | Boolean !Bool+      | Int {-# UNPACK #-} !Int32+      | Long {-# UNPACK #-} !Int64+      | Float {-# UNPACK #-} !Float+      | Double {-# UNPACK #-} !Double+      | Bytes {-# UNPACK #-} !ByteString+      | String {-# UNPACK #-} !Text+      | Array (Vector (Value f))       -- ^ Dynamically enforced monomorphic type.+      | Map (HashMap Text (Value f))   -- ^ Dynamically enforced monomorphic type+      | Record f (HashMap Text (Value f)) -- Order and a map+      | Union (NonEmpty f) f (Value f) -- ^ Set of union options, schema for selected option, and the actual value.+      | Fixed f {-# UNPACK #-} !ByteString+      | Enum f {-# UNPACK #-} !Int Text  -- ^ An enum is a set of the possible symbols (the schema) and the selected symbol+  deriving (Eq, Show)
+ test/Avro/Decode/Lazy/ValuesSpec.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE DeriveGeneric       #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+module Avro.Decode.Lazy.ValuesSpec+where++import           Data.Avro+import           Data.Avro.Decode.Lazy+import           Data.Avro.Decode.Lazy.Convert as TC+import           Data.Avro.Deriving+import           Data.Either                   (isLeft)++import           Test.Hspec++{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}++deriveAvro "test/data/small.avsc"++spec :: Spec+spec = describe "Avro.Decode.Lazy.ValueSpec" $ do+  let msg = Endpoint+              { endpointIps         = ["192.168.1.1", "127.0.0.1"]+              , endpointPorts       = [PortRange 1 10, PortRange 11 20]+              , endpointOpaque      = Opaque "16-b-long-string"+              , endpointCorrelation = Opaque "opaq-correlation"+              , endpointTag         = Left 14+              }++  it "should lazily decode correct value" $ do+    let lazyValue = decodeAvro schema'Endpoint (encode msg)+    TC.toStrictValue lazyValue `shouldBe` Right (toAvro msg)++  it "should return an error for a wrong content" $ do+    let lazyValue = decodeAvro schema'Endpoint "nonsense lives here"+    TC.toStrictValue lazyValue `shouldSatisfy` isLeft