argo 0.2022.1.15 → 0.2022.2.2
raw patch · 18 files changed
+1903/−1148 lines, 18 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Argo: fromValue :: HasCodec a => Value -> Either String a
- Argo: toValue :: HasCodec a => a -> Value
- Argo.Class.FromValue: fromValue :: HasCodec a => Value -> Either String a
- Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b) => Argo.Class.HasCodec.HasCodec (Data.Either.Either a b)
- Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b) => Argo.Class.HasCodec.HasCodec (a, b)
- Argo.Class.HasCodec: instance Argo.Class.HasCodec.HasCodec a => Argo.Class.HasCodec.HasCodec (Argo.Json.Array.Array a)
- Argo.Class.HasCodec: instance Argo.Class.HasCodec.HasCodec a => Argo.Class.HasCodec.HasCodec (Argo.Json.Object.Object a)
- Argo.Class.HasCodec: instance Argo.Class.HasCodec.HasCodec a => Argo.Class.HasCodec.HasCodec (Data.Map.Internal.Map Argo.Json.Name.Name a)
- Argo.Class.HasCodec: instance Argo.Class.HasCodec.HasCodec a => Argo.Class.HasCodec.HasCodec (GHC.Base.NonEmpty a)
- Argo.Class.HasCodec: instance Argo.Class.HasCodec.HasCodec a => Argo.Class.HasCodec.HasCodec (GHC.Maybe.Maybe a)
- Argo.Class.HasCodec: instance Argo.Class.HasCodec.HasCodec a => Argo.Class.HasCodec.HasCodec [a]
- Argo.Class.ToValue: toValue :: HasCodec a => a -> Value
- Argo.Codec.Codec: instance (GHC.Base.Alternative r, GHC.Base.Alternative w, GHC.Base.Monoid s) => GHC.Base.Alternative (Argo.Codec.Codec.Codec r w s i)
- Argo.Codec.Codec: instance (GHC.Base.Applicative r, GHC.Base.Applicative w, GHC.Base.Monoid s) => GHC.Base.Applicative (Argo.Codec.Codec.Codec r w s i)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Argo.Class.HasCodec.HasCodec c, Argo.Class.HasCodec.HasCodec d, Argo.Class.HasCodec.HasCodec e, Argo.Class.HasCodec.HasCodec f, Argo.Class.HasCodec.HasCodec g, Argo.Class.HasCodec.HasCodec h, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, Data.Typeable.Internal.Typeable c, Data.Typeable.Internal.Typeable d, Data.Typeable.Internal.Typeable e, Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable g, Data.Typeable.Internal.Typeable h) => Argo.Class.HasCodec.HasCodec (a, b, c, d, e, f, g, h)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Argo.Class.HasCodec.HasCodec c, Argo.Class.HasCodec.HasCodec d, Argo.Class.HasCodec.HasCodec e, Argo.Class.HasCodec.HasCodec f, Argo.Class.HasCodec.HasCodec g, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, Data.Typeable.Internal.Typeable c, Data.Typeable.Internal.Typeable d, Data.Typeable.Internal.Typeable e, Data.Typeable.Internal.Typeable f, Data.Typeable.Internal.Typeable g) => Argo.Class.HasCodec.HasCodec (a, b, c, d, e, f, g)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Argo.Class.HasCodec.HasCodec c, Argo.Class.HasCodec.HasCodec d, Argo.Class.HasCodec.HasCodec e, Argo.Class.HasCodec.HasCodec f, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, Data.Typeable.Internal.Typeable c, Data.Typeable.Internal.Typeable d, Data.Typeable.Internal.Typeable e, Data.Typeable.Internal.Typeable f) => Argo.Class.HasCodec.HasCodec (a, b, c, d, e, f)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Argo.Class.HasCodec.HasCodec c, Argo.Class.HasCodec.HasCodec d, Argo.Class.HasCodec.HasCodec e, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, Data.Typeable.Internal.Typeable c, Data.Typeable.Internal.Typeable d, Data.Typeable.Internal.Typeable e) => Argo.Class.HasCodec.HasCodec (a, b, c, d, e)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Argo.Class.HasCodec.HasCodec c, Argo.Class.HasCodec.HasCodec d, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, Data.Typeable.Internal.Typeable c, Data.Typeable.Internal.Typeable d) => Argo.Class.HasCodec.HasCodec (a, b, c, d)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Argo.Class.HasCodec.HasCodec c, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, Data.Typeable.Internal.Typeable c) => Argo.Class.HasCodec.HasCodec (a, b, c)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b) => Argo.Class.HasCodec.HasCodec (Data.Either.Either a b)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Argo.Class.HasCodec.HasCodec b, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b) => Argo.Class.HasCodec.HasCodec (a, b)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Argo.Json.Array.Array a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Argo.Json.Object.Object a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Data.Map.Internal.Map Argo.Json.Name.Name a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Data.Map.Internal.Map Argo.Json.String.String a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Data.Map.Internal.Map Argo.Vendor.Text.LazyText a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Data.Map.Internal.Map Data.Text.Internal.Text a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (Data.Map.Internal.Map GHC.Base.String a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (GHC.Base.NonEmpty a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec (GHC.Maybe.Maybe a)
+ Argo.Class.HasCodec: instance (Argo.Class.HasCodec.HasCodec a, Data.Typeable.Internal.Typeable a) => Argo.Class.HasCodec.HasCodec [a]
+ Argo.Codec.Codec: instance (GHC.Base.Alternative r, GHC.Base.Alternative w, GHC.Base.Applicative s, GHC.Base.Monoid a) => GHC.Base.Alternative (Argo.Codec.Codec.Codec r w (s a) i)
+ Argo.Codec.Codec: instance (GHC.Base.Applicative r, GHC.Base.Applicative w, GHC.Base.Applicative s, GHC.Base.Monoid a) => GHC.Base.Applicative (Argo.Codec.Codec.Codec r w (s a) i)
+ Argo.Codec.Value: getRef :: Value a -> AccumT (Map Identifier Schema) Identity (Either Schema Identifier)
+ Argo.Codec.Value: identified :: forall a. Typeable a => Value a -> Value a
+ Argo.Codec.Value: ref :: Either Schema Identifier -> Value
+ Argo.Schema.Identifier: Identifier :: Text -> Identifier
+ Argo.Schema.Identifier: fromText :: Text -> Identifier
+ Argo.Schema.Identifier: instance Control.DeepSeq.NFData Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance Data.String.IsString Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance GHC.Base.Semigroup Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance GHC.Classes.Eq Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance GHC.Classes.Ord Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance GHC.Generics.Generic Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance GHC.Show.Show Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: instance Language.Haskell.TH.Syntax.Lift Argo.Schema.Identifier.Identifier
+ Argo.Schema.Identifier: newtype Identifier
+ Argo.Schema.Identifier: toText :: Identifier -> Text
+ Argo.Schema.Schema: identified :: Identifier -> Schema -> (Maybe Identifier, Schema)
+ Argo.Schema.Schema: unidentified :: Schema -> (Maybe Identifier, Schema)
- Argo.Class.HasCodec: basicCodec :: String -> Schema -> (a -> Value) -> (Value -> Maybe a) -> Value a
+ Argo.Class.HasCodec: basicCodec :: forall a. Typeable a => Schema -> (a -> Value) -> (Value -> Maybe a) -> Value a
- Argo.Codec.Array: type Array a = List [Schema] Value a
+ Argo.Codec.Array: type Array a = List (AccumT (Map Identifier Schema) Identity [(Maybe Identifier, Schema)]) Value a
- Argo.Codec.List: fromListCodec :: (Permission -> s -> Schema) -> Value [e] -> Permission -> List s e a -> Value a
+ Argo.Codec.List: fromListCodec :: (Permission -> s -> AccumT (Map Identifier Schema) Identity (Maybe Identifier, Schema)) -> Value [e] -> Permission -> List s e a -> Value a
- Argo.Codec.Object: type Object a = List [(Name, Bool, Schema)] (Member Value) a
+ Argo.Codec.Object: type Object a = List (AccumT (Map Identifier Schema) Identity [((Name, Bool), (Maybe Identifier, Schema))]) (Member Value) a
- Argo.Codec.Value: type Value a = Codec (ReaderT Value (ExceptT String Identity)) (MaybeT (StateT Value Identity)) Schema a a
+ Argo.Codec.Value: type Value a = Codec (ReaderT Value (ExceptT String Identity)) (MaybeT (StateT Value Identity)) (AccumT (Map Identifier Schema) Identity (Maybe Identifier, Schema)) a a
Files
- argo.cabal +3/−3
- source/benchmark/Main.hs +135/−223
- source/library/Argo.hs +0/−4
- source/library/Argo/Class/FromValue.hs +0/−8
- source/library/Argo/Class/HasCodec.hs +950/−571
- source/library/Argo/Class/ToValue.hs +0/−8
- source/library/Argo/Codec/Array.hs +48/−22
- source/library/Argo/Codec/Codec.hs +19/−8
- source/library/Argo/Codec/List.hs +9/−1
- source/library/Argo/Codec/Object.hs +72/−37
- source/library/Argo/Codec/Value.hs +63/−6
- source/library/Argo/Decode.hs +2/−2
- source/library/Argo/Encode.hs +2/−2
- source/library/Argo/Schema/Identifier.hs +27/−0
- source/library/Argo/Schema/Schema.hs +8/−0
- source/library/Argo/Vendor/Map.hs +4/−0
- source/library/Argo/Vendor/Transformers.hs +26/−21
- source/test-suite/Main.hs +535/−232
argo.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: argo-version: 0.2022.1.15+version: 0.2022.2.2 build-type: Simple category: JSON@@ -67,9 +67,7 @@ autogen-modules: Paths_argo exposed-modules: Argo- Argo.Class.FromValue Argo.Class.HasCodec- Argo.Class.ToValue Argo.Codec.Array Argo.Codec.Codec Argo.Codec.List@@ -92,6 +90,7 @@ Argo.Pointer.Pointer Argo.Pointer.Token Argo.QuasiQuoter+ Argo.Schema.Identifier Argo.Schema.Schema Argo.Type.Config Argo.Type.Decimal@@ -134,6 +133,7 @@ import: executable build-depends:+ , tasty >= 1.4.2 && < 1.5 , tasty-bench >= 0.2.5 && < 0.4 hs-source-dirs: source/benchmark main-is: Main.hs
source/benchmark/Main.hs view
@@ -1,232 +1,144 @@-{-# LANGUAGE OverloadedStrings #-}- import qualified Argo+import qualified Control.DeepSeq as DeepSeq+import qualified Control.Exception as Exception+import qualified Control.Monad.Trans.Writer as Writer import qualified Data.ByteString as ByteString import qualified Data.ByteString.Builder as Builder import qualified Data.ByteString.Lazy as LazyByteString+import qualified Data.List as List import qualified Data.Text as Text-import qualified Test.Tasty.Bench as Tasty+import qualified Data.Text.Encoding as Encoding+import qualified Test.Tasty as Tasty+import qualified Test.Tasty.Bench as Bench main :: IO ()-main = Tasty.defaultMain- [ Tasty.bgroup- "encode"- [ Tasty.bgroup "Null" [Tasty.bench "null" $ Tasty.nf encode Argo.Null]- , Tasty.bgroup- "Boolean"- [Tasty.bench "false" . Tasty.nf encode $ Argo.Boolean False]- , Tasty.bgroup- "Number"- [ Tasty.bench "zero" . Tasty.nf encode . Argo.Number $ Argo.Decimal- 0- 0- ]- , Tasty.bgroup- "String"- [ Tasty.bench "empty" . Tasty.nf encode $ Argo.String ""- , Tasty.bench "1 character"- . Tasty.nf encode- . Argo.String- . Text.pack- $ replicate 1 'a'- , Tasty.bench "10 characters"- . Tasty.nf encode- . Argo.String- . Text.pack- $ replicate 10 'a'- , Tasty.bench "100 characters"- . Tasty.nf encode- . Argo.String- . Text.pack- $ replicate 100 'a'- , Tasty.bench "1000 characters"- . Tasty.nf encode- . Argo.String- . Text.pack- $ replicate 1000 'a'- , Tasty.bench "10000 characters"- . Tasty.nf encode- . Argo.String- . Text.pack- $ replicate 10000 'a'- ]- , Tasty.bgroup- "Array"- [ Tasty.bench "empty" . Tasty.nf encode $ Argo.Array []- , Tasty.bench "1 element"- . Tasty.nf encode- . Argo.Array- $ replicate 1 Argo.Null- , Tasty.bench "10 elements"- . Tasty.nf encode- . Argo.Array- $ replicate 10 Argo.Null- , Tasty.bench "100 elements"- . Tasty.nf encode- . Argo.Array- $ replicate 100 Argo.Null- , Tasty.bench "1000 elements"- . Tasty.nf encode- . Argo.Array- $ replicate 1000 Argo.Null- , Tasty.bench "10000 elements"- . Tasty.nf encode- . Argo.Array- $ replicate 10000 Argo.Null- ]- , Tasty.bgroup- "Object"- [ Tasty.bench "empty" . Tasty.nf encode $ Argo.Object []- , Tasty.bench "1 element"- . Tasty.nf encode- . Argo.Object- . replicate 1- $ Argo.Member (Argo.Name "") Argo.Null- , Tasty.bench "10 elements"- . Tasty.nf encode- . Argo.Object- . replicate 10- $ Argo.Member (Argo.Name "") Argo.Null- , Tasty.bench "100 elements"- . Tasty.nf encode- . Argo.Object- . replicate 100- $ Argo.Member (Argo.Name "") Argo.Null- , Tasty.bench "1000 elements"- . Tasty.nf encode- . Argo.Object- . replicate 1000- $ Argo.Member (Argo.Name "") Argo.Null- , Tasty.bench "10000 elements"- . Tasty.nf encode- . Argo.Object- . replicate 10000- $ Argo.Member (Argo.Name "") Argo.Null- ]- ]- , Tasty.bgroup- "decode"- [ Tasty.bgroup "Null" [Tasty.bench "null" $ Tasty.nf decode "null"]- , Tasty.bgroup- "Boolean"- [Tasty.bench "false" $ Tasty.nf decode "false"]- , Tasty.bgroup "Number" [Tasty.bench "zero" $ Tasty.nf decode "0"]- , Tasty.bgroup- "String"- [ Tasty.bench "empty" $ Tasty.nf decode "\"\""- , Tasty.bench "one byte" $ Tasty.nf decode "\"$\""- , Tasty.bench "two bytes" $ Tasty.nf decode "\"\xc2\xa2\""- , Tasty.bench "three bytes" $ Tasty.nf decode "\"\xe2\x82\xac\""- , Tasty.bench "four bytes" $ Tasty.nf decode "\"\xf0\x90\x8d\x88\""- , Tasty.bench "short escape" $ Tasty.nf decode "\"\\n\""- , Tasty.bench "long escape" $ Tasty.nf decode "\"\\u001f\""- , Tasty.bench "surrogate pair"- $ Tasty.nf decode "\"\\ud834\\udd1e\""- , Tasty.bench "1 character"- . Tasty.nf decode- $ "\""- <> ByteString.replicate 1 0x61- <> "\""- , Tasty.bench "10 characters"- . Tasty.nf decode- $ "\""- <> ByteString.replicate 10 0x61- <> "\""- , Tasty.bench "100 characters"- . Tasty.nf decode- $ "\""- <> ByteString.replicate 100 0x61- <> "\""- , Tasty.bench "1000 characters"- . Tasty.nf decode- $ "\""- <> ByteString.replicate 1000 0x61- <> "\""- , Tasty.bench "10000 characters"- . Tasty.nf decode- $ "\""- <> ByteString.replicate 10000 0x61- <> "\""- ]- , Tasty.bgroup- "Array"- [ Tasty.bench "empty" $ Tasty.nf decode "[]"- , Tasty.bench "1 element" $ Tasty.nf decode "[null]"- , Tasty.bench "10 elements"- . Tasty.nf decode- $ "[null"- <> ByteString.pack- (take (5 * 9) $ cycle [0x2c, 0x6e, 0x75, 0x6c, 0x6c])- <> "]"- , Tasty.bench "100 elements"- . Tasty.nf decode- $ "[null"- <> ByteString.pack- (take (5 * 99) $ cycle [0x2c, 0x6e, 0x75, 0x6c, 0x6c])- <> "]"- , Tasty.bench "1000 elements"- . Tasty.nf decode- $ "[null"- <> ByteString.pack- (take (5 * 999) $ cycle [0x2c, 0x6e, 0x75, 0x6c, 0x6c])- <> "]"- , Tasty.bench "10000 elements"- . Tasty.nf decode- $ "[null"- <> ByteString.pack- (take (5 * 9999) $ cycle [0x2c, 0x6e, 0x75, 0x6c, 0x6c])- <> "]"- ]- , Tasty.bgroup- "Object"- [ Tasty.bench "empty" $ Tasty.nf decode "{}"- , Tasty.bench "1 element" $ Tasty.nf decode "{\"\":null}"- , Tasty.bench "10 elements"- . Tasty.nf decode- $ "{\"\":null"- <> ByteString.pack- (take (5 * 9) $ cycle- [0x2c, 0x22, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c]- )- <> "}"- , Tasty.bench "100 elements"- . Tasty.nf decode- $ "{\"\":null"- <> ByteString.pack- (take (5 * 99) $ cycle- [0x2c, 0x22, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c]- )- <> "}"- , Tasty.bench "1000 elements"- . Tasty.nf decode- $ "{\"\":null"- <> ByteString.pack- (take (5 * 999) $ cycle- [0x2c, 0x22, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c]- )- <> "}"- , Tasty.bench "10000 elements"- . Tasty.nf decode- $ "{\"\":null"- <> ByteString.pack- (take (5 * 9999) $ cycle- [0x2c, 0x22, 0x22, 0x3a, 0x6e, 0x75, 0x6c, 0x6c]- )- <> "}"- ]- ]- , Tasty.bgroup- "Pointer"- [ Tasty.bench "decode" $ Tasty.nf Argo.decodePointer ""- , Tasty.bench "encode"- . Tasty.nf Builder.toLazyByteString- . Argo.encodePointer- $ Argo.Pointer []- ]- ]+main = Bench.defaultMain . Writer.execWriter $ do -encode :: Argo.Value -> LazyByteString.ByteString-encode = Builder.toLazyByteString . Argo.encode+ group "encode" $ do -decode :: ByteString.ByteString -> Either String Argo.Value-decode = Argo.decode+ group "Null" $ do+ bench "null" Argo.Null encode++ group "Boolean" $ do+ bench "false" (Argo.Boolean False) encode+ bench "true" (Argo.Boolean True) encode++ group "Number" $ do+ bench "zero" (Argo.Number $ Argo.Decimal 0 0) encode++ group "String" $ do+ let f n = Argo.String . Text.replicate n $ Text.singleton 'a'+ bench "empty" (f 0) encode+ bench "1 character" (f 1) encode+ bench "10 characters" (f 10) encode+ bench "100 characters" (f 100) encode+ bench "1000 characters" (f 1000) encode+ bench "10000 characters" (f 10000) encode++ group "Array" $ do+ let f n = Argo.Array $ replicate n Argo.Null+ bench "empty" (f 0) encode+ bench "1 element" (f 1) encode+ bench "10 elements" (f 10) encode+ bench "100 elements" (f 100) encode+ bench "1000 elements" (f 1000) encode+ bench "10000 elements" (f 10000) encode++ group "Object" $ do+ let+ f n = Argo.Object . replicate n $ Argo.Member+ (Argo.Name Text.empty)+ Argo.Null+ bench "empty" (f 0) encode+ bench "1 element" (f 1) encode+ bench "10 elements" (f 10) encode+ bench "100 elements" (f 100) encode+ bench "1000 elements" (f 1000) encode+ bench "10000 elements" (f 10000) encode++ group "decode" $ do++ group "Null" $ do+ bench "null" (utf8 "null") decode++ group "Boolean" $ do+ bench "false" (utf8 "false") decode+ bench "true" (utf8 "true") decode++ group "Number" $ do+ bench "zero" (utf8 "0") decode++ group "String" $ do+ let f n = utf8 . wrap "\"" "\"" $ replicate n 'a'+ bench "empty" (f 0) decode+ bench "one byte" (utf8 "\"$\"") decode+ bench "two bytes" (utf8 "\"\xc2\xa2\"") decode+ bench "three bytes" (utf8 "\"\xe2\x82\xac\"") decode+ bench "four bytes" (utf8 "\"\xf0\x90\x8d\x88\"") decode+ bench "short escape" (utf8 "\"\\n\"") decode+ bench "long escape" (utf8 "\"\\u001f\"") decode+ bench "surrogate pair" (utf8 "\"\\ud834\\udd1e\"") decode+ bench "1 element" (f 1) decode+ bench "10 elements" (f 10) decode+ bench "100 elements" (f 100) decode+ bench "1000 elements" (f 1000) decode+ bench "10000 elements" (f 10000) decode++ group "Array" $ do+ let+ f n = utf8 . wrap "[" "]" . List.intercalate "," $ replicate+ n+ "null"+ bench "empty" (f 0) decode+ bench "1 element" (f 1) decode+ bench "10 elements" (f 10) decode+ bench "100 elements" (f 100) decode+ bench "1000 elements" (f 1000) decode+ bench "10000 elements" (f 10000) decode++ group "Object" $ do+ let+ f n = utf8 . wrap "{" "}" . List.intercalate "," $ replicate+ n+ "\"\":null"+ bench "empty" (f 0) decode+ bench "1 element" (f 1) decode+ bench "10 elements" (f 10) decode+ bench "100 elements" (f 100) decode+ bench "1000 elements" (f 1000) decode+ bench "10000 elements" (f 10000) decode++bench+ :: (DeepSeq.NFData a, DeepSeq.NFData b)+ => String+ -> a+ -> (a -> IO b)+ -> Writer.Writer [Bench.Benchmark] ()+bench name x f =+ Writer.tell+ . pure+ . Tasty.withResource (Exception.evaluate $ DeepSeq.force x) discard+ $ Bench.bench name+ . Bench.nfIO+ . (>>= f)++decode :: ByteString.ByteString -> IO Argo.Value+decode = either fail pure . Argo.decode++discard :: Applicative f => a -> f ()+discard = const $ pure ()++encode :: Argo.Value -> IO LazyByteString.ByteString+encode = pure . Builder.toLazyByteString . Argo.encode++group+ :: String+ -> Writer.Writer [Bench.Benchmark] a+ -> Writer.Writer [Bench.Benchmark] ()+group x = Writer.tell . pure . Bench.bgroup x . Writer.execWriter++utf8 :: String -> ByteString.ByteString+utf8 = Encoding.encodeUtf8 . Text.pack++wrap :: Monoid a => a -> a -> a -> a+wrap l r x = l <> x <> r
source/library/Argo.hs view
@@ -13,8 +13,6 @@ , Encode.encodeWith , Indent.Indent(Spaces, Tab) , Decode.decode- , FromValue.fromValue- , ToValue.toValue , HasCodec.HasCodec(codec) , QuasiQuoter.value , QuasiQuoter.pointer@@ -28,9 +26,7 @@ , Schema.Schema ) where -import qualified Argo.Class.FromValue as FromValue import qualified Argo.Class.HasCodec as HasCodec-import qualified Argo.Class.ToValue as ToValue import qualified Argo.Decode as Decode import qualified Argo.Encode as Encode import qualified Argo.Json.Member as Member
− source/library/Argo/Class/FromValue.hs
@@ -1,8 +0,0 @@-module Argo.Class.FromValue where--import qualified Argo.Class.HasCodec as HasCodec-import qualified Argo.Codec.Value as Codec-import qualified Argo.Json.Value as Value--fromValue :: HasCodec.HasCodec a => Value.Value -> Either String a-fromValue = Codec.decodeWith HasCodec.codec
source/library/Argo/Class/HasCodec.hs view
@@ -34,577 +34,956 @@ import qualified Data.Functor.Identity as Identity import qualified Data.Int as Int import qualified Data.List.NonEmpty as NonEmpty-import qualified Data.Word as Word-import qualified Numeric.Natural as Natural--class HasCodec a where- codec :: Codec.Value a--instance HasCodec Value.Value where- codec = Codec.Codec- { Codec.decode = Trans.ask- , Codec.encode = Codec.tap $ Trans.lift . Trans.put- , Codec.schema = Schema.true- }--instance HasCodec Null.Null where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "null"- )- ]- in- basicCodec "Null" schema Value.Null $ \value -> case value of- Value.Null null_ -> Just null_- _ -> Nothing--instance HasCodec Boolean.Boolean where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "boolean"- )- ]- in- basicCodec "Boolean" schema Value.Boolean $ \value -> case value of- Value.Boolean boolean -> Just boolean- _ -> Nothing--instance HasCodec Number.Number where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "number"- )- ]- in- basicCodec "Number" schema Value.Number $ \value -> case value of- Value.Number number -> Just number- _ -> Nothing--instance HasCodec String.String where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "string"- )- ]- in- basicCodec "String" schema Value.String $ \value -> case value of- Value.String string -> Just string- _ -> Nothing--instance HasCodec a => HasCodec (Array.Array a) where- codec = Codec.Codec- { Codec.decode = do- array <- castValue "Array" $ \value -> case value of- Value.Array array -> Just array- _ -> Nothing- either (Trans.lift . Trans.throwE) (pure . Array.fromList)- . traverse (Codec.decodeWith codec)- $ Array.toList array- , Codec.encode =- Codec.tap- $ Trans.lift- . Trans.put- . Value.Array- . Array.fromList- . fmap (Codec.encodeWith codec)- . Array.toList- , Codec.schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "array"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "items"- , Schema.toValue $ Codec.schema (codec :: Codec.Value a)- )- ]- }--instance HasCodec a => HasCodec (Object.Object a) where- codec = Codec.Codec- { Codec.decode = do- object <- castValue "Object" $ \value -> case value of- Value.Object object -> Just object- _ -> Nothing- either (Trans.lift . Trans.throwE) (pure . Object.fromList)- . traverse- (\(Member.Member k v) ->- Member.Member k <$> Codec.decodeWith codec v- )- $ Object.toList object- , Codec.encode =- Codec.tap- $ Trans.lift- . Trans.put- . Value.Object- . Object.fromList- . fmap- (\(Member.Member k v) ->- Member.Member k $ Codec.encodeWith codec v- )- . Object.toList- , Codec.schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "object"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack- "additionalProperties"- , Schema.toValue $ Codec.schema (codec :: Codec.Value a)- )- ]- }--instance HasCodec a => HasCodec (Maybe a) where- codec =- Codec.mapMaybe (Just . Just) id codec- <|> Codec.map (const Nothing) (const $ Null.fromUnit ()) codec--instance (HasCodec a, HasCodec b) => HasCodec (Either a b) where- codec =- Codec.mapMaybe- (Just . Left)- (either Just $ const Nothing)- (Codec.tagged "Left" codec)- <|> Codec.mapMaybe- (Just . Right)- (either (const Nothing) Just)- (Codec.tagged "Right" codec)--instance HasCodec () where- codec = Codec.fromArrayCodec Permission.Forbid $ pure ()--instance (HasCodec a, HasCodec b) => HasCodec (a, b) where- codec =- Codec.fromArrayCodec Permission.Forbid- $ (,)- <$> Codec.project fst (Codec.element codec)- <*> Codec.project snd (Codec.element codec)--instance HasCodec Bool where- codec = Codec.map Boolean.toBool Boolean.fromBool codec--instance HasCodec Decimal.Decimal where- codec = Codec.map Number.toDecimal Number.fromDecimal codec--instance HasCodec Text.Text where- codec = Codec.map String.toText String.fromText codec--instance {-# OVERLAPPABLE #-} HasCodec a => HasCodec [a] where- codec = Codec.map Array.toList Array.fromList codec--instance HasCodec a => HasCodec (Map.Map Name.Name a) where- codec = Codec.map- (Map.fromList . fmap Member.toTuple . Object.toList)- (Object.fromList . fmap Member.fromTuple . Map.toList)- codec--instance HasCodec String where- codec = Codec.map Text.unpack Text.pack codec--instance HasCodec Char where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "string"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minLength"- , Value.Number . Number.fromDecimal $ Decimal.fromInteger 1- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maxLength"- , Value.Number . Number.fromDecimal $ Decimal.fromInteger 1- )- ]- in- Codec.mapMaybe- (\x -> case Text.uncons x of- Just (y, z) | Text.null z -> Just y- _ -> Nothing- )- (Just . Text.singleton)- codec { Codec.schema = schema }--instance HasCodec Text.LazyText where- codec = Codec.map Text.fromStrict Text.toStrict codec--instance HasCodec a => HasCodec (NonEmpty.NonEmpty a) where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "array"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "items"- , Schema.toValue $ Codec.schema (codec :: Codec.Value a)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minItems"- , Value.Number . Number.fromDecimal $ Decimal.fromInteger 1- )- ]- in- Codec.mapMaybe- NonEmpty.nonEmpty- (Just . NonEmpty.toList)- codec { Codec.schema = schema }--instance HasCodec Integer where- codec =- let- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- ]- in- Codec.mapMaybe- Decimal.toInteger- (Just . Decimal.fromInteger)- codec { Codec.schema = schema }--instance HasCodec Int where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Int- into = fromIntegral :: Int -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Int)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Int)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Int.Int8 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Int.Int8- into = fromIntegral :: Int.Int8 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Int.Int8)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Int.Int8)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Int.Int16 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Int.Int16- into = fromIntegral :: Int.Int16 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Int.Int16)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Int.Int16)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Int.Int32 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Int.Int32- into = fromIntegral :: Int.Int32 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Int.Int32)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Int.Int32)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Int.Int64 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Int.Int64- into = fromIntegral :: Int.Int64 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Int.Int64)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Int.Int64)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Natural.Natural where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Natural.Natural- into = fromIntegral :: Natural.Natural -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number . Number.fromDecimal $ Decimal.fromInteger 0- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Word where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Word- into = fromIntegral :: Word -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Word)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Word)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Word.Word8 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Word.Word8- into = fromIntegral :: Word.Word8 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Word.Word8)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Word.Word8)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Word.Word16 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Word.Word16- into = fromIntegral :: Word.Word16 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Word.Word16)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Word.Word16)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Word.Word32 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Word.Word32- into = fromIntegral :: Word.Word32 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Word.Word32)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Word.Word32)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Word.Word64 where- codec =- let- from = Bits.toIntegralSized :: Integer -> Maybe Word.Word64- into = fromIntegral :: Word.Word64 -> Integer- schema = Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "integer"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "minimum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (minBound :: Word.Word64)- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "maximum"- , Value.Number- . Number.fromDecimal- . Decimal.fromInteger- $ toInteger (maxBound :: Word.Word64)- )- ]- in Codec.mapMaybe from (Just . into) codec { Codec.schema = schema }--instance HasCodec Float where- codec =- Codec.mapMaybe (Just . Decimal.toRealFloat) Decimal.fromRealFloat codec--instance HasCodec Double where- codec =- Codec.mapMaybe (Just . Decimal.toRealFloat) Decimal.fromRealFloat codec--instance HasCodec Pointer.Pointer where- codec = Codec.mapMaybe- (either (const Nothing) Just- . Decoder.run Pointer.decode- . Text.encodeUtf8- )- (either (const Nothing) Just- . Text.decodeUtf8'- . ByteString.toStrict- . Builder.toLazyByteString- . Encoder.run Config.initial- . Pointer.encode- )- codec--instance HasCodec Schema.Schema where- codec = Codec.map Schema.fromValue Schema.toValue codec--basicCodec- :: String- -> Schema.Schema- -> (a -> Value.Value)- -> (Value.Value -> Maybe a)- -> Codec.Value a-basicCodec expected schema toValue fromValue = Codec.Codec- { Codec.decode = castValue expected fromValue- , Codec.encode = Codec.tap $ Trans.lift . Trans.put . toValue- , Codec.schema = schema+import qualified Data.Typeable as Typeable+import qualified Data.Word as Word+import qualified Numeric.Natural as Natural++class HasCodec a where+ codec :: Codec.Value a++instance HasCodec Value.Value where+ codec = basicCodec Schema.true id Just++instance HasCodec Null.Null where+ codec =+ let+ schema = Schema.fromValue . Value.Object $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack "type"+ , Value.String . String.fromText $ Text.pack "null"+ )+ ]+ in+ basicCodec schema Value.Null $ \value -> case value of+ Value.Null null_ -> Just null_+ _ -> Nothing++instance HasCodec Boolean.Boolean where+ codec =+ let+ schema = Schema.fromValue . Value.Object $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack "type"+ , Value.String . String.fromText $ Text.pack "boolean"+ )+ ]+ in+ basicCodec schema Value.Boolean $ \value -> case value of+ Value.Boolean boolean -> Just boolean+ _ -> Nothing++instance HasCodec Number.Number where+ codec =+ let+ schema = Schema.fromValue . Value.Object $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack "type"+ , Value.String . String.fromText $ Text.pack "number"+ )+ ]+ in+ basicCodec schema Value.Number $ \value -> case value of+ Value.Number number -> Just number+ _ -> Nothing++instance HasCodec String.String where+ codec =+ let+ schema = Schema.fromValue . Value.Object $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack "type"+ , Value.String . String.fromText $ Text.pack "string"+ )+ ]+ in+ basicCodec schema Value.String $ \value -> case value of+ Value.String string -> Just string+ _ -> Nothing++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Array.Array a) where+ codec = Codec.identified Codec.Codec+ { Codec.decode = do+ array <- castValue "Array" $ \value -> case value of+ Value.Array array -> Just array+ _ -> Nothing+ either (Trans.lift . Trans.throwE) (pure . Array.fromList)+ . traverse (Codec.decodeWith codec)+ $ Array.toList array+ , Codec.encode =+ Codec.tap+ $ Trans.lift+ . Trans.put+ . Value.Array+ . Array.fromList+ . fmap (Codec.encodeWith codec)+ . Array.toList+ , Codec.schema = do+ ref <- Codec.getRef (codec :: Codec.Value a)+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack "array"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "items"+ , Codec.ref ref+ )+ ]+ }++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Object.Object a) where+ codec = Codec.identified Codec.Codec+ { Codec.decode = do+ object <- castValue "Object" $ \value -> case value of+ Value.Object object -> Just object+ _ -> Nothing+ either (Trans.lift . Trans.throwE) (pure . Object.fromList)+ . traverse+ (\(Member.Member k v) ->+ Member.Member k <$> Codec.decodeWith codec v+ )+ $ Object.toList object+ , Codec.encode =+ Codec.tap+ $ Trans.lift+ . Trans.put+ . Value.Object+ . Object.fromList+ . fmap+ (\(Member.Member k v) ->+ Member.Member k $ Codec.encodeWith codec v+ )+ . Object.toList+ , Codec.schema = do+ ref <- Codec.getRef (codec :: Codec.Value a)+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack "object"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "additionalProperties"+ , Codec.ref ref+ )+ ]+ }++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Maybe a) where+ codec =+ Codec.identified+ $ Codec.mapMaybe (Just . Just) id codec+ <|> Codec.map (const Nothing) (const $ Null.fromUnit ()) codec++instance+ ( HasCodec a+ , HasCodec b+ , Typeable.Typeable a+ , Typeable.Typeable b+ ) => HasCodec (Either a b) where+ codec =+ Codec.identified+ $ Codec.mapMaybe+ (Just . Left)+ (either Just $ const Nothing)+ (Codec.tagged "Left" codec)+ <|> Codec.mapMaybe+ (Just . Right)+ (either (const Nothing) Just)+ (Codec.tagged "Right" codec)++instance HasCodec () where+ codec =+ Codec.identified . Codec.fromArrayCodec Permission.Forbid $ pure ()++instance+ ( HasCodec a+ , HasCodec b+ , Typeable.Typeable a+ , Typeable.Typeable b+ ) => HasCodec (a, b) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,)+ <$> Codec.project fst (Codec.element codec)+ <*> Codec.project snd (Codec.element codec)++instance+ ( HasCodec a+ , HasCodec b+ , HasCodec c+ , Typeable.Typeable a+ , Typeable.Typeable b+ , Typeable.Typeable c+ ) => HasCodec (a, b, c) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,,)+ <$> Codec.project (\(a, _, _) -> a) (Codec.element codec)+ <*> Codec.project (\(_, b, _) -> b) (Codec.element codec)+ <*> Codec.project (\(_, _, c) -> c) (Codec.element codec)++instance+ ( HasCodec a+ , HasCodec b+ , HasCodec c+ , HasCodec d+ , Typeable.Typeable a+ , Typeable.Typeable b+ , Typeable.Typeable c+ , Typeable.Typeable d+ ) => HasCodec (a, b, c, d) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,,,)+ <$> Codec.project (\(a, _, _, _) -> a) (Codec.element codec)+ <*> Codec.project (\(_, b, _, _) -> b) (Codec.element codec)+ <*> Codec.project (\(_, _, c, _) -> c) (Codec.element codec)+ <*> Codec.project (\(_, _, _, d) -> d) (Codec.element codec)++instance+ ( HasCodec a+ , HasCodec b+ , HasCodec c+ , HasCodec d+ , HasCodec e+ , Typeable.Typeable a+ , Typeable.Typeable b+ , Typeable.Typeable c+ , Typeable.Typeable d+ , Typeable.Typeable e+ ) => HasCodec (a, b, c, d, e) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,,,,)+ <$> Codec.project (\(a, _, _, _, _) -> a) (Codec.element codec)+ <*> Codec.project (\(_, b, _, _, _) -> b) (Codec.element codec)+ <*> Codec.project (\(_, _, c, _, _) -> c) (Codec.element codec)+ <*> Codec.project (\(_, _, _, d, _) -> d) (Codec.element codec)+ <*> Codec.project (\(_, _, _, _, e) -> e) (Codec.element codec)++instance+ ( HasCodec a+ , HasCodec b+ , HasCodec c+ , HasCodec d+ , HasCodec e+ , HasCodec f+ , Typeable.Typeable a+ , Typeable.Typeable b+ , Typeable.Typeable c+ , Typeable.Typeable d+ , Typeable.Typeable e+ , Typeable.Typeable f+ ) => HasCodec (a, b, c, d, e, f) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,,,,,)+ <$> Codec.project (\(a, _, _, _, _, _) -> a) (Codec.element codec)+ <*> Codec.project (\(_, b, _, _, _, _) -> b) (Codec.element codec)+ <*> Codec.project (\(_, _, c, _, _, _) -> c) (Codec.element codec)+ <*> Codec.project (\(_, _, _, d, _, _) -> d) (Codec.element codec)+ <*> Codec.project (\(_, _, _, _, e, _) -> e) (Codec.element codec)+ <*> Codec.project (\(_, _, _, _, _, f) -> f) (Codec.element codec)++instance+ ( HasCodec a+ , HasCodec b+ , HasCodec c+ , HasCodec d+ , HasCodec e+ , HasCodec f+ , HasCodec g+ , Typeable.Typeable a+ , Typeable.Typeable b+ , Typeable.Typeable c+ , Typeable.Typeable d+ , Typeable.Typeable e+ , Typeable.Typeable f+ , Typeable.Typeable g+ ) => HasCodec (a, b, c, d, e, f, g) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,,,,,,)+ <$> Codec.project+ (\(a, _, _, _, _, _, _) -> a)+ (Codec.element codec)+ <*> Codec.project+ (\(_, b, _, _, _, _, _) -> b)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, c, _, _, _, _) -> c)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, d, _, _, _) -> d)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, e, _, _) -> e)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, _, f, _) -> f)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, _, _, g) -> g)+ (Codec.element codec)++instance+ ( HasCodec a+ , HasCodec b+ , HasCodec c+ , HasCodec d+ , HasCodec e+ , HasCodec f+ , HasCodec g+ , HasCodec h+ , Typeable.Typeable a+ , Typeable.Typeable b+ , Typeable.Typeable c+ , Typeable.Typeable d+ , Typeable.Typeable e+ , Typeable.Typeable f+ , Typeable.Typeable g+ , Typeable.Typeable h+ ) => HasCodec (a, b, c, d, e, f, g, h) where+ codec =+ Codec.identified+ . Codec.fromArrayCodec Permission.Forbid+ $ (,,,,,,,)+ <$> Codec.project+ (\(a, _, _, _, _, _, _, _) -> a)+ (Codec.element codec)+ <*> Codec.project+ (\(_, b, _, _, _, _, _, _) -> b)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, c, _, _, _, _, _) -> c)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, d, _, _, _, _) -> d)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, e, _, _, _) -> e)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, _, f, _, _) -> f)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, _, _, g, _) -> g)+ (Codec.element codec)+ <*> Codec.project+ (\(_, _, _, _, _, _, _, h) -> h)+ (Codec.element codec)++instance HasCodec Bool where+ codec = Codec.identified $ Codec.map Boolean.toBool Boolean.fromBool codec++instance HasCodec Decimal.Decimal where+ codec =+ Codec.identified $ Codec.map Number.toDecimal Number.fromDecimal codec++instance HasCodec Text.Text where+ codec = Codec.identified $ Codec.map String.toText String.fromText codec++instance {-# OVERLAPPABLE #-} (HasCodec a, Typeable.Typeable a) => HasCodec [a] where+ codec = Codec.identified $ Codec.map Array.toList Array.fromList codec++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Map.Map Name.Name a) where+ codec = Codec.identified $ Codec.map+ (Map.fromList . fmap Member.toTuple . Object.toList)+ (Object.fromList . fmap Member.fromTuple . Map.toList)+ codec++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Map.Map String.String a) where+ codec = Codec.identified $ Codec.map+ (Map.mapKeys Name.toString)+ (Map.mapKeys Name.fromString)+ codec++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Map.Map Text.Text a) where+ codec = Codec.identified $ Codec.map+ (Map.mapKeys String.toText)+ (Map.mapKeys String.fromText)+ codec++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Map.Map Text.LazyText a) where+ codec = Codec.identified $ Codec.map+ (Map.mapKeys Text.fromStrict)+ (Map.mapKeys Text.toStrict)+ codec++instance (HasCodec a, Typeable.Typeable a) => HasCodec (Map.Map String a) where+ codec = Codec.identified+ $ Codec.map (Map.mapKeys Text.unpack) (Map.mapKeys Text.pack) codec++instance HasCodec String where+ codec = Codec.identified $ Codec.map Text.unpack Text.pack codec++instance HasCodec Char where+ codec =+ let+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "string"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minLength"+ , Value.Number+ . Number.fromDecimal+ $ Decimal.fromInteger 1+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maxLength"+ , Value.Number+ . Number.fromDecimal+ $ Decimal.fromInteger 1+ )+ ]+ in+ Codec.identified $ Codec.mapMaybe+ (\x -> case Text.uncons x of+ Just (y, z) | Text.null z -> Just y+ _ -> Nothing+ )+ (Just . Text.singleton)+ codec { Codec.schema = pure schema }++instance HasCodec Text.LazyText where+ codec = Codec.identified $ Codec.map Text.fromStrict Text.toStrict codec++instance (HasCodec a, Typeable.Typeable a) => HasCodec (NonEmpty.NonEmpty a) where+ codec =+ let+ schema = do+ (_, itemSchema) <- Codec.schema (codec :: Codec.Value a)+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "array"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "items"+ , Schema.toValue itemSchema+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minItems"+ , Value.Number+ . Number.fromDecimal+ $ Decimal.fromInteger 1+ )+ ]+ in+ Codec.identified $ Codec.mapMaybe+ NonEmpty.nonEmpty+ (Just . NonEmpty.toList)+ codec { Codec.schema = schema }++instance HasCodec Integer where+ codec =+ let+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ ]+ in+ Codec.identified $ Codec.mapMaybe+ Decimal.toInteger+ (Just . Decimal.fromInteger)+ codec { Codec.schema = pure schema }++instance HasCodec Int where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Int+ into = fromIntegral :: Int -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Int)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Int)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Int.Int8 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Int.Int8+ into = fromIntegral :: Int.Int8 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Int.Int8)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Int.Int8)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Int.Int16 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Int.Int16+ into = fromIntegral :: Int.Int16 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Int.Int16)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Int.Int16)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Int.Int32 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Int.Int32+ into = fromIntegral :: Int.Int32 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Int.Int32)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Int.Int32)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Int.Int64 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Int.Int64+ into = fromIntegral :: Int.Int64 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Int.Int64)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Int.Int64)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Natural.Natural where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Natural.Natural+ into = fromIntegral :: Natural.Natural -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ $ Decimal.fromInteger 0+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Word where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Word+ into = fromIntegral :: Word -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Word)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Word)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Word.Word8 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Word.Word8+ into = fromIntegral :: Word.Word8 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Word.Word8)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Word.Word8)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Word.Word16 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Word.Word16+ into = fromIntegral :: Word.Word16 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Word.Word16)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Word.Word16)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Word.Word32 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Word.Word32+ into = fromIntegral :: Word.Word32 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Word.Word32)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Word.Word32)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Word.Word64 where+ codec =+ let+ from = Bits.toIntegralSized :: Integer -> Maybe Word.Word64+ into = fromIntegral :: Word.Word64 -> Integer+ schema =+ Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "integer"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "minimum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (minBound :: Word.Word64)+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "maximum"+ , Value.Number+ . Number.fromDecimal+ . Decimal.fromInteger+ $ toInteger (maxBound :: Word.Word64)+ )+ ]+ in Codec.identified $ Codec.mapMaybe+ from+ (Just . into)+ codec { Codec.schema = pure schema }++instance HasCodec Float where+ codec = Codec.identified $ Codec.mapMaybe+ (Just . Decimal.toRealFloat)+ Decimal.fromRealFloat+ codec++instance HasCodec Double where+ codec = Codec.identified $ Codec.mapMaybe+ (Just . Decimal.toRealFloat)+ Decimal.fromRealFloat+ codec++instance HasCodec Pointer.Pointer where+ codec = Codec.identified $ Codec.mapMaybe+ (either (const Nothing) Just+ . Decoder.run Pointer.decode+ . Text.encodeUtf8+ )+ (either (const Nothing) Just+ . Text.decodeUtf8'+ . ByteString.toStrict+ . Builder.toLazyByteString+ . Encoder.run Config.initial+ . Pointer.encode+ )+ codec++instance HasCodec Schema.Schema where+ codec = Codec.identified $ Codec.map Schema.fromValue Schema.toValue codec++basicCodec+ :: forall a+ . Typeable.Typeable a+ => Schema.Schema+ -> (a -> Value.Value)+ -> (Value.Value -> Maybe a)+ -> Codec.Value a+basicCodec schema toValue fromValue = Codec.identified Codec.Codec+ { Codec.decode = castValue+ (show $ Typeable.typeRep (Typeable.Proxy :: Typeable.Proxy a))+ fromValue+ , Codec.encode = Codec.tap $ Trans.lift . Trans.put . toValue+ , Codec.schema = pure $ Schema.unidentified schema } castValue
− source/library/Argo/Class/ToValue.hs
@@ -1,8 +0,0 @@-module Argo.Class.ToValue where--import qualified Argo.Class.HasCodec as HasCodec-import qualified Argo.Codec.Value as Codec-import qualified Argo.Json.Value as Value--toValue :: HasCodec.HasCodec a => a -> Value.Value-toValue = Codec.encodeWith HasCodec.codec
source/library/Argo/Codec/Array.hs view
@@ -10,36 +10,57 @@ import qualified Argo.Json.Object as Object import qualified Argo.Json.String as String import qualified Argo.Json.Value as Value+import qualified Argo.Schema.Identifier as Identifier import qualified Argo.Schema.Schema as Schema import qualified Argo.Type.Permission as Permission+import qualified Argo.Vendor.Map as Map import qualified Argo.Vendor.Text as Text import qualified Argo.Vendor.Transformers as Trans+import qualified Data.Functor.Identity as Identity -type Array a = Codec.List [Schema.Schema] Value.Value a+type Array a+ = Codec.List+ ( Trans.AccumT+ (Map.Map Identifier.Identifier Schema.Schema)+ Identity.Identity+ [(Maybe Identifier.Identifier, Schema.Schema)]+ )+ Value.Value+ a fromArrayCodec :: Permission.Permission -> Array a -> Codec.Value a fromArrayCodec = Codec.fromListCodec- (\permission schemas ->- Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "array"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "items"- , Value.Array . Array.fromList $ fmap- Schema.toValue- schemas- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack- "additionalItems"- , Value.Boolean . Boolean.fromBool $ case permission of- Permission.Allow -> True- Permission.Forbid -> False- )- ]+ (\permission schemasM -> do+ schemas <- schemasM+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "array"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "items"+ , Value.Array . Array.fromList $ fmap+ (Schema.toValue . snd)+ schemas+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "additionalItems"+ , Value.Boolean+ . Boolean.fromBool+ $ case permission of+ Permission.Allow -> True+ Permission.Forbid -> False+ )+ ] ) $ Codec.map Array.toList Array.fromList Codec.arrayCodec @@ -57,5 +78,10 @@ , Codec.encode = \x -> do Trans.tell [Codec.encodeWith c x] pure x- , Codec.schema = [Codec.schema c]+ , Codec.schema =+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Codec.ref+ <$> Codec.getRef c }
source/library/Argo/Codec/Codec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE FlexibleInstances #-}+ module Argo.Codec.Codec where import Control.Applicative ((<|>))@@ -17,29 +19,38 @@ , schema = schema c } -instance (Applicative r, Applicative w, Monoid s) => Applicative (Codec r w s i) where- pure x =- Codec { decode = pure x, encode = const $ pure x, schema = mempty }+instance+ ( Applicative r+ , Applicative w+ , Applicative s+ , Monoid a+ ) => Applicative (Codec r w (s a) i) where+ pure x = Codec+ { decode = pure x+ , encode = const $ pure x+ , schema = pure mempty+ } cf <*> cx = Codec { decode = decode cf <*> decode cx , encode = \i -> encode cf i <*> encode cx i- , schema = schema cf <> schema cx+ , schema = (<>) <$> schema cf <*> schema cx } instance ( Applicative.Alternative r , Applicative.Alternative w- , Monoid s- ) => Applicative.Alternative (Codec r w s i) where+ , Applicative s+ , Monoid a+ ) => Applicative.Alternative (Codec r w (s a) i) where empty = Codec { decode = Applicative.empty , encode = const Applicative.empty- , schema = mempty+ , schema = pure mempty } cx <|> cy = Codec { decode = decode cx <|> decode cy , encode = \i -> encode cx i <|> encode cy i- , schema = schema cx <> schema cy+ , schema = (<>) <$> schema cx <*> schema cy } map
source/library/Argo/Codec/List.hs view
@@ -2,8 +2,10 @@ import qualified Argo.Codec.Codec as Codec import qualified Argo.Codec.Value as Codec+import qualified Argo.Schema.Identifier as Identifier import qualified Argo.Schema.Schema as Schema import qualified Argo.Type.Permission as Permission+import qualified Argo.Vendor.Map as Map import qualified Argo.Vendor.Transformers as Trans import qualified Control.Monad as Monad import qualified Data.Functor.Identity as Identity@@ -17,7 +19,13 @@ a fromListCodec- :: (Permission.Permission -> s -> Schema.Schema)+ :: ( Permission.Permission+ -> s+ -> Trans.AccumT+ (Map.Map Identifier.Identifier Schema.Schema)+ Identity.Identity+ (Maybe Identifier.Identifier, Schema.Schema)+ ) -> Codec.Value [e] -> Permission.Permission -> List s e a
source/library/Argo/Codec/Object.hs view
@@ -7,59 +7,80 @@ import qualified Argo.Json.Boolean as Boolean import qualified Argo.Json.Member as Member import qualified Argo.Json.Name as Name+import qualified Argo.Json.Null as Null import qualified Argo.Json.Object as Object import qualified Argo.Json.String as String import qualified Argo.Json.Value as Value+import qualified Argo.Schema.Identifier as Identifier import qualified Argo.Schema.Schema as Schema import qualified Argo.Type.Permission as Permission+import qualified Argo.Vendor.Map as Map import qualified Argo.Vendor.Text as Text import qualified Argo.Vendor.Transformers as Trans import qualified Control.Monad as Monad+import qualified Data.Functor.Identity as Identity import qualified Data.List as List import qualified Data.Maybe as Maybe type Object a = Codec.List- [(Name.Name, Bool, Schema.Schema)]+ ( Trans.AccumT+ (Map.Map Identifier.Identifier Schema.Schema)+ Identity.Identity+ [ ( (Name.Name, Bool)+ , (Maybe Identifier.Identifier, Schema.Schema)+ )+ ]+ ) (Member.Member Value.Value) a fromObjectCodec :: Permission.Permission -> Object a -> Codec.Value a fromObjectCodec = Codec.fromListCodec- (\permission schemas ->- Schema.fromValue . Value.Object $ Object.fromList- [ Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack "type"- , Value.String . String.fromText $ Text.pack "object"- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack- "properties"- , Value.Object . Object.fromList $ fmap- (\(k, _, s) ->- Member.fromTuple (k, Schema.toValue s)- )- schemas- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack- "required"- , Value.Array . Array.fromList $ Maybe.mapMaybe- (\(k, r, _) -> if r- then Just . Value.String $ Name.toString k- else Nothing- )- schemas- )- , Member.fromTuple- ( Name.fromString . String.fromText $ Text.pack- "additionalProperties"- , Value.Boolean . Boolean.fromBool $ case permission of- Permission.Allow -> True- Permission.Forbid -> False- )- ]+ (\permission schemasM -> do+ schemas <- schemasM+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "type"+ , Value.String . String.fromText $ Text.pack+ "object"+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "properties"+ , Value.Object . Object.fromList $ fmap+ (\((k, _), (_, s)) ->+ Member.fromTuple (k, Schema.toValue s)+ )+ schemas+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "required"+ , Value.Array . Array.fromList $ Maybe.mapMaybe+ (\((k, r), _) -> if r+ then Just . Value.String $ Name.toString+ k+ else Nothing+ )+ schemas+ )+ , Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack+ "additionalProperties"+ , Value.Boolean+ . Boolean.fromBool+ $ case permission of+ Permission.Allow -> True+ Permission.Forbid -> False+ )+ ] ) $ Codec.map Object.toList Object.fromList Codec.objectCodec @@ -77,7 +98,13 @@ , Codec.encode = \x -> do Monad.void . Codec.encode (optional k c) $ Just x pure x- , Codec.schema = [(k, True, Codec.schema c)]+ , Codec.schema =+ pure+ . (,) (k, True)+ . Schema.unidentified+ . Schema.fromValue+ . Codec.ref+ <$> Codec.getRef c } optional :: Name.Name -> Codec.Value a -> Object (Maybe a)@@ -86,7 +113,9 @@ xs <- Trans.get case List.partition (\(Member.Member j _) -> j == k) xs of (Member.Member _ x : _, ys) -> case Codec.decodeWith c x of- Left y -> Trans.lift $ Trans.throwE y+ Left y -> if x == Value.Null (Null.fromUnit ())+ then pure Nothing+ else Trans.lift $ Trans.throwE y Right y -> do Trans.put ys pure $ Just y@@ -96,7 +125,13 @@ Nothing -> pure () Just y -> Trans.tell [Member.Member k $ Codec.encodeWith c y] pure x- , Codec.schema = [(k, False, Codec.schema c)]+ , Codec.schema =+ pure+ . (,) (k, False)+ . Schema.unidentified+ . Schema.fromValue+ . Codec.ref+ <$> Codec.getRef c } tagged :: String -> Codec.Value a -> Codec.Value a
source/library/Argo/Codec/Value.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE ScopedTypeVariables #-}+ module Argo.Codec.Value where import qualified Argo.Codec.Codec as Codec@@ -8,11 +10,14 @@ import qualified Argo.Json.Object as Object import qualified Argo.Json.String as String import qualified Argo.Json.Value as Value+import qualified Argo.Schema.Identifier as Identifier import qualified Argo.Schema.Schema as Schema+import qualified Argo.Vendor.Map as Map import qualified Argo.Vendor.Text as Text import qualified Argo.Vendor.Transformers as Trans import qualified Control.Monad as Monad import qualified Data.Functor.Identity as Identity+import qualified Data.Typeable as Typeable decodeWith :: Value a -> Value.Value -> Either String a decodeWith c =@@ -30,7 +35,11 @@ = Codec.Codec (Trans.ReaderT Value.Value (Trans.ExceptT String Identity.Identity)) (Trans.MaybeT (Trans.StateT Value.Value Identity.Identity))- Schema.Schema+ ( Trans.AccumT+ (Map.Map Identifier.Identifier Schema.Schema)+ Identity.Identity+ (Maybe Identifier.Identifier, Schema.Schema)+ ) a a @@ -45,7 +54,7 @@ , Codec.encode = \x -> do Trans.lift . Trans.put $ Value.Array x pure x- , Codec.schema = Schema.false+ , Codec.schema = pure $ Schema.unidentified Schema.false } objectCodec :: Value (Object.Object Value.Value)@@ -62,7 +71,7 @@ , Codec.encode = \x -> do Trans.lift . Trans.put $ Value.Object x pure x- , Codec.schema = Schema.false+ , Codec.schema = pure $ Schema.unidentified Schema.false } literalCodec :: Value.Value -> Value ()@@ -77,8 +86,56 @@ <> " but got " <> show actual , Codec.encode = const . Trans.lift $ Trans.put expected- , Codec.schema = Schema.fromValue . Value.Object $ Object.fromList+ , Codec.schema =+ pure+ . Schema.unidentified+ . Schema.fromValue+ . Value.Object+ $ Object.fromList+ [ Member.fromTuple+ ( Name.fromString . String.fromText $ Text.pack "const"+ , expected+ )+ ]+ }++identified :: forall a . Typeable.Typeable a => Value a -> Value a+identified c =+ let+ i = Identifier.fromText . Text.pack . show $ Typeable.typeRep+ (Typeable.Proxy :: Typeable.Proxy a)+ in c { Codec.schema = Schema.identified i . snd <$> Codec.schema c }++getRef+ :: Value a+ -> Trans.AccumT+ (Map.Map Identifier.Identifier Schema.Schema)+ Identity.Identity+ (Either Schema.Schema Identifier.Identifier)+getRef codec = do+ let+ (maybeIdentifier, schema) =+ fst . Identity.runIdentity $ Trans.runAccumT+ (Codec.schema codec)+ Map.empty+ case maybeIdentifier of+ Nothing -> pure $ Left schema+ Just identifier -> do+ schemas <- Trans.look+ Monad.unless (Map.member identifier schemas) $ do+ Trans.add $ Map.singleton identifier schema+ Monad.void $ Codec.schema codec+ pure $ Right identifier++ref :: Either Schema.Schema Identifier.Identifier -> Value.Value+ref e = case e of+ Left s -> Schema.toValue s+ Right i -> Value.Object $ Object.fromList [ Member.fromTuple- (Name.fromString . String.fromText $ Text.pack "const", expected)+ ( Name.fromString . String.fromText $ Text.pack "$ref"+ , Value.String+ . String.fromText+ . mappend (Text.pack "#/definitions/")+ $ Identifier.toText i+ ) ]- }
source/library/Argo/Decode.hs view
@@ -1,7 +1,7 @@ module Argo.Decode where -import qualified Argo.Class.FromValue as FromValue import qualified Argo.Class.HasCodec as HasCodec+import qualified Argo.Codec.Value as Codec import qualified Argo.Json.Value as Value import qualified Argo.Pointer.Pointer as Pointer import qualified Argo.Type.Decoder as Decoder@@ -10,7 +10,7 @@ decode :: HasCodec.HasCodec a => ByteString.ByteString -> Either String a decode x = do y <- Decoder.run (Decoder.spaces *> Value.decode) x- FromValue.fromValue y+ Codec.decodeWith HasCodec.codec y decodePointer :: ByteString.ByteString -> Either String Pointer.Pointer decodePointer = Decoder.run Pointer.decode
source/library/Argo/Encode.hs view
@@ -1,7 +1,7 @@ module Argo.Encode where import qualified Argo.Class.HasCodec as HasCodec-import qualified Argo.Class.ToValue as ToValue+import qualified Argo.Codec.Value as Codec import qualified Argo.Json.Value as Value import qualified Argo.Literal as Literal import qualified Argo.Pointer.Pointer as Pointer@@ -20,7 +20,7 @@ let c = Config.initial { Config.indent = i } in Encoder.run c $ do- Value.encode $ ToValue.toValue x+ Value.encode $ Codec.encodeWith HasCodec.codec x Monad.when (Config.hasIndent c) . Trans.lift . Trans.tell
+ source/library/Argo/Schema/Identifier.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveLift #-}++module Argo.Schema.Identifier where++import qualified Argo.Vendor.DeepSeq as DeepSeq+import qualified Argo.Vendor.TemplateHaskell as TH+import qualified Argo.Vendor.Text as Text+import qualified Data.String as String+import qualified GHC.Generics as Generics++newtype Identifier+ = Identifier Text.Text+ deriving (Eq, Generics.Generic, TH.Lift, DeepSeq.NFData, Ord, Show)++instance String.IsString Identifier where+ fromString = fromText . String.fromString++instance Semigroup Identifier where+ x <> y = fromText $ toText x <> toText y -- TODO: remove this++fromText :: Text.Text -> Identifier+fromText = Identifier++toText :: Identifier -> Text.Text+toText (Identifier x) = x
source/library/Argo/Schema/Schema.hs view
@@ -11,6 +11,7 @@ import qualified Argo.Json.Object as Object import qualified Argo.Json.String as String import qualified Argo.Json.Value as Value+import qualified Argo.Schema.Identifier as Identifier import qualified Argo.Vendor.DeepSeq as DeepSeq import qualified Argo.Vendor.TemplateHaskell as TH import qualified Argo.Vendor.Text as Text@@ -44,3 +45,10 @@ true :: Schema true = fromValue . Value.Boolean $ Boolean.fromBool True++unidentified :: Schema -> (Maybe Identifier.Identifier, Schema)+unidentified s = (Nothing, s)++identified+ :: Identifier.Identifier -> Schema -> (Maybe Identifier.Identifier, Schema)+identified i s = (Just i, s)
source/library/Argo/Vendor/Map.hs view
@@ -1,6 +1,10 @@ module Argo.Vendor.Map ( Map.Map+ , Map.empty , Map.fromList+ , Map.mapKeys+ , Map.member+ , Map.singleton , Map.toList ) where
source/library/Argo/Vendor/Transformers.hs view
@@ -1,26 +1,31 @@ module Argo.Vendor.Transformers- ( ExceptT.ExceptT- , MaybeT.MaybeT- , ReaderT.ReaderT- , StateT.StateT- , WriterT.WriterT- , ReaderT.ask- , StateT.get+ ( Accum.AccumT+ , Except.ExceptT+ , Maybe.MaybeT+ , Reader.ReaderT+ , State.StateT+ , Writer.WriterT+ , Accum.add+ , Reader.ask+ , State.get , Trans.lift- , ReaderT.local- , StateT.put- , ExceptT.runExceptT- , MaybeT.runMaybeT- , ReaderT.runReaderT- , StateT.runStateT- , WriterT.runWriterT- , WriterT.tell- , ExceptT.throwE+ , Reader.local+ , Accum.look+ , State.put+ , Accum.runAccumT+ , Except.runExceptT+ , Maybe.runMaybeT+ , Reader.runReaderT+ , State.runStateT+ , Writer.runWriterT+ , Writer.tell+ , Except.throwE ) where +import qualified Control.Monad.Trans.Accum as Accum import qualified Control.Monad.Trans.Class as Trans-import qualified Control.Monad.Trans.Except as ExceptT-import qualified Control.Monad.Trans.Maybe as MaybeT-import qualified Control.Monad.Trans.Reader as ReaderT-import qualified Control.Monad.Trans.State as StateT-import qualified Control.Monad.Trans.Writer as WriterT+import qualified Control.Monad.Trans.Except as Except+import qualified Control.Monad.Trans.Maybe as Maybe+import qualified Control.Monad.Trans.Reader as Reader+import qualified Control.Monad.Trans.State as State+import qualified Control.Monad.Trans.Writer as Writer
source/test-suite/Main.hs view
@@ -17,12 +17,15 @@ import qualified Argo.Json.Number as Number import qualified Argo.Json.Object as Object import qualified Argo.Json.String as String+import qualified Argo.Schema.Identifier as Identifier import qualified Argo.Schema.Schema as Schema import qualified Argo.Type.Decimal as Decimal import qualified Argo.Type.Permission as Permission+import qualified Control.Monad.Trans.Accum as Accum import qualified Data.ByteString as ByteString import qualified Data.ByteString.Builder as Builder import qualified Data.ByteString.Lazy as LazyByteString+import qualified Data.Functor.Identity as Identity import qualified Data.Int as Int import qualified Data.Map as Map import qualified Data.Text as Text@@ -362,121 +365,119 @@ , Tasty.testGroup "fromValue" [ Tasty.testCase "Value" $ do- Argo.fromValue Argo.Null @?= Right Argo.Null+ fromValue Argo.Null @?= Right Argo.Null , Tasty.testCase "Bool" $ do- Argo.fromValue (Argo.Boolean False) @?= Right False+ fromValue (Argo.Boolean False) @?= Right False , Tasty.testCase "Char" $ do- Argo.fromValue (Argo.String "a") @?= Right 'a'+ fromValue (Argo.String "a") @?= Right 'a' , Tasty.testCase "Int" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Int)+ fromValue (number 0 0) @?= Right (0 :: Int) , Tasty.testCase "Int8" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Int.Int8)+ fromValue (number 0 0) @?= Right (0 :: Int.Int8) , Tasty.testCase "Int16" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Int.Int16)+ fromValue (number 0 0) @?= Right (0 :: Int.Int16) , Tasty.testCase "Int32" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Int.Int32)+ fromValue (number 0 0) @?= Right (0 :: Int.Int32) , Tasty.testCase "Int64" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Int.Int64)+ fromValue (number 0 0) @?= Right (0 :: Int.Int64) , Tasty.testCase "Word" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Word)+ fromValue (number 0 0) @?= Right (0 :: Word) , Tasty.testCase "Word8" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Word.Word8)+ fromValue (number 0 0) @?= Right (0 :: Word.Word8) , Tasty.testCase "Word16" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Word.Word16)+ fromValue (number 0 0) @?= Right (0 :: Word.Word16) , Tasty.testCase "Word32" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Word.Word32)+ fromValue (number 0 0) @?= Right (0 :: Word.Word32) , Tasty.testCase "Word64" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Word.Word64)+ fromValue (number 0 0) @?= Right (0 :: Word.Word64) , Tasty.testCase "Integer" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Integer)+ fromValue (number 0 0) @?= Right (0 :: Integer) , Tasty.testCase "Float" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Float)+ fromValue (number 0 0) @?= Right (0 :: Float) , Tasty.testCase "Double" $ do- Argo.fromValue (number 0 0) @?= Right (0 :: Double)+ fromValue (number 0 0) @?= Right (0 :: Double) , Tasty.testCase "String" $ do- Argo.fromValue (Argo.String "") @?= Right ("" :: String)+ fromValue (Argo.String "") @?= Right ("" :: String) , Tasty.testCase "Text" $ do- Argo.fromValue (Argo.String "") @?= Right ("" :: Text.Text)+ fromValue (Argo.String "") @?= Right ("" :: Text.Text) , Tasty.testCase "LazyText" $ do- Argo.fromValue (Argo.String "") @?= Right ("" :: LazyText.Text)+ fromValue (Argo.String "") @?= Right ("" :: LazyText.Text) , Tasty.testCase "Maybe a" $ do- Argo.fromValue (Argo.Boolean False) @?= Right (Just False)+ fromValue (Argo.Boolean False) @?= Right (Just False) , Tasty.testCase "()" $ do- Argo.fromValue (Argo.Array []) @?= Right ()+ fromValue (Argo.Array []) @?= Right () , Tasty.testCase "(a, b)" $ do- Argo.fromValue (Argo.Array [Argo.Boolean False, Argo.String "a"])+ fromValue (Argo.Array [Argo.Boolean False, Argo.String "a"]) @?= Right (False, 'a') , Tasty.testCase "[a]" $ do- Argo.fromValue (Argo.Array []) @?= Right ([] :: [Bool])+ fromValue (Argo.Array []) @?= Right ([] :: [Bool]) , Tasty.testCase "NonEmpty a" $ do- Argo.fromValue (Argo.Array [Argo.Boolean False])- @?= Right (False :| [])+ fromValue (Argo.Array [Argo.Boolean False]) @?= Right (False :| []) , Tasty.testCase "Map Name a" $ do- Argo.fromValue+ fromValue (Argo.Object [Argo.Member (Argo.Name "a") $ Argo.Boolean False] ) @?= Right (Map.fromList [(Argo.Name "a", False)]) , Tasty.testCase "Pointer" $ do- Argo.fromValue (Argo.String "") @?= Right (Argo.Pointer [])+ fromValue (Argo.String "") @?= Right (Argo.Pointer []) ] , Tasty.testGroup "toValue" [ Tasty.testCase "Value" $ do- Argo.toValue Argo.Null @?= Argo.Null+ toValue Argo.Null @?= Argo.Null , Tasty.testCase "Bool" $ do- Argo.toValue False @?= Argo.Boolean False+ toValue False @?= Argo.Boolean False , Tasty.testCase "Char" $ do- Argo.toValue 'a' @?= Argo.String "a"+ toValue 'a' @?= Argo.String "a" , Tasty.testCase "Int" $ do- Argo.toValue (0 :: Int) @?= number 0 0+ toValue (0 :: Int) @?= number 0 0 , Tasty.testCase "Int8" $ do- Argo.toValue (0 :: Int.Int8) @?= number 0 0+ toValue (0 :: Int.Int8) @?= number 0 0 , Tasty.testCase "Int16" $ do- Argo.toValue (0 :: Int.Int16) @?= number 0 0+ toValue (0 :: Int.Int16) @?= number 0 0 , Tasty.testCase "Int32" $ do- Argo.toValue (0 :: Int.Int32) @?= number 0 0+ toValue (0 :: Int.Int32) @?= number 0 0 , Tasty.testCase "Int64" $ do- Argo.toValue (0 :: Int.Int64) @?= number 0 0+ toValue (0 :: Int.Int64) @?= number 0 0 , Tasty.testCase "Word" $ do- Argo.toValue (0 :: Word) @?= number 0 0+ toValue (0 :: Word) @?= number 0 0 , Tasty.testCase "Word8" $ do- Argo.toValue (0 :: Word.Word8) @?= number 0 0+ toValue (0 :: Word.Word8) @?= number 0 0 , Tasty.testCase "Word16" $ do- Argo.toValue (0 :: Word.Word16) @?= number 0 0+ toValue (0 :: Word.Word16) @?= number 0 0 , Tasty.testCase "Word32" $ do- Argo.toValue (0 :: Word.Word32) @?= number 0 0+ toValue (0 :: Word.Word32) @?= number 0 0 , Tasty.testCase "Word64" $ do- Argo.toValue (0 :: Word.Word64) @?= number 0 0+ toValue (0 :: Word.Word64) @?= number 0 0 , Tasty.testCase "Integer" $ do- Argo.toValue (0 :: Integer) @?= number 0 0+ toValue (0 :: Integer) @?= number 0 0 , Tasty.testCase "Float" $ do- Argo.toValue (0 :: Float) @?= number 0 0+ toValue (0 :: Float) @?= number 0 0 , Tasty.testCase "Double" $ do- Argo.toValue (0 :: Double) @?= number 0 0+ toValue (0 :: Double) @?= number 0 0 , Tasty.testCase "String" $ do- Argo.toValue ("" :: String) @?= Argo.String ""+ toValue ("" :: String) @?= Argo.String "" , Tasty.testCase "Text" $ do- Argo.toValue ("" :: Text.Text) @?= Argo.String ""+ toValue ("" :: Text.Text) @?= Argo.String "" , Tasty.testCase "LazyText" $ do- Argo.toValue ("" :: LazyText.Text) @?= Argo.String ""+ toValue ("" :: LazyText.Text) @?= Argo.String "" , Tasty.testCase "Maybe a" $ do- Argo.toValue (Just False) @?= Argo.Boolean False+ toValue (Just False) @?= Argo.Boolean False , Tasty.testCase "()" $ do- Argo.toValue () @?= Argo.Array []+ toValue () @?= Argo.Array [] , Tasty.testCase "(a, b)" $ do- Argo.toValue (False, 'a')+ toValue (False, 'a') @?= Argo.Array [Argo.Boolean False, Argo.String "a"] , Tasty.testCase "[a]" $ do- Argo.toValue ([] :: [Bool]) @?= Argo.Array []+ toValue ([] :: [Bool]) @?= Argo.Array [] , Tasty.testCase "NonEmpty a" $ do- Argo.toValue (False :| []) @?= Argo.Array [Argo.Boolean False]+ toValue (False :| []) @?= Argo.Array [Argo.Boolean False] , Tasty.testCase "Map Name a" $ do- Argo.toValue (Map.fromList [(Argo.Name "a", False)])- @?= Argo.Object- [Argo.Member (Argo.Name "a") $ Argo.Boolean False]+ toValue (Map.fromList [(Argo.Name "a", False)]) @?= Argo.Object+ [Argo.Member (Argo.Name "a") $ Argo.Boolean False] , Tasty.testCase "Pointer" $ do- Argo.toValue (Argo.Pointer []) @?= Argo.String ""+ toValue (Argo.Pointer []) @?= Argo.String "" ] , Tasty.testGroup "quasi quoter"@@ -511,72 +512,63 @@ === Right (x :: Argo.Value) , Tasty.testGroup "fromValue . toValue"- [ property "Value" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Argo.Value)- , property "Bool" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Bool)+ [ property "Value"+ $ \x -> fromValue (toValue x) === Right (x :: Argo.Value)+ , property "Bool"+ $ \x -> fromValue (toValue x) === Right (x :: Bool) , property "Char" $ \x ->- Argo.fromValue (Argo.toValue x)- === if '\xd800' <= x && x <= '\xdfff'- then Right '\xfffd'- else Right x- , property "Int" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Int)- , property "Int8" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Int.Int8)- , property "Int16" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Int.Int16)- , property "Int32" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Int.Int32)- , property "Int64" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Int.Int64)- , property "Word" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Word)- , property "Word8" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Word.Word8)+ fromValue (toValue x) === if '\xd800' <= x && x <= '\xdfff'+ then Right '\xfffd'+ else Right x+ , property "Int" $ \x -> fromValue (toValue x) === Right (x :: Int)+ , property "Int8"+ $ \x -> fromValue (toValue x) === Right (x :: Int.Int8)+ , property "Int16"+ $ \x -> fromValue (toValue x) === Right (x :: Int.Int16)+ , property "Int32"+ $ \x -> fromValue (toValue x) === Right (x :: Int.Int32)+ , property "Int64"+ $ \x -> fromValue (toValue x) === Right (x :: Int.Int64)+ , property "Word"+ $ \x -> fromValue (toValue x) === Right (x :: Word)+ , property "Word8"+ $ \x -> fromValue (toValue x) === Right (x :: Word.Word8) , property "Word16"- $ \x -> Argo.fromValue (Argo.toValue x)- === Right (x :: Word.Word16)- , property "Word32" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Word.Word32)+ $ \x -> fromValue (toValue x) === Right (x :: Word.Word16)+ , property "Word32"+ $ \x -> fromValue (toValue x) === Right (x :: Word.Word32) , property "Word64"- $ \x -> Argo.fromValue (Argo.toValue x)- === Right (x :: Word.Word64)- , property "Integer" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Integer)+ $ \x -> fromValue (toValue x) === Right (x :: Word.Word64)+ , property "Integer"+ $ \x -> fromValue (toValue x) === Right (x :: Integer) , property "Float" $ \x ->- Argo.fromValue (Argo.toValue x) === if isNaN x || isInfinite x+ fromValue (toValue x) === if isNaN x || isInfinite x then Left "expected Float but got Null (Null ())" else Right (x :: Float) , property "Double" $ \x ->- Argo.fromValue (Argo.toValue x) === if isNaN x || isInfinite x+ fromValue (toValue x) === if isNaN x || isInfinite x then Left "expected Double but got Null (Null ())" else Right (x :: Double)- , property "String"- $ \x -> Argo.fromValue (Argo.toValue x)- === Right (Text.unpack $ Text.pack x)- , property "Text" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Text.Text)- , property "LazyText"- $ \x -> Argo.fromValue (Argo.toValue x)- === Right (x :: LazyText.Text)- , property "Maybe a" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Maybe Bool)- , property "()"- $ \x -> Argo.fromValue (Argo.toValue x) === Right (x :: ())- , property "(a, b)"- $ \x -> Argo.fromValue (Argo.toValue x)- === Right (x :: (Bool, Int.Int8))+ , property "String" $ \x ->+ fromValue (toValue x) === Right (Text.unpack $ Text.pack x)+ , property "Text"+ $ \x -> fromValue (toValue x) === Right (x :: Text.Text)+ , property "LazyText" $ \x ->+ fromValue (toValue x) === Right (x :: LazyText.Text)+ , property "Maybe a"+ $ \x -> fromValue (toValue x) === Right (x :: Maybe Bool)+ , property "()" $ \x -> fromValue (toValue x) === Right (x :: ())+ , property "(a, b)" $ \x ->+ fromValue (toValue x) === Right (x :: (Bool, Int.Int8)) , property "[a]"- $ \x -> Argo.fromValue (Argo.toValue x) === Right (x :: [Bool])- , property "NonEmpty a"- $ \x -> Argo.fromValue (Argo.toValue x)- === Right (x :: NonEmpty Bool)+ $ \x -> fromValue (toValue x) === Right (x :: [Bool])+ , property "NonEmpty a" $ \x ->+ fromValue (toValue x) === Right (x :: NonEmpty Bool) , property "Map Name a"- $ \x -> Argo.fromValue (Argo.toValue x)+ $ \x -> fromValue (toValue x) === Right (x :: Map.Map Argo.Name Bool)- , property "Pointer" $ \x ->- Argo.fromValue (Argo.toValue x) === Right (x :: Argo.Pointer)+ , property "Pointer"+ $ \x -> fromValue (toValue x) === Right (x :: Argo.Pointer) ] ] , Tasty.testGroup@@ -745,231 +737,533 @@ , Tasty.testGroup "Schema" [ Tasty.testCase "value" $ do- let expected = [Argo.schema| true |]+ let expected = schemafy (Just "Value") [Argo.schema| true |] actual = Codec.schema (Argo.codec :: Codec.Value Argo.Value)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "null" $ do- let expected = [Argo.schema| { "type": "null" } |]+ let expected =+ schemafy (Just "Null") [Argo.schema| { "type": "null" } |] actual = Codec.schema (Argo.codec :: Codec.Value Null.Null)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "boolean" $ do- let expected = [Argo.schema| { "type": "boolean" } |]+ let expected = schemafy+ (Just "Boolean")+ [Argo.schema| { "type": "boolean" } |] actual = Codec.schema (Argo.codec :: Codec.Value Boolean.Boolean)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "number" $ do- let expected = [Argo.schema| { "type": "number" } |]+ let expected = schemafy+ (Just "Number")+ [Argo.schema| { "type": "number" } |] actual = Codec.schema (Argo.codec :: Codec.Value Number.Number)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "string" $ do- let expected = [Argo.schema| { "type": "string" } |]+ let expected = schemafy+ (Just "String")+ [Argo.schema| { "type": "string" } |] actual = Codec.schema (Argo.codec :: Codec.Value String.String)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "array boolean" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "array", "items": { "type": "boolean" } } |]+ let expected = schemafy+ (Just "Array Boolean")+ [Argo.schema| { "type": "array", "items": { "$ref": "#/definitions/Boolean" } } |] actual = Codec.schema (Argo.codec :: Codec.Value (Array.Array Boolean.Boolean) )- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "object boolean" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "object", "additionalProperties": { "type": "boolean" } } |]+ let expected = schemafy+ (Just "Object Boolean")+ [Argo.schema| { "type": "object", "additionalProperties": { "$ref": "#/definitions/Boolean" } } |] actual = Codec.schema (Argo.codec :: Codec.Value (Object.Object Boolean.Boolean) )- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "maybe boolean" $ do- let expected =- Schema.fromValue- [Argo.value| { "oneOf": [ { "type": "boolean" }, { "type": "null" } ] } |]+ let expected = schemafy+ (Just "Maybe Boolean")+ [Argo.schema| { "oneOf": [ { "type": "boolean" }, { "type": "null" } ] } |] actual = Codec.schema (Argo.codec :: Codec.Value (Maybe Boolean.Boolean))- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "either boolean number" $ do- let expected =- Schema.fromValue- [Argo.value| { "oneOf": [ { "type": "object", "properties": { "type": { "const": "Left" }, "value": { "type": "boolean" } }, "required": [ "type", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "const": "Right" }, "value": { "type": "number" } }, "required": [ "type", "value" ], "additionalProperties": false } ] } |]+ let expected = schemafy+ (Just "Either Boolean Number")+ [Argo.schema| { "oneOf": [ { "type": "object", "properties": { "type": { "const": "Left" }, "value": { "$ref": "#/definitions/Boolean" } }, "required": [ "type", "value" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "const": "Right" }, "value": { "$ref": "#/definitions/Number" } }, "required": [ "type", "value" ], "additionalProperties": false } ] } |] actual = Codec.schema (Argo.codec :: Codec.Value (Either Boolean.Boolean Number.Number) )- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "()" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "array", "items": [], "additionalItems": false } |]+ let expected = schemafy+ (Just "()")+ [Argo.schema| { "type": "array", "items": [], "additionalItems": false } |] actual = Codec.schema (Argo.codec :: Codec.Value ())- actual @?= expected- , Tasty.testCase "(boolean, number)" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "array", "items": [ { "type": "boolean" }, { "type": "number" } ], "additionalItems": false } |]- actual =- Codec.schema- (Argo.codec :: Codec.Value- (Boolean.Boolean, Number.Number)- )- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "2-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null)")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value (Argo.Value, Null.Null))+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "3-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null,Boolean)")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ , { "$ref": "#/definitions/Boolean" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ (Argo.Value, Null.Null, Boolean.Boolean)+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "4-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null,Boolean,Number)")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ , { "$ref": "#/definitions/Boolean" }+ , { "$ref": "#/definitions/Number" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ ( Argo.Value+ , Null.Null+ , Boolean.Boolean+ , Number.Number+ )+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "5-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null,Boolean,Number,Integer)")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ , { "$ref": "#/definitions/Boolean" }+ , { "$ref": "#/definitions/Number" }+ , { "$ref": "#/definitions/Integer" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ ( Argo.Value+ , Null.Null+ , Boolean.Boolean+ , Number.Number+ , Integer+ )+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "6-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null,Boolean,Number,Integer,String)")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ , { "$ref": "#/definitions/Boolean" }+ , { "$ref": "#/definitions/Number" }+ , { "$ref": "#/definitions/Integer" }+ , { "$ref": "#/definitions/String" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ ( Argo.Value+ , Null.Null+ , Boolean.Boolean+ , Number.Number+ , Integer+ , String.String+ )+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "7-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null,Boolean,Number,Integer,String,())")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ , { "$ref": "#/definitions/Boolean" }+ , { "$ref": "#/definitions/Number" }+ , { "$ref": "#/definitions/Integer" }+ , { "$ref": "#/definitions/String" }+ , { "$ref": "#/definitions/()" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ ( Argo.Value+ , Null.Null+ , Boolean.Boolean+ , Number.Number+ , Integer+ , String.String+ , ()+ )+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "8-tuple" $ do+ let expected = schemafy+ (Just "(Value,Null,Boolean,Number,Integer,String,(),Char)")+ [Argo.schema| { "type": "array", "items":+ [ { "$ref": "#/definitions/Value" }+ , { "$ref": "#/definitions/Null" }+ , { "$ref": "#/definitions/Boolean" }+ , { "$ref": "#/definitions/Number" }+ , { "$ref": "#/definitions/Integer" }+ , { "$ref": "#/definitions/String" }+ , { "$ref": "#/definitions/()" }+ , { "$ref": "#/definitions/Char" }+ ], "additionalItems": false } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ ( Argo.Value+ , Null.Null+ , Boolean.Boolean+ , Number.Number+ , Integer+ , String.String+ , ()+ , Char+ )+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "bool" $ do- let expected = [Argo.schema| { "type": "boolean" } |]+ let expected = schemafy+ (Just "Bool")+ [Argo.schema| { "type": "boolean" } |] actual = Codec.schema (Argo.codec :: Codec.Value Bool)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "decimal" $ do- let expected = [Argo.schema| { "type": "number" } |]+ let expected = schemafy+ (Just "Decimal")+ [Argo.schema| { "type": "number" } |] actual = Codec.schema (Argo.codec :: Codec.Value Decimal.Decimal)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "text" $ do- let expected = [Argo.schema| { "type": "string" } |]+ let expected = schemafy+ (Just "Text")+ [Argo.schema| { "type": "string" } |] actual = Codec.schema (Argo.codec :: Codec.Value Text.Text)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "list boolean" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "array", "items": { "type": "boolean" } } |]+ let expected = schemafy+ (Just "[Boolean]")+ [Argo.schema| { "type": "array", "items": { "$ref": "#/definitions/Boolean" } } |] actual = Codec.schema (Argo.codec :: Codec.Value [Boolean.Boolean])- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "map name boolean" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "object", "additionalProperties": { "type": "boolean" } } |]+ let expected = schemafy+ (Just "Map Name Boolean")+ [Argo.schema| { "type": "object", "additionalProperties": { "$ref": "#/definitions/Boolean" } } |] actual = Codec.schema (Argo.codec :: Codec.Value (Map.Map Name.Name Boolean.Boolean) )- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "map (argo) string boolean" $ do+ let expected = schemafy+ (Just "Map String Boolean")+ [Argo.schema| { "type": "object", "additionalProperties": { "$ref": "#/definitions/Boolean" } } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ (Map.Map String.String Boolean.Boolean)+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "map (strict) text boolean" $ do+ let expected = schemafy+ (Just "Map Text Boolean")+ [Argo.schema| { "type": "object", "additionalProperties": { "$ref": "#/definitions/Boolean" } } |]+ actual =+ Codec.schema+ (Argo.codec :: Codec.Value+ (Map.Map Text.Text Boolean.Boolean)+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "map (lazy) text boolean" $ do+ let expected = schemafy+ (Just "Map Text Boolean")+ [Argo.schema| { "type": "object", "additionalProperties": { "$ref": "#/definitions/Boolean" } } |]+ actual = Codec.schema+ (Argo.codec :: Codec.Value+ (Map.Map LazyText.Text Boolean.Boolean)+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "map (base) string boolean" $ do+ let expected = schemafy+ (Just "Map [Char] Boolean")+ [Argo.schema| { "type": "object", "additionalProperties": { "$ref": "#/definitions/Boolean" } } |]+ actual =+ Codec.schema+ (Argo.codec :: Codec.Value+ (Map.Map String Boolean.Boolean)+ )+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "string" $ do- let expected = [Argo.schema| { "type": "string" } |]+ let expected = schemafy+ (Just "[Char]")+ [Argo.schema| { "type": "string" } |] actual = Codec.schema (Argo.codec :: Codec.Value String)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "char" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "string", "minLength": 1, "maxLength": 1 } |]+ let expected = schemafy+ (Just "Char")+ [Argo.schema| { "type": "string", "minLength": 1, "maxLength": 1 } |] actual = Codec.schema (Argo.codec :: Codec.Value Char)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "lazy text" $ do- let expected = [Argo.schema| { "type": "string" } |]+ let expected = schemafy+ (Just "Text")+ [Argo.schema| { "type": "string" } |] actual = Codec.schema (Argo.codec :: Codec.Value LazyText.Text)- actual @?= expected- , Tasty.testCase "list boolean" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "array", "items": { "type": "boolean" }, "minItems": 1 } |]+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "non-empty boolean" $ do+ let expected = schemafy+ (Just "NonEmpty Boolean")+ [Argo.schema| { "type": "array", "items": { "type": "boolean" }, "minItems": 1 } |] actual = Codec.schema (Argo.codec :: Codec.Value (NonEmpty Boolean.Boolean))- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "integer" $ do- let expected = [Argo.schema| { "type": "integer" } |]+ let expected = schemafy+ (Just "Integer")+ [Argo.schema| { "type": "integer" } |] actual = Codec.schema (Argo.codec :: Codec.Value Integer)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "int" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": -9223372036854775808, "maximum": 9223372036854775807 } |]+ let expected = schemafy+ (Just "Int")+ [Argo.schema| { "type": "integer", "minimum": -9223372036854775808, "maximum": 9223372036854775807 } |] actual = Codec.schema (Argo.codec :: Codec.Value Int)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "int8" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": -128, "maximum": 127 } |]+ let expected = schemafy+ (Just "Int8")+ [Argo.schema| { "type": "integer", "minimum": -128, "maximum": 127 } |] actual = Codec.schema (Argo.codec :: Codec.Value Int.Int8)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "int16" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": -32768, "maximum": 32767 } |]+ let expected = schemafy+ (Just "Int16")+ [Argo.schema| { "type": "integer", "minimum": -32768, "maximum": 32767 } |] actual = Codec.schema (Argo.codec :: Codec.Value Int.Int16)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "int32" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": -2147483648, "maximum": 2147483647 } |]+ let expected = schemafy+ (Just "Int32")+ [Argo.schema| { "type": "integer", "minimum": -2147483648, "maximum": 2147483647 } |] actual = Codec.schema (Argo.codec :: Codec.Value Int.Int32)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "int64" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": -9223372036854775808, "maximum": 9223372036854775807 } |]+ let expected = schemafy+ (Just "Int64")+ [Argo.schema| { "type": "integer", "minimum": -9223372036854775808, "maximum": 9223372036854775807 } |] actual = Codec.schema (Argo.codec :: Codec.Value Int.Int64)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "natural" $ do- let expected = Schema.fromValue- [Argo.value| { "type": "integer", "minimum": 0 } |]+ let expected = schemafy+ (Just "Natural")+ [Argo.schema| { "type": "integer", "minimum": 0 } |] actual = Codec.schema (Argo.codec :: Codec.Value Natural.Natural)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "word" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": 0, "maximum": 18446744073709551615 } |]+ let expected = schemafy+ (Just "Word")+ [Argo.schema| { "type": "integer", "minimum": 0, "maximum": 18446744073709551615 } |] actual = Codec.schema (Argo.codec :: Codec.Value Word)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "word8" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": 0, "maximum": 255 } |]+ let expected = schemafy+ (Just "Word8")+ [Argo.schema| { "type": "integer", "minimum": 0, "maximum": 255 } |] actual = Codec.schema (Argo.codec :: Codec.Value Word.Word8)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "word16" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": 0, "maximum": 65535 } |]+ let expected = schemafy+ (Just "Word16")+ [Argo.schema| { "type": "integer", "minimum": 0, "maximum": 65535 } |] actual = Codec.schema (Argo.codec :: Codec.Value Word.Word16)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "word32" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": 0, "maximum": 4294967295 } |]+ let expected = schemafy+ (Just "Word32")+ [Argo.schema| { "type": "integer", "minimum": 0, "maximum": 4294967295 } |] actual = Codec.schema (Argo.codec :: Codec.Value Word.Word32)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "word64" $ do- let expected =- Schema.fromValue- [Argo.value| { "type": "integer", "minimum": 0, "maximum": 18446744073709551615 } |]+ let expected = schemafy+ (Just "Word64")+ [Argo.schema| { "type": "integer", "minimum": 0, "maximum": 18446744073709551615 } |] actual = Codec.schema (Argo.codec :: Codec.Value Word.Word64)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "float" $ do- let expected = [Argo.schema| { "type": "number" } |]+ let expected = schemafy+ (Just "Float")+ [Argo.schema| { "type": "number" } |] actual = Codec.schema (Argo.codec :: Codec.Value Float)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "double" $ do- let expected = [Argo.schema| { "type": "number" } |]+ let expected = schemafy+ (Just "Double")+ [Argo.schema| { "type": "number" } |] actual = Codec.schema (Argo.codec :: Codec.Value Double)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "pointer" $ do- let expected = [Argo.schema| { "type": "string" } |]+ let expected = schemafy+ (Just "Pointer")+ [Argo.schema| { "type": "string" } |] actual = Codec.schema (Argo.codec :: Codec.Value Argo.Pointer)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "schema" $ do- let expected = [Argo.schema| true |]+ let expected = schemafy (Just "Schema") [Argo.schema| true |] actual = Codec.schema (Argo.codec :: Codec.Value Schema.Schema)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty , Tasty.testCase "record" $ do- let expected- = [Argo.schema| { "type": "object", "properties": { "bool": { "type": "boolean" }, "text": { "type": "string" } }, "required": [ "bool" ], "additionalProperties": true } |]+ let expected = schemafy+ Nothing+ [Argo.schema| { "type": "object", "properties": { "bool": { "$ref": "#/definitions/Bool" }, "text": { "$ref": "#/definitions/Text" } }, "required": [ "bool" ], "additionalProperties": true } |] actual = Codec.schema (Argo.codec :: Codec.Value Record)- actual @?= expected+ Accum.evalAccumT actual mempty @?= Accum.evalAccumT expected mempty ]+ , Tasty.testGroup "T1"+ $ let codec = Argo.codec :: Codec.Value T1+ in+ [ Tasty.testCase "schema" $ do+ let expected = schemafy+ Nothing+ [Argo.schema|+ {+ "type": "object",+ "properties": {+ "t1c1f1": { "$ref": "#/definitions/Float" },+ "t1c1f2": { "$ref": "#/definitions/Maybe Float" },+ "t1c1f3": { "$ref": "#/definitions/Float" },+ "t1c1f4": { "$ref": "#/definitions/Maybe Float" }+ },+ "required": [ "t1c1f1", "t1c1f2" ],+ "additionalProperties": true+ }+ |]+ actual = Codec.schema codec+ Accum.evalAccumT actual mempty+ @?= Accum.evalAccumT expected mempty+ , Tasty.testCase "decode" $ do+ hush (Argo.decode "{ \"t1c1f1\": 0 }")+ @?= (Nothing :: Maybe T1)+ Argo.decode "{ \"t1c1f1\": 0, \"t1c1f2\": null }"+ @?= Right (T1C1 0 Nothing Nothing Nothing)+ Argo.decode "{ \"t1c1f1\": 1, \"t1c1f2\": 0 }"+ @?= Right (T1C1 1 (Just 0) Nothing Nothing)+ Argo.decode+ "{ \"t1c1f1\": 2, \"t1c1f2\": null, \"t1c1f3\": null }"+ @?= Right (T1C1 2 Nothing Nothing Nothing)+ Argo.decode+ "{ \"t1c1f1\": 3, \"t1c1f2\": null, \"t1c1f3\": 0 }"+ @?= Right (T1C1 3 Nothing (Just 0) Nothing)+ Argo.decode+ "{ \"t1c1f1\": 4, \"t1c1f2\": null, \"t1c1f4\": null }"+ @?= Right (T1C1 4 Nothing Nothing (Just Nothing))+ Argo.decode+ "{ \"t1c1f1\": 5, \"t1c1f2\": null, \"t1c1f4\": 0 }"+ @?= Right (T1C1 5 Nothing Nothing (Just (Just 0)))+ hush (Argo.decode "{ \"t1c1f1\": 6, \"t1c1f2\": [] }")+ @?= (Nothing :: Maybe T1)+ hush+ (Argo.decode+ "{ \"t1c1f1\": 7, \"t1c1f2\": null, \"t1c1f3\": [] }"+ )+ @?= (Nothing :: Maybe T1)+ hush+ (Argo.decode+ "{ \"t1c1f1\": 8, \"t1c1f2\": null, \"t1c1f4\": [] }"+ )+ @?= (Nothing :: Maybe T1)+ , Tasty.testCase "encode" $ do+ let+ encode =+ Builder.toLazyByteString . Argo.encode :: T1+ -> LazyByteString.ByteString+ encode (T1C1 0 Nothing Nothing Nothing)+ @?= "{\"t1c1f1\":0,\"t1c1f2\":null}"+ encode (T1C1 1 (Just 0) Nothing Nothing)+ @?= "{\"t1c1f1\":1,\"t1c1f2\":0}"+ encode (T1C1 2 Nothing (Just 0) Nothing)+ @?= "{\"t1c1f1\":2,\"t1c1f2\":null,\"t1c1f3\":0}"+ encode (T1C1 3 Nothing Nothing (Just Nothing))+ @?= "{\"t1c1f1\":3,\"t1c1f2\":null,\"t1c1f4\":null}"+ encode (T1C1 4 Nothing Nothing (Just (Just 0)))+ @?= "{\"t1c1f1\":4,\"t1c1f2\":null,\"t1c1f4\":0}"+ ]+ , Tasty.testCase "T2" $ do+ let schema = [Argo.schema|+ { "type": "object"+ , "properties": { "t2c1f1": { "$ref": "#/definitions/T2" } }+ , "required": []+ , "additionalProperties": true+ } |]+ expected = schemafy (Just "T2") schema+ actual = Codec.schema (Argo.codec :: Codec.Value T2)+ Accum.runAccum actual mempty+ @?= (Accum.evalAccum expected mempty, Map.singleton "T2" schema) ] +fromValue :: Argo.HasCodec a => Argo.Value -> Either String a+fromValue = Codec.decodeWith Argo.codec++toValue :: Argo.HasCodec a => a -> Argo.Value+toValue = Codec.encodeWith Argo.codec+ number :: Integer -> Integer -> Argo.Value number s = Argo.Number . Argo.Decimal s +newtype T2 = T2C1+ { t2c1f1 :: Maybe T2+ } deriving (Eq, Show)++instance Argo.HasCodec T2 where+ codec =+ Codec.identified+ . Codec.fromObjectCodec Permission.Allow+ $ T2C1+ <$> Codec.project t2c1f1 (Codec.optional "t2c1f1" Argo.codec)++data T1 = T1C1+ { t1c1f1 :: Float+ , t1c1f2 :: Maybe Float+ , t1c1f3 :: Maybe Float+ , t1c1f4 :: Maybe (Maybe Float)+ }+ deriving (Eq, Show)++instance Argo.HasCodec T1 where+ codec =+ Codec.fromObjectCodec Permission.Allow+ $ T1C1+ <$> Codec.project t1c1f1 (Codec.required "t1c1f1" Argo.codec)+ <*> Codec.project t1c1f2 (Codec.required "t1c1f2" Argo.codec)+ <*> Codec.project t1c1f3 (Codec.optional "t1c1f3" Argo.codec)+ <*> Codec.project t1c1f4 (Codec.optional "t1c1f4" Argo.codec)+ data Record = Record { recordBool :: Bool , recordText :: Maybe Text.Text@@ -1006,3 +1300,12 @@ hush :: Either String a -> Maybe a hush = either (const Nothing) Just++schemafy+ :: Maybe Identifier.Identifier+ -> Schema.Schema+ -> Accum.AccumT+ (Map.Map Identifier.Identifier Schema.Schema)+ Identity.Identity+ (Maybe Identifier.Identifier, Schema.Schema)+schemafy m = pure . maybe Schema.unidentified Schema.identified m