packages feed

autodocodec 0.3.0.0 → 0.4.0.0

raw patch · 6 files changed

+209/−133 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Autodocodec: boundedIntegralNumberBounds :: forall i. (Integral i, Bounded i) => NumberBounds
- Autodocodec.Codec: NumberBounds :: !Scientific -> !Scientific -> NumberBounds
- Autodocodec.Codec: OtherDouble :: !Double -> ScientificSymbolic
- Autodocodec.Codec: OtherNumberBounds :: !ScientificSymbolic -> !ScientificSymbolic -> NumberBoundsSymbolic
- Autodocodec.Codec: [numberBoundsLower] :: NumberBounds -> !Scientific
- Autodocodec.Codec: [numberBoundsUpper] :: NumberBounds -> !Scientific
- Autodocodec.Codec: boundedIntegralNumberBounds :: forall i. (Integral i, Bounded i) => NumberBounds
- Autodocodec.Codec: checkNumberBounds :: NumberBounds -> Scientific -> Either String Scientific
- Autodocodec.Codec: data NumberBounds
- Autodocodec.Codec: data NumberBoundsSymbolic
- Autodocodec.Codec: data ScientificSymbolic
- Autodocodec.Codec: guessNumberBoundsSymbolic :: NumberBounds -> NumberBoundsSymbolic
- Autodocodec.Codec: guessScientificSymbolic :: Scientific -> ScientificSymbolic
- Autodocodec.Codec: instance Data.Validity.Validity Autodocodec.Codec.NumberBounds
- Autodocodec.Codec: instance GHC.Classes.Eq Autodocodec.Codec.NumberBounds
- Autodocodec.Codec: instance GHC.Classes.Ord Autodocodec.Codec.NumberBounds
- Autodocodec.Codec: instance GHC.Generics.Generic Autodocodec.Codec.NumberBounds
- Autodocodec.Codec: instance GHC.Show.Show Autodocodec.Codec.NumberBounds
+ Autodocodec: Bounds :: !Maybe a -> !Maybe a -> Bounds a
+ Autodocodec: [IntegerCodec] :: (Coercible a Integer, Coercible b Integer) => Maybe Text -> Bounds Integer -> ValueCodec a b
+ Autodocodec: [boundsLower] :: Bounds a -> !Maybe a
+ Autodocodec: [boundsUpper] :: Bounds a -> !Maybe a
+ Autodocodec: boundedBounds :: Bounded a => Bounds a
+ Autodocodec: checkBounds :: (Show a, Ord a) => Bounds a -> a -> Either String a
+ Autodocodec: data Bounds a
+ Autodocodec: emptyBounds :: Bounds a
+ Autodocodec: integerWithBoundsCodec :: Bounds Integer -> JSONCodec Integer
+ Autodocodec.Codec: Bounds :: !Maybe a -> !Maybe a -> Bounds a
+ Autodocodec.Codec: OtherIntegerBounds :: !Maybe IntegerSymbolic -> !Maybe IntegerSymbolic -> IntegerBoundsSymbolic
+ Autodocodec.Codec: [IntegerCodec] :: (Coercible a Integer, Coercible b Integer) => Maybe Text -> Bounds Integer -> ValueCodec a b
+ Autodocodec.Codec: [boundsLower] :: Bounds a -> !Maybe a
+ Autodocodec.Codec: [boundsUpper] :: Bounds a -> !Maybe a
+ Autodocodec.Codec: boundedBounds :: Bounded a => Bounds a
+ Autodocodec.Codec: boundedIntegralBounds :: forall i. (Integral i, Bounded i) => Bounds Integer
+ Autodocodec.Codec: checkBounds :: (Show a, Ord a) => Bounds a -> a -> Either String a
+ Autodocodec.Codec: data Bounds a
+ Autodocodec.Codec: data IntegerBoundsSymbolic
+ Autodocodec.Codec: data IntegerSymbolic
+ Autodocodec.Codec: emptyBounds :: Bounds a
+ Autodocodec.Codec: guessIntegerBoundsSymbolic :: Bounds Integer -> IntegerBoundsSymbolic
+ Autodocodec.Codec: guessIntegerSymbolic :: Integer -> IntegerSymbolic
+ Autodocodec.Codec: instance Data.Validity.Validity a => Data.Validity.Validity (Autodocodec.Codec.Bounds a)
+ Autodocodec.Codec: instance GHC.Base.Functor Autodocodec.Codec.Bounds
+ Autodocodec.Codec: instance GHC.Classes.Eq a => GHC.Classes.Eq (Autodocodec.Codec.Bounds a)
+ Autodocodec.Codec: instance GHC.Classes.Ord a => GHC.Classes.Ord (Autodocodec.Codec.Bounds a)
+ Autodocodec.Codec: instance GHC.Generics.Generic (Autodocodec.Codec.Bounds a)
+ Autodocodec.Codec: instance GHC.Show.Show a => GHC.Show.Show (Autodocodec.Codec.Bounds a)
+ Autodocodec.Codec: integerWithBoundsCodec :: Bounds Integer -> JSONCodec Integer
- Autodocodec: [NumberCodec] :: (Coercible a Scientific, Coercible b Scientific) => Maybe Text -> Maybe NumberBounds -> ValueCodec a b
+ Autodocodec: [NumberCodec] :: (Coercible a Scientific, Coercible b Scientific) => Maybe Text -> Bounds Scientific -> ValueCodec a b
- Autodocodec: scientificWithBoundsCodec :: NumberBounds -> JSONCodec Scientific
+ Autodocodec: scientificWithBoundsCodec :: Bounds Scientific -> JSONCodec Scientific
- Autodocodec.Codec: BitSInt :: !Word8 -> NumberBoundsSymbolic
+ Autodocodec.Codec: BitSInt :: !Word8 -> IntegerBoundsSymbolic
- Autodocodec.Codec: BitUInt :: !Word8 -> NumberBoundsSymbolic
+ Autodocodec.Codec: BitUInt :: !Word8 -> IntegerBoundsSymbolic
- Autodocodec.Codec: MinusPowerOf2 :: !Word8 -> ScientificSymbolic
+ Autodocodec.Codec: MinusPowerOf2 :: !Word8 -> IntegerSymbolic
- Autodocodec.Codec: MinusPowerOf2MinusOne :: !Word8 -> ScientificSymbolic
+ Autodocodec.Codec: MinusPowerOf2MinusOne :: !Word8 -> IntegerSymbolic
- Autodocodec.Codec: OtherInteger :: !Integer -> ScientificSymbolic
+ Autodocodec.Codec: OtherInteger :: !Integer -> IntegerSymbolic
- Autodocodec.Codec: PowerOf2 :: !Word8 -> ScientificSymbolic
+ Autodocodec.Codec: PowerOf2 :: !Word8 -> IntegerSymbolic
- Autodocodec.Codec: PowerOf2MinusOne :: !Word8 -> ScientificSymbolic
+ Autodocodec.Codec: PowerOf2MinusOne :: !Word8 -> IntegerSymbolic
- Autodocodec.Codec: Zero :: ScientificSymbolic
+ Autodocodec.Codec: Zero :: IntegerSymbolic
- Autodocodec.Codec: [NumberCodec] :: (Coercible a Scientific, Coercible b Scientific) => Maybe Text -> Maybe NumberBounds -> ValueCodec a b
+ Autodocodec.Codec: [NumberCodec] :: (Coercible a Scientific, Coercible b Scientific) => Maybe Text -> Bounds Scientific -> ValueCodec a b
- Autodocodec.Codec: scientificWithBoundsCodec :: NumberBounds -> JSONCodec Scientific
+ Autodocodec.Codec: scientificWithBoundsCodec :: Bounds Scientific -> JSONCodec Scientific

