diff --git a/src/Data/Aeson/Types/FromJSON.hs b/src/Data/Aeson/Types/FromJSON.hs index 3f766e43..0f90efd8 100644 --- a/src/Data/Aeson/Types/FromJSON.hs +++ b/src/Data/Aeson/Types/FromJSON.hs @@ -93,6 +93,7 @@ import Data.Aeson.Types.Internal import Data.Aeson.Decoding.ByteString.Lazy import Data.Aeson.Decoding.Conversion (unResult, toResultValue, lbsSpace) import Data.Bits (unsafeShiftR) +import Data.Complex (Complex(..)) import Data.Fixed (Fixed, HasResolution (resolution), Nano) import Data.Functor.Compose (Compose(..)) import Data.Functor.Identity (Identity(..)) @@ -1720,6 +1721,14 @@ instance (FromJSON a, Integral a) => FromJSON (Ratio a) where then fail "Ratio denominator was 0" else pure $ numerator % denominator +instance FromJSON a => FromJSON (Complex a) where + parseJSON = withArray "Complex" $ \c -> + let n = V.length c + in if n == 2 + then (:+) <$> parseJSONElemAtIndex parseJSON 0 c + <*> parseJSONElemAtIndex parseJSON 1 c + else fail $ "cannot unpack array of length " ++ show n ++ "into a Complex" + -- | This instance includes a bounds check to prevent maliciously -- large inputs to fill up the memory of the target system. You can -- newtype 'Scientific' and provide your own instance using diff --git a/src/Data/Aeson/Types/ToJSON.hs b/src/Data/Aeson/Types/ToJSON.hs index 7de88759..ce071c32 100644 --- a/src/Data/Aeson/Types/ToJSON.hs +++ b/src/Data/Aeson/Types/ToJSON.hs @@ -67,6 +67,7 @@ import Data.Aeson.Types.Internal import qualified Data.Aeson.Key as Key import qualified Data.Aeson.KeyMap as KM import Data.Bits (unsafeShiftR) +import Data.Complex (Complex(..)) import Data.DList (DList) import Data.Fixed (Fixed, HasResolution, Nano) import Data.Foldable (toList) @@ -1421,6 +1422,16 @@ instance (ToJSON a, Integral a) => ToJSON (Ratio a) where "numerator" .= numerator r <> "denominator" .= denominator r +instance ToJSON a => ToJSON (Complex a) where + toJSON (i :+ q) = Array $ V.create $ do + mv <- VM.unsafeNew 2 + VM.unsafeWrite mv 0 (toJSON i) + VM.unsafeWrite mv 1 (toJSON q) + return mv + toEncoding (i :+ q) = E.list id + [ toEncoding i + , toEncoding q + ] instance HasResolution a => ToJSON (Fixed a) where toJSON = Number . realToFrac