packages feed

autodocodec 0.0.1.1 → 0.1.0.0

raw patch · 4 files changed

+340/−102 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Autodocodec: disjointMatchChoiceCodec :: Codec context input output -> Codec context input' output -> (newInput -> Either input input') -> Codec context newInput output
+ Autodocodec: disjointMatchChoicesCodec :: [(input -> Maybe input, Codec context input output)] -> Codec context input output -> Codec context input output
+ Autodocodec: matchChoiceCodecAs :: Union -> Codec context input output -> Codec context input' output -> (newInput -> Either input input') -> Codec context newInput output
+ Autodocodec: matchChoicesCodecAs :: Union -> [(input -> Maybe input, Codec context input output)] -> Codec context input output -> Codec context input output
+ Autodocodec.Codec: disjointMatchChoiceCodec :: Codec context input output -> Codec context input' output -> (newInput -> Either input input') -> Codec context newInput output
+ Autodocodec.Codec: disjointMatchChoicesCodec :: [(input -> Maybe input, Codec context input output)] -> Codec context input output -> Codec context input output
+ Autodocodec.Codec: matchChoiceCodecAs :: Union -> Codec context input output -> Codec context input' output -> (newInput -> Either input input') -> Codec context newInput output
+ Autodocodec.Codec: matchChoicesCodecAs :: Union -> [(input -> Maybe input, Codec context input output)] -> Codec context input output -> Codec context input output
- Autodocodec: matchChoiceCodec :: Codec context input output -> Codec context input output -> (newInput -> Either input input) -> Codec context newInput output
+ Autodocodec: matchChoiceCodec :: Codec context input output -> Codec context input' output -> (newInput -> Either input input') -> Codec context newInput output
- Autodocodec.Codec: matchChoiceCodec :: Codec context input output -> Codec context input output -> (newInput -> Either input input) -> Codec context newInput output
+ Autodocodec.Codec: matchChoiceCodec :: Codec context input output -> Codec context input' output -> (newInput -> Either input input') -> Codec context newInput output

Files