Files

CHANGELOG.md view
@@ -1,5 +1,16 @@ # Changelog +## [0.4.0.0] - 2024-07-26++This is technically a breaking change but it's unlikely that you'll need to+change any of your codecs.++### Changed++* Changed `NumberBounds` to `Bounds` and made both bounds optional.+* Added `IntegerCodec` as distinct from `NumberCodec` to represent integers+  effectively in documentation.+ ## [0.3.0.0] - 2024-07-19  ### Added
autodocodec.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           autodocodec-version:        0.3.0.0+version:        0.4.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
@@ -74,14 +74,20 @@     boolCodec,     textCodec,     stringCodec,+    integerCodec,+    integerWithBoundsCodec,     scientificCodec,     scientificWithBoundsCodec,     valueCodec, +    -- *** Bounds+    Bounds (..),+    emptyBounds,+    boundedBounds,+    checkBounds,+     -- *** Integral codecs     boundedIntegralCodec,-    boundedIntegralNumberBounds,-    integerCodec,     unsafeUnboundedIntegerCodec,     naturalCodec,     unsafeUnboundedNaturalCodec,
src/Autodocodec/Aeson/Decode.hs view
@@ -29,6 +29,7 @@ import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import Data.Map (Map)+import Data.Scientific as Scientific import Data.Text (Text) import qualified Data.Text as T import Data.Vector (Vector)@@ -69,13 +70,36 @@       StringCodec mname -> case mname of         Nothing -> coerce (parseJSON value :: JSON.Parser Text)         Just name -> coerce $ withText (T.unpack name) pure value-      NumberCodec mname mBounds ->+      IntegerCodec mname bounds ->         coerce $+          ( \f -> do+              let safetyBounds =+                    Bounds+                      { boundsLower = Just $ scientific (-1) 1024,+                        boundsUpper = Just $ scientific 1 1024+                      }+                  checkSafetyBounds s =+                    case checkBounds safetyBounds s of+                      Left err -> fail err+                      Right i' -> pure i'+              s <- case mname of+                Nothing -> parseJSON value >>= checkSafetyBounds+                Just name -> withScientific (T.unpack name) checkSafetyBounds value+              case Scientific.floatingOrInteger s :: Either Double Integer of+                Left _ -> fail $ "Number was not integer: " <> show s+                Right i -> f (i :: Integer)+          )+            ( \i -> case checkBounds bounds i of+                Left err -> fail err+                Right i' -> pure i'+            )+      NumberCodec mname bounds ->+        coerce $           ( \f -> case mname of               Nothing -> parseJSON value >>= f               Just name -> withScientific (T.unpack name) f value           )-            ( \s -> case maybe Right checkNumberBounds mBounds s of+            ( \s -> case checkBounds bounds s of                 Left err -> fail err                 Right s' -> pure s'             )
src/Autodocodec/Aeson/Encode.hs view
@@ -76,6 +76,7 @@       NullCodec -> JSON.Null       BoolCodec _ -> toJSON (coerce a :: Bool)       StringCodec _ -> toJSON (coerce a :: Text)+      IntegerCodec _ _ -> toJSON (coerce a :: Integer)       NumberCodec _ _ -> toJSON (coerce a :: Scientific)       ArrayOfCodec _ c -> toJSON (fmap (`go` c) (coerce a :: Vector _))       ObjectOfCodec _ oc -> JSON.Object (toJSONObjectVia oc a)@@ -131,6 +132,7 @@       NullCodec -> JSON.null_       BoolCodec _ -> JSON.bool (coerce a :: Bool)       StringCodec _ -> JSON.text (coerce a :: Text)+      IntegerCodec _ _ -> JSON.scientific (fromInteger (coerce a :: Integer) :: Scientific)       NumberCodec _ _ -> JSON.scientific (coerce a :: Scientific)       ArrayOfCodec _ c -> JSON.list (`go` c) (V.toList (coerce a :: Vector _))       ObjectOfCodec _ oc -> JSON.pairs (toSeriesVia oc a)
src/Autodocodec/Codec.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-}@@ -98,9 +99,24 @@     -- | Name of the @string@, for error messages and documentation.     Maybe Text ->     ValueCodec a b+  -- | Encode 'Integer' to a @number@ value, and decode a @number@ value as an 'Integer'.+  --+  -- The number has 'Bounds Integer'.+  -- These are only enforced at decoding time, not at encoding-time.+  --+  -- NOTE: Decoding 'Integer's is dangerous so decoding may fail for enormous numbers.+  -- API NOTE: This is separate from 'NumberCodec' so that we can produce+  -- more precise documentation about whether the numbers are integers.+  IntegerCodec ::+    (Coercible a Integer, Coercible b Integer) =>+    -- | Name of the @integer@, for error messages and documentation.+    Maybe Text ->+    -- | Bounds for the integer, these are checked and documented+    Bounds Integer ->+    ValueCodec a b   -- | Encode 'Scientific' to a @number@ value, and decode a @number@ value as a 'Scientific'.   ---  -- The number has optional 'NumberBounds'.+  -- The number has 'Bounds Scientific'.   -- These are only enforced at decoding time, not at encoding-time.   --   -- NOTE: We use 'Scientific' here because that is what aeson uses.@@ -109,7 +125,7 @@     -- | Name of the @number@, for error messages and documentation.     Maybe Text ->     -- | Bounds for the number, these are checked and documented-    Maybe NumberBounds ->+    Bounds Scientific ->     ValueCodec a b   -- | Encode a 'HashMap', and decode any 'HashMap'.   HashMapCodec ::@@ -279,72 +295,68 @@     ObjectCodec input output ->     ObjectCodec input newOutput -data NumberBounds = NumberBounds-  { numberBoundsLower :: !Scientific,-    numberBoundsUpper :: !Scientific+data Bounds a = Bounds+  { -- | Lower bound, inclusive+    boundsLower :: !(Maybe a),+    -- Upper bound, inclusive+    boundsUpper :: !(Maybe a)   }-  deriving (Show, Eq, Ord, Generic)+  deriving (Show, Eq, Ord, Generic, Functor) -instance Validity NumberBounds+instance (Validity a) => Validity (Bounds a) -optionalKeyWithDefaultCodec ::-  -- | Key-  Text ->-  -- | Codec for the value-  ValueCodec value value ->-  -- | Default value-  value ->-  -- | Documentation-  Maybe Text ->-  ObjectCodec value value-optionalKeyWithDefaultCodec = OptionalKeyWithDefaultCodec+emptyBounds :: Bounds a+emptyBounds = Bounds Nothing Nothing +boundedBounds :: (Bounded a) => Bounds a+boundedBounds =+  Bounds+    { boundsLower = Just minBound,+      boundsUpper = Just maxBound+    }+ -- | Check if a number falls within given 'NumberBounds'.-checkNumberBounds :: NumberBounds -> Scientific -> Either String Scientific-checkNumberBounds NumberBounds {..} s =-  if numberBoundsLower <= s-    then-      if s <= numberBoundsUpper-        then Right s-        else Left $ unwords ["Number", show s, "is bigger than the upper bound", show numberBoundsUpper]-    else Left $ unwords ["Number", show s, "is smaller than the lower bound", show numberBoundsUpper]+checkBounds :: (Show a, Ord a) => Bounds a -> a -> Either String a+checkBounds Bounds {..} s =+  case boundsLower of+    Just lo | s < lo -> Left $ unwords ["Number", show s, "is smaller than the lower bound", show lo]+    _ -> case boundsUpper of+      Just hi | s > hi -> Left $ unwords ["Number", show s, "is bigger than the upper bound", show hi]+      _ -> Right s -data NumberBoundsSymbolic+data IntegerBoundsSymbolic   = BitUInt !Word8 -- w bit unsigned int   | BitSInt !Word8 -- w bit signed int-  | OtherNumberBounds !ScientificSymbolic !ScientificSymbolic+  | OtherIntegerBounds !(Maybe IntegerSymbolic) !(Maybe IntegerSymbolic) -guessNumberBoundsSymbolic :: NumberBounds -> NumberBoundsSymbolic-guessNumberBoundsSymbolic NumberBounds {..} =-  case (guessScientificSymbolic numberBoundsLower, guessScientificSymbolic numberBoundsUpper) of-    (Zero, PowerOf2MinusOne w) -> BitUInt w-    (MinusPowerOf2 w1, PowerOf2MinusOne w2) | w1 == w2 -> BitSInt (succ w1)-    (l, u) -> OtherNumberBounds l u+guessIntegerBoundsSymbolic :: Bounds Integer -> IntegerBoundsSymbolic+guessIntegerBoundsSymbolic Bounds {..} =+  case (guessIntegerSymbolic <$> boundsLower, guessIntegerSymbolic <$> boundsUpper) of+    (Just Zero, Just (PowerOf2MinusOne w)) -> BitUInt w+    (Just (MinusPowerOf2 w1), Just (PowerOf2MinusOne w2)) | w1 == w2 -> BitSInt (succ w1)+    (l, u) -> OtherIntegerBounds l u -data ScientificSymbolic+data IntegerSymbolic   = Zero   | PowerOf2 !Word8 -- 2^w   | PowerOf2MinusOne !Word8 -- 2^w -1   | MinusPowerOf2 !Word8 -- - 2^w   | MinusPowerOf2MinusOne !Word8 -- - (2^w -1)   | OtherInteger !Integer-  | OtherDouble !Double -guessScientificSymbolic :: Scientific -> ScientificSymbolic-guessScientificSymbolic s = case floatingOrInteger s of-  Left d -> OtherDouble d-  Right i ->-    let log2Rounded :: Word8-        log2Rounded = round (logBase 2 (fromInteger (abs i)) :: Double)-        guess :: Integer-        guess = 2 ^ log2Rounded-     in if-          | i == 0 -> Zero-          | guess == i -> PowerOf2 log2Rounded-          | (guess - 1) == i -> PowerOf2MinusOne log2Rounded-          | -guess == i -> MinusPowerOf2 log2Rounded-          | -(guess - 1) == i -> MinusPowerOf2MinusOne log2Rounded-          | otherwise -> OtherInteger i+guessIntegerSymbolic :: Integer -> IntegerSymbolic+guessIntegerSymbolic i =+  let log2Rounded :: Word8+      log2Rounded = round (logBase 2 (fromInteger (abs i)) :: Double)+      guess :: Integer+      guess = 2 ^ log2Rounded+   in if+        | i == 0 -> Zero+        | guess == i -> PowerOf2 log2Rounded+        | (guess - 1) == i -> PowerOf2MinusOne log2Rounded+        | -guess == i -> MinusPowerOf2 log2Rounded+        | -(guess - 1) == i -> MinusPowerOf2MinusOne log2Rounded+        | otherwise -> OtherInteger i  -- | What type of union the encoding uses data Union@@ -398,6 +410,7 @@       NullCodec -> pure $ showString "NullCodec"       BoolCodec mName -> pure $ showParen (d > 10) $ showString "BoolCodec " . showsPrec 11 mName       StringCodec mName -> pure $ showParen (d > 10) $ showString "StringCodec " . showsPrec 11 mName+      IntegerCodec mName mbs -> pure $ showParen (d > 10) $ showString "IntegerCodec " . showsPrec 11 mName . showString " " . showsPrec 11 mbs       NumberCodec mName mbs -> pure $ showParen (d > 10) $ showString "NumberCodec " . showsPrec 11 mName . showString " " . showsPrec 11 mbs       ArrayOfCodec mName c -> (\s -> showParen (d > 10) $ showString "ArrayOfCodec " . showsPrec 11 mName . showString " " . s) <$> go 11 c       ObjectOfCodec mName oc -> (\s -> showParen (d > 10) $ showString "ObjectOfCodec " . showsPrec 11 mName . showString " " . s) <$> go 11 oc@@ -864,6 +877,18 @@ optionalKeyCodec :: Text -> ValueCodec input output -> Maybe Text -> ObjectCodec (Maybe input) (Maybe output) optionalKeyCodec = OptionalKeyCodec +optionalKeyWithDefaultCodec ::+  -- | Key+  Text ->+  -- | Codec for the value+  ValueCodec value value ->+  -- | Default value+  value ->+  -- | Documentation+  Maybe Text ->+  ObjectCodec value value+optionalKeyWithDefaultCodec = OptionalKeyWithDefaultCodec+ -- | Build a codec for nonempty lists of values from a codec for a single value. -- --@@ -1319,14 +1344,67 @@ -- -- > scientificCodec = NumberCodec Nothing Nothing scientificCodec :: JSONCodec Scientific-scientificCodec = NumberCodec Nothing Nothing+scientificCodec = NumberCodec Nothing emptyBounds +-- | Codec for 'Integer' values+--+-- This codec does a bounds check for the range [-10^1024, 10^1024] it can safely parse very large numbers.+--+--+-- === Example usage+--+-- >>> toJSONVia integerCodec 5+-- Number 5.0+-- >>> toJSONVia integerCodec (-1000000000000)+-- Number (-1.0e12)+-- >>> JSON.parseMaybe (parseJSONVia integerCodec) (Number (-4.0))+-- Just (-4)+-- >>> JSON.parseMaybe (parseJSONVia integerCodec) (Number (scientific 1 100000000))+-- Nothing+--+--+-- ==== API Note+--+-- This is a forward-compatible version of 'IntegerCodec' without a name.+--+-- > scientificCodec = IntegerCodec Nothing Nothing+--+-- For a codec without this protection, see 'unsafeUnboundedIntegerCodec'.+integerCodec :: JSONCodec Integer+integerCodec = IntegerCodec Nothing emptyBounds++-- | A codec for 'Natural' values.+--+-- This codec does a bounds check for the range [0, 10^1024] it can safely parse very large numbers.+--+-- For a codec without this protection, see 'unsafeUnboundedNaturalCodec'.+--+-- === Example usage+--+-- >>> toJSONVia naturalCodec 5+-- Number 5.0+-- >>> toJSONVia naturalCodec (1000000000000)+-- Number 1.0e12+-- >>> JSON.parseMaybe (parseJSONVia naturalCodec) (Number 4.0)+-- Just 4+-- >>> JSON.parseMaybe (parseJSONVia naturalCodec) (Number (scientific 1 100000000))+-- Nothing+naturalCodec :: JSONCodec Natural+naturalCodec =+  dimapCodec fromIntegral fromIntegral $+    integerWithBoundsCodec+      ( Bounds+          { boundsLower = Just 0,+            boundsUpper = Nothing+          }+      )+ -- | Codec for 'Scientific' values with bounds -- -- -- === Example usage ----- >>> let c = scientificWithBoundsCodec NumberBounds {numberBoundsLower = 2, numberBoundsUpper = 4}+-- >>> let c = scientificWithBoundsCodec Bounds {boundsLower = Just 2, boundsUpper = Just 4} -- >>> toJSONVia c 3 -- Number 3.0 -- >>> toJSONVia c 5@@ -1353,10 +1431,33 @@ -- -- This is a forward-compatible version of 'NumberCodec' without a name. ----- > scientificWithBoundsCodec bounds = NumberCodec Nothing (Just bounds)-scientificWithBoundsCodec :: NumberBounds -> JSONCodec Scientific-scientificWithBoundsCodec bounds = NumberCodec Nothing (Just bounds)+-- > scientificWithBoundsCodec bounds = NumberCodec Nothing bounds+scientificWithBoundsCodec :: Bounds Scientific -> JSONCodec Scientific+scientificWithBoundsCodec bounds = NumberCodec Nothing bounds +-- | Codec for 'Integer' values with bounds+--+--+-- === Example usage+--+-- >>> let c = integerWithBoundsCodec Bounds {boundsLower = Just 2, boundsUpper = Just 4}+-- >>> toJSONVia c 3+-- Number 3.0+-- >>> toJSONVia c 5+-- Number 5.0+-- >>> JSON.parseMaybe (parseJSONVia c) (Number 3)+-- Just 3+-- >>> JSON.parseMaybe (parseJSONVia c) (Number 5)+-- Nothing+--+-- ==== API Note+--+-- This is a forward-compatible version of 'IntegerCodec' without a name.+--+-- > integerWithBoundsCodec bounds = IntegerCodec Nothing bounds+integerWithBoundsCodec :: Bounds Integer -> JSONCodec Integer+integerWithBoundsCodec bounds = IntegerCodec Nothing bounds+ -- | An object codec with a given name -- --@@ -1396,51 +1497,13 @@ -- Nothing boundedIntegralCodec :: forall i. (Integral i, Bounded i) => JSONCodec i boundedIntegralCodec =-  bimapCodec go fromIntegral $ scientificWithBoundsCodec (boundedIntegralNumberBounds @i)-  where-    go s = case Scientific.toBoundedInteger s of-      Nothing -> Left $ "Number did not fit into bounded integer: " <> show s-      Just i -> Right i+  dimapCodec fromIntegral fromIntegral $ integerWithBoundsCodec (boundedIntegralBounds @i)  -- | 'NumberBounds' for a bounded integral type. ----- You can call this using @TypeApplications@: @boundedIntegralNumberBounds @Word@-boundedIntegralNumberBounds :: forall i. (Integral i, Bounded i) => NumberBounds-boundedIntegralNumberBounds =-  NumberBounds-    { numberBoundsLower = fromIntegral (minBound :: i),-      numberBoundsUpper = fromIntegral (maxBound :: i)-    }---- | A safe codec for 'Integer'.------ This codec does a bounds check for the range [-10^1024, 10^1024] it can safely parse very large numbers.------ For a codec without this protection, see 'unsafeUnboundedIntegerCodec'.------ === Example usage------ >>> toJSONVia integerCodec 5--- Number 5.0--- >>> toJSONVia integerCodec (-1000000000000)--- Number (-1.0e12)--- >>> JSON.parseMaybe (parseJSONVia integerCodec) (Number (-4.0))--- Just (-4)--- >>> JSON.parseMaybe (parseJSONVia integerCodec) (Number (scientific 1 100000000))--- Nothing-integerCodec :: JSONCodec Integer-integerCodec =-  bimapCodec go fromIntegral $-    scientificWithBoundsCodec-      ( NumberBounds-          { numberBoundsLower = scientific (-1) 1024,-            numberBoundsUpper = scientific 1 1024-          }-      )-  where-    go s = case Scientific.floatingOrInteger s :: Either Float Integer of-      Right i -> Right i-      Left _ -> Left ("Number is not an integer: " <> show s)+-- You can call this using @TypeApplications@: @boundedIntegralBounds @Word@+boundedIntegralBounds :: forall i. (Integral i, Bounded i) => Bounds Integer+boundedIntegralBounds = fromIntegral <$> boundedBounds @i  -- | This is an unsafe (unchecked) version of 'integerCodec'. unsafeUnboundedIntegerCodec :: JSONCodec Integer@@ -1448,36 +1511,6 @@   bimapCodec go fromIntegral scientificCodec   where     go s = case Scientific.floatingOrInteger s :: Either Float Integer of-      Right i -> Right i-      Left _ -> Left ("Number is not an integer: " <> show s)---- | A safe codec for 'Natural'.------ This codec does a bounds check for the range [0, 10^1024] it can safely parse very large numbers.------ For a codec without this protection, see 'unsafeUnboundedNaturalCodec'.------ === Example usage------ >>> toJSONVia naturalCodec 5--- Number 5.0--- >>> toJSONVia naturalCodec (1000000000000)--- Number 1.0e12--- >>> JSON.parseMaybe (parseJSONVia naturalCodec) (Number 4.0)--- Just 4--- >>> JSON.parseMaybe (parseJSONVia naturalCodec) (Number (scientific 1 100000000))--- Nothing-naturalCodec :: JSONCodec Natural-naturalCodec =-  bimapCodec go fromIntegral $-    scientificWithBoundsCodec-      ( NumberBounds-          { numberBoundsLower = scientific 0 0,-            numberBoundsUpper = scientific 1 1024-          }-      )-  where-    go s = case Scientific.floatingOrInteger s :: Either Float Natural of       Right i -> Right i       Left _ -> Left ("Number is not an integer: " <> show s)