CHANGELOG.md view
@@ -1,5 +1,12 @@ # Changelog +## [0.1.0.0] - 2022-05-03++### Changed+* Generalise type of `matchChoiceCodec` to allow for two different input types.+* Add disjoint versions of `matchChoiceCodec` and `matchChoicesCodec`.+* Functions `enumCodec`, `stringConstCodec`, and `shownBoundedEnumCodec` now produce disjoint codecs.+ ## [0.0.1.1] - 2022-04-26  ### Added
autodocodec.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           autodocodec-version:        0.0.1.1+version:        0.1.0.0 synopsis:       Self-documenting encoder and decoder homepage:       https://github.com/NorfairKing/autodocodec#readme bug-reports:    https://github.com/NorfairKing/autodocodec/issues
src/Autodocodec.hs view
@@ -104,7 +104,11 @@      -- *** Choice     matchChoiceCodec,+    disjointMatchChoiceCodec,+    matchChoiceCodecAs,     matchChoicesCodec,+    disjointMatchChoicesCodec,+    matchChoicesCodecAs,      -- *** Adding documentation to a codec     (<?>),
src/Autodocodec/Codec.hs view
@@ -431,14 +431,28 @@   Codec context newInput newOutput dimapCodec f g = bimapCodec (Right . f) g --- | Forward-compatible version of 'PureCodec'+-- | Produce a value without parsing any part of an 'Object'. --+-- This function exists to implement @Applicative (ObjectCodec input)@.+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'PureCodec'.+-- -- > pureCodec = PureCodec pureCodec :: output -> ObjectCodec input output pureCodec = PureCodec --- | Forward-compatible version of 'ApCodec'+-- | Sequentially apply two codecs that parse part of an 'Object'. --+-- This function exists to implement @Applicative (ObjectCodec input)@.+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'ApCodec'.+-- -- > apCodec = ApCodec apCodec :: ObjectCodec input (output -> newOutput) -> ObjectCodec input output -> ObjectCodec input newOutput apCodec = ApCodec@@ -447,8 +461,10 @@   pure = pureCodec   (<*>) = apCodec --- | Also allow @null@ during decoding of a 'Maybe' value.+-- | Maybe codec --+-- This can be used to also allow @null@ during decoding of a 'Maybe' value.+-- -- During decoding, also accept a @null@ value as 'Nothing'. -- During encoding, encode as usual. --@@ -473,9 +489,10 @@       Nothing -> Left ()       Just r -> Right r --- | Forward-compatible version of 'EitherCodec'+-- | Either codec ----- > eitherCodec = EitherCodec PossiblyJointUnion+-- During encoding, parse a value according to either codec.+-- During encoding, use the corresponding codec to encode either value. -- -- === 'HasCodec' instance for sum types --@@ -488,6 +505,7 @@ -- -- @No  ->@ use 'disjointEitherCodec'. --+-- -- === Example usage -- -- >>> let c = eitherCodec codec codec :: JSONCodec (Either Int String)@@ -497,80 +515,29 @@ -- String "hello" -- >>> JSON.parseMaybe (parseJSONVia c) (String "world") :: Maybe (Either Int String) -- Just (Right "world")-eitherCodec ::-  -- |-  Codec context input1 output1 ->-  -- |-  Codec context input2 output2 ->-  -- |-  Codec context (Either input1 input2) (Either output1 output2)-eitherCodec = possiblyJointEitherCodec---- | Forward-compatible version of 'EitherCodec PossiblyJointUnion' ----- > possiblyJointEitherCodec = EitherCodec PossiblyJointUnion ----- === 'HasCodec' instance for sum types with an encoding that is not disjoint.------ The 'eitherCodec' can be used to implement 'HasCodec' instances for sum types.--- If you just have two codecs that you want to try in order, while parsing, you can do this:------ >>> :{---   data Ainur---     = Valar Text Text---     | Maiar Text---     deriving (Show, Eq)--- :}------ >>> :{---   instance HasCodec Ainur where---     codec =---       dimapCodec f g $---         possiblyJointEitherCodec---           (object "Valar" $---             (,)---              <$> requiredField "domain" "Domain which the Valar rules over" .= fst---              <*> requiredField "name" "Name of the Valar" .= snd)---           (object "Maiar" $ requiredField "name" "Name of the Maiar")---       where---         f = \case---           Left (domain, name) -> Valar domain name---           Right name -> Maiar name---         g = \case---           Valar domain name -> Left (domain, name)---           Maiar name -> Right name--- :}------ Note that this encoding is indeed not disjoint, because a @Valar@ object can--- parse as a @Maiar@ value.------ >>> toJSONViaCodec (Valar "Stars" "Varda")--- Object (fromList [("domain",String "Stars"),("name",String "Varda")])--- >>> toJSONViaCodec (Maiar "Sauron")--- Object (fromList [("name",String "Sauron")])--- >>> JSON.parseMaybe parseJSONViaCodec (Object (Compat.fromList [("name",String "Olorin")])) :: Maybe Ainur--- Just (Maiar "Olorin")------ === WARNING+-- ==== API Note ----- The order of the codecs in a 'possiblyJointEitherCodec' matters.+-- This is a forward-compatible version of 'possiblyJointEitherCodec'. ----- In the above example, decoding works as expected because the @Valar@ case is parsed first.--- If the @Maiar@ case were first in the 'possiblyJointEitherCodec', then--- @Valar@ could never be parsed.-possiblyJointEitherCodec ::+-- > eitherCodec = possiblyJointEitherCodec+eitherCodec ::   -- |   Codec context input1 output1 ->   -- |   Codec context input2 output2 ->   -- |   Codec context (Either input1 input2) (Either output1 output2)-possiblyJointEitherCodec = EitherCodec PossiblyJointUnion+eitherCodec = possiblyJointEitherCodec --- | Forward-compatible version of 'EitherCodec DisjointUnion'+-- | Possibly joint either codec ----- > disjointEitherCodec = EitherCodec DisjointUnion+-- During encoding, parse a value according to either codec.+-- During encoding, use the corresponding codec to encode either value. --+-- This codec is for the case in which parsing must be disjoint.+-- -- === 'HasCodec' instance for sum types with an encoding that is definitely disjoint. -- -- The 'eitherCodec' can be used to implement 'HasCodec' instances sum types@@ -603,6 +570,7 @@ -- >>> JSON.parseMaybe parseJSONViaCodec (String "of the roses") :: Maybe War -- Just (OtherWar "of the roses") --+-- -- === WARNING -- -- If it turns out that the encoding of a value is not disjoint, decoding may@@ -619,12 +587,20 @@ -- >>> toJSONVia c (Right 6) -- Number 6.0 --+-- -- === Example usage -- -- >>> toJSONVia (disjointEitherCodec (codec :: JSONCodec Int) (codec :: JSONCodec String)) (Left 5) -- Number 5.0 -- >>> toJSONVia (disjointEitherCodec (codec :: JSONCodec Int) (codec :: JSONCodec String)) (Right "hello") -- String "hello"+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'EitherCodec DisjointUnion'.+--+-- > disjointEitherCodec = EitherCodec DisjointUnion disjointEitherCodec ::   -- |   Codec context input1 output1 ->@@ -634,6 +610,78 @@   Codec context (Either input1 input2) (Either output1 output2) disjointEitherCodec = EitherCodec DisjointUnion +-- | Possibly joint either codec+--+-- During encoding, parse a value according to either codec.+-- During encoding, use the corresponding codec to encode either value.+--+-- This codec is for the case in which parsing may not be disjoint.+--+-- === 'HasCodec' instance for sum types with an encoding that is not disjoint.+--+-- The 'eitherCodec' can be used to implement 'HasCodec' instances for sum types.+-- If you just have two codecs that you want to try in order, while parsing, you can do this:+--+-- >>> :{+--   data Ainur+--     = Valar Text Text+--     | Maiar Text+--     deriving (Show, Eq)+-- :}+--+-- >>> :{+--   instance HasCodec Ainur where+--     codec =+--       dimapCodec f g $+--         possiblyJointEitherCodec+--           (object "Valar" $+--             (,)+--              <$> requiredField "domain" "Domain which the Valar rules over" .= fst+--              <*> requiredField "name" "Name of the Valar" .= snd)+--           (object "Maiar" $ requiredField "name" "Name of the Maiar")+--       where+--         f = \case+--           Left (domain, name) -> Valar domain name+--           Right name -> Maiar name+--         g = \case+--           Valar domain name -> Left (domain, name)+--           Maiar name -> Right name+-- :}+--+-- Note that this encoding is indeed not disjoint, because a @Valar@ object can+-- parse as a @Maiar@ value.+--+-- >>> toJSONViaCodec (Valar "Stars" "Varda")+-- Object (fromList [("domain",String "Stars"),("name",String "Varda")])+-- >>> toJSONViaCodec (Maiar "Sauron")+-- Object (fromList [("name",String "Sauron")])+-- >>> JSON.parseMaybe parseJSONViaCodec (Object (Compat.fromList [("name",String "Olorin")])) :: Maybe Ainur+-- Just (Maiar "Olorin")+--+--+-- === WARNING+--+-- The order of the codecs in a 'possiblyJointEitherCodec' matters.+--+-- In the above example, decoding works as expected because the @Valar@ case is parsed first.+-- If the @Maiar@ case were first in the 'possiblyJointEitherCodec', then+-- @Valar@ could never be parsed.+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'EitherCodec PossiblyJointUnion'.+--+-- > possiblyJointEitherCodec = EitherCodec PossiblyJointUnion+possiblyJointEitherCodec ::+  -- |+  Codec context input1 output1 ->+  -- |+  Codec context input2 output2 ->+  -- |+  Codec context (Either input1 input2) (Either output1 output2)+possiblyJointEitherCodec = EitherCodec PossiblyJointUnion+ -- | Map a codec's input and output types. -- -- This function allows you to have the parsing fail in a new way.@@ -642,6 +690,7 @@ -- -- This function is like 'BimapCodec' except it also combines one level of a nested 'BimapCodec's. --+-- -- === Example usage -- -- logLevelCodec :: JSONCodec LogLevel@@ -651,36 +700,61 @@   (newInput -> oldInput) ->   Codec context oldInput oldOutput ->   Codec context newInput newOutput-bimapCodec f g = \case-  BimapCodec f' g' c -> BimapCodec (f' >=> f) (g' . g) c-  c -> BimapCodec f g c+bimapCodec f g =+  -- We distinguish between a 'BimapCodec' and a non-'BimapCodec' just so that+  -- we don't introduce additional layers that we can already combine anyway.+  \case+    BimapCodec f' g' c -> BimapCodec (f' >=> f) (g' . g) c+    c -> BimapCodec f g c --- | Forward-compatible version of 'ArrayOfCodec' without a name+-- | Vector codec ----- > vectorCodec = ArrayOfCodec Nothing+-- Build a codec for vectors of values from a codec for a single value. --+-- -- === Example usage -- -- >>> toJSONVia (vectorCodec codec) (Vector.fromList ['a','b']) -- Array [String "a",String "b"]+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'ArrayOfCodec' without a name.+--+-- > vectorCodec = ArrayOfCodec Nothing vectorCodec :: ValueCodec input output -> ValueCodec (Vector input) (Vector output) vectorCodec = ArrayOfCodec Nothing --- | Build a codec for lists of values from a codec for a single value.+-- | List codec --+-- Build a codec for lists of values from a codec for a single value.+--+-- -- === Example usage -- -- >>> toJSONVia (listCodec codec) ['a','b'] -- Array [String "a",String "b"]+--+--+-- ==== API Note+--+-- This is the list version of 'vectorCodec'. listCodec :: ValueCodec input output -> ValueCodec [input] [output] listCodec = dimapCodec V.toList V.fromList . vectorCodec  -- | Build a codec for nonempty lists of values from a codec for a single value. --+-- -- === Example usage -- -- >>> toJSONVia (nonEmptyCodec codec) ('a' :| ['b']) -- Array [String "a",String "b"]+--+--+-- ==== API Note+--+-- This is the non-empty list version of 'vectorCodec'. nonEmptyCodec :: ValueCodec input output -> ValueCodec (NonEmpty input) (NonEmpty output) nonEmptyCodec = bimapCodec parseNonEmptyList NE.toList . listCodec   where@@ -688,11 +762,15 @@       Nothing -> Left "Expected a nonempty list, but got an empty list."       Just ne -> Right ne --- | Like 'listCodec', except the values may also be simplified as a single value.+-- | Single or list codec --+-- This codec behaves like 'listCodec', except the values may also be+-- simplified as a single value.+-- -- During parsing, a single element may be parsed as the list of just that element. -- During rendering, a list with only one element will be rendered as just that element. --+-- -- === Example usage -- -- >>> let c = singleOrListCodec codec :: JSONCodec [Int]@@ -705,6 +783,7 @@ -- >>> JSON.parseMaybe (parseJSONVia c) (Array [Number 5, Number 6]) :: Maybe [Int] -- Just [5,6] --+-- -- === WARNING -- -- If you use nested lists, for example when the given value codec is also a@@ -719,11 +798,15 @@       [v] -> Left v       vs -> Right vs --- | Like 'nonEmptyCodec', except the values may also be simplified as a single value.+-- | Single or nonempty list codec --+-- This codec behaves like 'nonEmptyCodec', except the values may also be+-- simplified as a single value.+-- -- During parsing, a single element may be parsed as the list of just that element. -- During rendering, a list with only one element will be rendered as just that element. --+-- -- === Example usage -- -- >>> let c = singleOrNonEmptyCodec codec :: JSONCodec (NonEmpty Int)@@ -736,10 +819,15 @@ -- >>> JSON.parseMaybe (parseJSONVia c) (Array [Number 5, Number 6]) :: Maybe (NonEmpty Int) -- Just (5 :| [6]) --+-- -- === WARNING -- -- If you use nested lists, for example when the given value codec is also a -- 'nonEmptyCodec', you may get in trouble with ambiguities during parsing.+--+-- ==== API Note+--+-- This is a nonempty version of 'singleOrListCodec'. singleOrNonEmptyCodec :: ValueCodec input output -> ValueCodec (NonEmpty input) (NonEmpty output) singleOrNonEmptyCodec c = dimapCodec f g $ eitherCodec c $ nonEmptyCodec c   where@@ -860,6 +948,8 @@   ObjectCodec output output optionalFieldWithOmittedDefaultWith' key c defaultValue = OptionalKeyWithOmittedDefaultCodec key c defaultValue Nothing +-- | Like 'optionalFieldWithOmittedDefaultWith', but the value may also be+-- @null@ and that will be interpreted as the default value. optionalFieldOrNullWithOmittedDefaultWith ::   Eq output =>   -- | Key@@ -878,6 +968,8 @@       Nothing -> defaultValue     g v = if v == defaultValue then Nothing else Just v +-- | Like 'optionalFieldWithOmittedDefaultWith'', but the value may also be+-- @null@ and that will be interpreted as the default value. optionalFieldOrNullWithOmittedDefaultWith' ::   Eq output =>   -- | Key@@ -942,8 +1034,11 @@  -- | Encode a 'HashMap', and decode any 'HashMap'. ----- Forward-compatible version of 'HashMapCodec' --+-- ==== API Note+--+-- This is a forward-compatible version of 'HashMapCodec'.+-- -- > hashMapCodec = HashMapCodec hashMapCodec ::   (Eq k, Hashable k, FromJSONKey k, ToJSONKey k) =>@@ -955,8 +1050,11 @@  -- | Encode a 'Map', and decode any 'Map'. ----- Forward-compatible version of 'MapCodec' --+-- ==== API Note+--+-- This is a forward-compatible version of 'MapCodec'.+-- -- > mapCodec = MapCodec mapCodec ::   (Ord k, FromJSONKey k, ToJSONKey k) =>@@ -982,20 +1080,23 @@   Nothing -> dimapCodec KM.fromHashMap KM.toHashMap . hashMapCodec #endif --- | Forward-compatible version of 'ValueCodec'------ > valueCodec = ValueCodec+-- | Codec for a 'JSON.Value' -- -- This is essentially your escape-hatch for when you would normally need a monad instance for 'Codec'. -- You can build monad parsing by using 'valueCodec' together with 'bimapCodec' and supplying your own parsing function. -- -- Note that this _does_ mean that the documentation will just say that you are parsing and rendering a value, so you may want to document the extra parsing further using '<?>'.+--+-- ==== API Note+--+-- This is a forward-compatible version of 'ValueCodec'.+--+-- > valueCodec = ValueCodec valueCodec :: JSONCodec JSON.Value valueCodec = ValueCodec --- | Forward-compatible version of 'NullCodec'+-- | Codec for @null@ ----- > nullCodec = NullCodec -- -- === Example usage --@@ -1005,49 +1106,76 @@ -- Just () -- >>> JSON.parseMaybe (parseJSONVia nullCodec) (Number 5) -- Nothing+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'NullCodec'.+--+-- > nullCodec = NullCodec nullCodec :: JSONCodec () nullCodec = NullCodec --- | Forward-compatible version of 'BoolCodec' without a name+-- | Codec for boolean values ----- > boolCodec = BoolCodec Nothing -- -- === Example usage -- -- >>> toJSONVia boolCodec True -- Bool True+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'BoolCodec' without a name.+--+-- > boolCodec = BoolCodec Nothing boolCodec :: JSONCodec Bool boolCodec = BoolCodec Nothing --- | Forward-compatible version of 'StringCodec' without a name+-- | Codec for text values ----- > textCodec = StringCodec Nothing -- -- === Example usage -- -- >>> toJSONVia textCodec "hello" -- String "hello"+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'StringCodec' without a name.+--+-- > textCodec = StringCodec Nothing textCodec :: JSONCodec Text textCodec = StringCodec Nothing --- | A 'String' version of 'textCodec'.+-- | Codec for 'String' values --+-- -- === Example usage -- -- >>> toJSONVia stringCodec "hello" -- String "hello" --+-- -- === WARNING -- -- This codec uses 'T.unpack' and 'T.pack' to dimap a 'textCodec', so it __does not roundtrip__. -- -- >>> toJSONVia stringCodec "\55296" -- String "\65533"+--+--+-- ==== API Note+--+-- This is a 'String' version of 'textCodec'. stringCodec :: JSONCodec String stringCodec = dimapCodec T.unpack T.pack textCodec --- | Forward-compatible version of 'NumberCodec' without a name+-- | Codec for 'Scientific' values --+-- -- === Example usage -- -- > scientificCodec = NumberCodec Nothing Nothing@@ -1055,6 +1183,7 @@ -- >>> toJSONVia scientificCodec 5 -- Number 5.0 --+-- -- === WARNING -- -- 'Scientific' is a type that is only for JSON parsing and rendering.@@ -1065,12 +1194,18 @@ -- λ> (1 / 3) :: Scientific -- *** Exception: fromRational has been applied to a repeating decimal which can't be represented as a Scientific! It's better to avoid performing fractional operations on Scientifics and convert them to other fractional types like Double as early as possible. -- @+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'NumberCodec' without a name.+--+-- > scientificCodec = NumberCodec Nothing Nothing scientificCodec :: JSONCodec Scientific scientificCodec = NumberCodec Nothing Nothing  -- | An object codec with a given name ----- > object name = ObjectOfCodec (Just name) -- -- === Example usage --@@ -1085,6 +1220,13 @@ -- >       Example -- >         <$> requiredField "text" "a text" .= exampleText -- >         <*> requiredField "bool" "a bool" .= exampleBool+--+--+-- ==== API Note+--+-- This is a forward-compatible version 'ObjectOfCodec' with a name.+--+-- > object name = ObjectOfCodec (Just name) object :: Text -> ObjectCodec input output -> ValueCodec input output object name = ObjectOfCodec (Just name) @@ -1127,6 +1269,7 @@ -- -- During rendering, the given 'Text' is always output. --+-- -- === Example usage -- -- >>> let c = literalTextCodec "hello"@@ -1147,6 +1290,7 @@ -- -- During rendering, the given @value@ is always output. --+-- -- === Example usage -- -- >>> let c = literalTextValueCodec True "yes"@@ -1161,7 +1305,7 @@ literalTextValueCodec :: value -> Text -> JSONCodec value literalTextValueCodec value text = dimapCodec (const value) (const text) (literalTextCodec text) --- | A choice codec, but unlike 'eitherCodec', it's for the same type instead of different ones.+-- | A choice codec, but unlike 'eitherCodec', it's for the same output type instead of different ones. -- -- While parsing, this codec will first try the left codec, then the right if that fails. --@@ -1170,6 +1314,7 @@ -- Note: The reason this is less primitive than the 'eitherCodec' is that 'Either' makes it clear which codec you want to use for rendering. -- In this case, we need to provide our own function for choosing which codec we want to use for rendering. --+-- -- === Example usage -- -- >>> :{@@ -1188,29 +1333,66 @@ -- Just "even" -- >>> JSON.parseMaybe (parseJSONVia c) (String "odd") :: Maybe Text -- Just "odd"+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'matchChoiceCodecAs PossiblyJointUnion':+--+-- > disjointMatchChoiceCodec = matchChoiceCodecAs PossiblyJointUnion matchChoiceCodec ::   -- | First codec   Codec context input output ->   -- | Second codec+  Codec context input' output ->+  -- | Rendering chooser+  (newInput -> Either input input') ->+  -- |+  Codec context newInput output+matchChoiceCodec = matchChoiceCodecAs PossiblyJointUnion++-- | Disjoint version of 'matchChoiceCodec'+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'matchChoiceCodecAs DisjointUnion':+--+-- > disjointMatchChoiceCodec = matchChoiceCodecAs DisjointUnion+disjointMatchChoiceCodec ::+  -- | First codec   Codec context input output ->+  -- | Second codec+  Codec context input' output ->   -- | Rendering chooser-  (newInput -> Either input input) ->+  (newInput -> Either input input') ->   -- |   Codec context newInput output-matchChoiceCodec c1 c2 renderingChooser =-  dimapCodec f renderingChooser $-    eitherCodec c1 c2-  where-    f = \case-      Left a -> a-      Right a -> a+disjointMatchChoiceCodec = matchChoiceCodecAs DisjointUnion +-- | An even more general version of 'matchChoiceCodec' and 'disjointMatchChoiceCodec'.+matchChoiceCodecAs ::+  -- | Is the union DisjointUnion or PossiblyJointUnion+  Union ->+  -- | First codec+  Codec context input output ->+  -- | Second codec+  Codec context input' output ->+  -- | Rendering chooser+  (newInput -> Either input input') ->+  -- |+  Codec context newInput output+matchChoiceCodecAs union c1 c2 renderingChooser =+  dimapCodec (either id id) renderingChooser $+    EitherCodec union c1 c2+ -- | A choice codec for a list of options, each with their own rendering matcher. -- -- During parsing, each of the codecs are tried from first to last until one succeeds. -- -- During rendering, each matching function is tried until either one succeeds and the corresponding codec is used, or none succeed and the fallback codec is used. --+-- -- === Example usage -- -- >>> :{@@ -1235,6 +1417,13 @@ -- Nothing -- >>> JSON.parseMaybe (parseJSONVia c) (String "fallback") :: Maybe Text -- Just "fallback"+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'matchChoicesCodecAs DisjointUnion'.+--+-- > disjointMatchChoiceCodec = matchChoicesCodecAs DisjointUnion matchChoicesCodec ::   -- | Codecs, each which their own rendering matcher   [(input -> Maybe input, Codec context input output)] ->@@ -1242,11 +1431,39 @@   Codec context input output ->   -- |   Codec context input output-matchChoicesCodec l fallback = go l+matchChoicesCodec = matchChoicesCodecAs PossiblyJointUnion++-- | Disjoint version of 'matchChoicesCodec'+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'matchChoicesCodecAs DisjointUnion'.+--+-- > disjointMatchChoiceCodec = matchChoicesCodecAs DisjointUnion+disjointMatchChoicesCodec ::+  -- | Codecs, each which their own rendering matcher+  [(input -> Maybe input, Codec context input output)] ->+  -- | Fallback codec, in case none of the matchers in the list match+  Codec context input output ->+  -- |+  Codec context input output+disjointMatchChoicesCodec = matchChoicesCodecAs DisjointUnion++-- | An even more general version of 'matchChoicesCodec' and 'disjointMatchChoicesCodec'+matchChoicesCodecAs ::+  Union ->+  -- | Codecs, each which their own rendering matcher+  [(input -> Maybe input, Codec context input output)] ->+  -- | Fallback codec, in case none of the matchers in the list match+  Codec context input output ->+  -- |+  Codec context input output+matchChoicesCodecAs union l fallback = go l   where     go = \case       [] -> fallback-      ((m, c) : rest) -> matchChoiceCodec c (go rest) $ \i -> case m i of+      ((m, c) : rest) -> matchChoiceCodecAs union c (go rest) $ \i -> case m i of         Just j -> Left j         Nothing -> Right i @@ -1255,6 +1472,7 @@ -- -- You can use this for keeping old ways of parsing intact while already rendering in the new way. --+-- -- === Example usage -- -- >>> data Fruit = Apple | Orange deriving (Show, Eq, Bounded, Enum)@@ -1281,6 +1499,7 @@  -- | Like 'parseAlternatives', but with only one alternative codec --+-- -- === Example usage -- -- >>> data Fruit = Apple | Orange deriving (Show, Eq, Bounded, Enum)@@ -1301,6 +1520,7 @@  -- | A codec for an enum that can be written each with their own codec. --+-- -- === WARNING -- -- If you don't provide a string for one of the type's constructors, the last codec in the list will be used instead.@@ -1316,13 +1536,14 @@     go :: NonEmpty (enum, Codec context enum enum) -> Codec context enum enum     go ((e, c) :| rest) = case NE.nonEmpty rest of       Nothing -> c-      Just ne -> matchChoiceCodec c (go ne) $ \i ->+      Just ne -> disjointMatchChoiceCodec c (go ne) $ \i ->         if e == i           then Left e           else Right i  -- | A codec for an enum that can be written as constant string values --+-- -- === Example usage -- -- >>> data Fruit = Apple | Orange deriving (Show, Eq)@@ -1332,6 +1553,7 @@ -- >>> JSON.parseMaybe (parseJSONVia c) (String "foo") :: Maybe Fruit -- Just Apple --+-- -- === WARNING -- -- If you don't provide a string for one of the type's constructors, the last string in the list will be used instead:@@ -1357,6 +1579,7 @@  -- | A codec for a 'Bounded' 'Enum' that uses its 'Show' instance to have the values correspond to literal 'Text' values. --+-- -- === Example usage -- -- >>> data Fruit = Apple | Orange deriving (Show, Eq, Enum, Bounded)@@ -1399,8 +1622,11 @@ -- This is used to allow for references to the codec, and that's necessary -- to produce finite documentation for recursive codecs. ----- Forward-compatible version of 'ReferenceCodec' --+-- ==== API Note+--+-- This is a forward-compatible version of 'ReferenceCodec'.+-- -- > named = ReferenceCodec named :: Text -> ValueCodec input output -> ValueCodec input output named = ReferenceCodec@@ -1412,6 +1638,7 @@ -- -- Note that this will not have good documentation because, at a codec level, -- it's just parsing and rendering a 'JSON.Value'.+-- -- -- === Example usage --