{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- |
-- Module      : Test.Hspec.BenchGolden.Types
-- Description : Core types for benchmark golden testing
-- Copyright   : (c) 2026
-- License     : MIT
-- Maintainer  : your.email@example.com
--
-- This module defines the core data types used by the golds-gym framework:
--
-- * 'BenchGolden' - Configuration for a benchmark golden test
-- * 'BenchConfig' - Configurable benchmark parameters
-- * 'GoldenStats' - Statistics stored in golden files
-- * 'ArchConfig' - Machine architecture identification
-- * 'BenchResult' - Result of comparing benchmark against golden

module Test.Hspec.BenchGolden.Types
  ( -- * Benchmark Configuration
    BenchGolden(..)
  , BenchConfig(..)
  , defaultBenchConfig

    -- * Golden File Statistics
  , GoldenStats(..)

    -- * Architecture Configuration
  , ArchConfig(..)

    -- * Benchmark Results
  , BenchResult(..)
  , Warning(..)
  ) where

import Data.Aeson
import Data.Text (Text)
import Data.Time (UTCTime)
import GHC.Generics (Generic)

-- | Configuration for a single benchmark golden test.
data BenchGolden = BenchGolden
  { BenchGolden -> String
benchName   :: !String
    -- ^ Name of the benchmark (used for golden file naming)
  , BenchGolden -> IO ()
benchAction :: !(IO ())
    -- ^ The IO action to benchmark
  , BenchGolden -> BenchConfig
benchConfig :: !BenchConfig
    -- ^ Configuration parameters
  }

-- | Configurable parameters for benchmark execution and comparison.
data BenchConfig = BenchConfig
  { BenchConfig -> Int
iterations            :: !Int
    -- ^ Number of benchmark iterations to run
  , BenchConfig -> Int
warmupIterations      :: !Int
    -- ^ Number of warm-up iterations (discarded before measurement)
  , BenchConfig -> Double
tolerancePercent      :: !Double
    -- ^ Allowed deviation in mean time (as percentage, e.g., 15.0 = ±15%)
  , BenchConfig -> Maybe Double
absoluteToleranceMs   :: !(Maybe Double)
    -- ^ Minimum absolute tolerance in milliseconds (e.g., 0.01 = 10 microseconds).
    --   When set, benchmarks pass if EITHER the percentage difference is within
    --   'tolerancePercent' OR the absolute time difference is within this threshold.
    --   This prevents false failures for extremely fast operations (< 1ms) where
    --   measurement noise causes large percentage variations despite negligible
    --   absolute time differences. Set to 'Nothing' to disable (percentage-only).
  , BenchConfig -> Bool
warnOnVarianceChange  :: !Bool
    -- ^ Whether to emit warnings when stddev changes significantly
  , BenchConfig -> Double
varianceTolerancePercent :: !Double
    -- ^ Allowed deviation in stddev (as percentage)
  , BenchConfig -> String
outputDir             :: !FilePath
    -- ^ Directory for storing golden files
  , BenchConfig -> Bool
failOnFirstRun        :: !Bool
    -- ^ Whether to fail if no golden file exists yet
  , BenchConfig -> Bool
useRobustStatistics   :: !Bool
    -- ^ Use robust statistics (trimmed mean, MAD) instead of mean/stddev
  , BenchConfig -> Double
trimPercent           :: !Double
    -- ^ Percentage to trim from each tail for trimmed mean (e.g., 10.0 = 10%)
  , BenchConfig -> Double
outlierThreshold      :: !Double
    -- ^ MAD multiplier for outlier detection (e.g., 3.0 = 3 MADs from median)
  } deriving (Int -> BenchConfig -> ShowS
[BenchConfig] -> ShowS
BenchConfig -> String
(Int -> BenchConfig -> ShowS)
-> (BenchConfig -> String)
-> ([BenchConfig] -> ShowS)
-> Show BenchConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BenchConfig -> ShowS
showsPrec :: Int -> BenchConfig -> ShowS
$cshow :: BenchConfig -> String
show :: BenchConfig -> String
$cshowList :: [BenchConfig] -> ShowS
showList :: [BenchConfig] -> ShowS
Show, BenchConfig -> BenchConfig -> Bool
(BenchConfig -> BenchConfig -> Bool)
-> (BenchConfig -> BenchConfig -> Bool) -> Eq BenchConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BenchConfig -> BenchConfig -> Bool
== :: BenchConfig -> BenchConfig -> Bool
$c/= :: BenchConfig -> BenchConfig -> Bool
/= :: BenchConfig -> BenchConfig -> Bool
Eq, (forall x. BenchConfig -> Rep BenchConfig x)
-> (forall x. Rep BenchConfig x -> BenchConfig)
-> Generic BenchConfig
forall x. Rep BenchConfig x -> BenchConfig
forall x. BenchConfig -> Rep BenchConfig x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BenchConfig -> Rep BenchConfig x
from :: forall x. BenchConfig -> Rep BenchConfig x
$cto :: forall x. Rep BenchConfig x -> BenchConfig
to :: forall x. Rep BenchConfig x -> BenchConfig
Generic)

-- | Default benchmark configuration with sensible defaults.
--
-- * 100 iterations
-- * 5 warm-up iterations
-- * 15% tolerance on mean time
-- * 0.01 ms (10 microseconds) absolute tolerance - prevents false failures for fast operations
-- * Variance warnings enabled at 50% tolerance
-- * Output to @.golden/@ directory
-- * Success on first run (creates baseline)
--
-- = Hybrid Tolerance Strategy
--
-- The default configuration uses BOTH percentage and absolute tolerance:
--
-- * Benchmarks pass if mean time is within ±15% OR within ±0.01ms
-- * This prevents measurement noise from failing fast operations (< 1ms)
-- * For slower operations (> 1ms), percentage tolerance dominates
--
-- Set @absoluteToleranceMs = Nothing@ for percentage-only comparison.
defaultBenchConfig :: BenchConfig
defaultBenchConfig :: BenchConfig
defaultBenchConfig = BenchConfig
  { iterations :: Int
iterations            = Int
100
  , warmupIterations :: Int
warmupIterations      = Int
5
  , tolerancePercent :: Double
tolerancePercent      = Double
15.0
  , absoluteToleranceMs :: Maybe Double
absoluteToleranceMs   = Double -> Maybe Double
forall a. a -> Maybe a
Just Double
0.01  -- 10 microseconds
  , warnOnVarianceChange :: Bool
warnOnVarianceChange  = Bool
True
  , varianceTolerancePercent :: Double
varianceTolerancePercent = Double
50.0
  , outputDir :: String
outputDir             = String
".golden"
  , failOnFirstRun :: Bool
failOnFirstRun        = Bool
False
  , useRobustStatistics :: Bool
useRobustStatistics   = Bool
False
  , trimPercent :: Double
trimPercent           = Double
10.0
  , outlierThreshold :: Double
outlierThreshold      = Double
3.0
  }

-- | Statistics stored in golden files.
--
-- These represent the baseline performance characteristics of a benchmark
-- on a specific architecture.
data GoldenStats = GoldenStats
  { GoldenStats -> Double
statsMean        :: !Double
    -- ^ Mean execution time in milliseconds
  , GoldenStats -> Double
statsStddev      :: !Double
    -- ^ Standard deviation in milliseconds
  , GoldenStats -> Double
statsMedian      :: !Double
    -- ^ Median execution time in milliseconds
  , GoldenStats -> Double
statsMin         :: !Double
    -- ^ Minimum execution time in milliseconds
  , GoldenStats -> Double
statsMax         :: !Double
    -- ^ Maximum execution time in milliseconds
  , GoldenStats -> [(Int, Double)]
statsPercentiles :: ![(Int, Double)]
    -- ^ Percentile values (e.g., [(50, 1.2), (90, 1.5), (99, 1.8)])
  , GoldenStats -> Text
statsArch        :: !Text
    -- ^ Architecture identifier
  , GoldenStats -> UTCTime
statsTimestamp   :: !UTCTime
    -- ^ When this baseline was recorded
  , GoldenStats -> Double
statsTrimmedMean :: !Double
    -- ^ Trimmed mean (with tails removed) in milliseconds
  , GoldenStats -> Double
statsMAD         :: !Double
    -- ^ Median absolute deviation in milliseconds
  , GoldenStats -> Double
statsIQR         :: !Double
    -- ^ Interquartile range (Q3 - Q1) in milliseconds
  , GoldenStats -> [Double]
statsOutliers    :: ![Double]
    -- ^ List of detected outlier timings in milliseconds
  } deriving (Int -> GoldenStats -> ShowS
[GoldenStats] -> ShowS
GoldenStats -> String
(Int -> GoldenStats -> ShowS)
-> (GoldenStats -> String)
-> ([GoldenStats] -> ShowS)
-> Show GoldenStats
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GoldenStats -> ShowS
showsPrec :: Int -> GoldenStats -> ShowS
$cshow :: GoldenStats -> String
show :: GoldenStats -> String
$cshowList :: [GoldenStats] -> ShowS
showList :: [GoldenStats] -> ShowS
Show, GoldenStats -> GoldenStats -> Bool
(GoldenStats -> GoldenStats -> Bool)
-> (GoldenStats -> GoldenStats -> Bool) -> Eq GoldenStats
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: GoldenStats -> GoldenStats -> Bool
== :: GoldenStats -> GoldenStats -> Bool
$c/= :: GoldenStats -> GoldenStats -> Bool
/= :: GoldenStats -> GoldenStats -> Bool
Eq, (forall x. GoldenStats -> Rep GoldenStats x)
-> (forall x. Rep GoldenStats x -> GoldenStats)
-> Generic GoldenStats
forall x. Rep GoldenStats x -> GoldenStats
forall x. GoldenStats -> Rep GoldenStats x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. GoldenStats -> Rep GoldenStats x
from :: forall x. GoldenStats -> Rep GoldenStats x
$cto :: forall x. Rep GoldenStats x -> GoldenStats
to :: forall x. Rep GoldenStats x -> GoldenStats
Generic)

-- | Machine architecture configuration.
--
-- Used to generate unique identifiers for golden file directories,
-- ensuring benchmarks are only compared against equivalent hardware.
data ArchConfig = ArchConfig
  { ArchConfig -> Text
archId    :: !Text
    -- ^ Unique identifier (e.g., "aarch64-darwin-Apple_M1")
  , ArchConfig -> Text
archOS    :: !Text
    -- ^ Operating system (e.g., "darwin", "linux")
  , ArchConfig -> Text
archCPU   :: !Text
    -- ^ CPU architecture (e.g., "aarch64", "x86_64")
  , ArchConfig -> Maybe Text
archModel :: !(Maybe Text)
    -- ^ CPU model if available (e.g., "Apple M1", "Intel Core i7")
  } deriving (Int -> ArchConfig -> ShowS
[ArchConfig] -> ShowS
ArchConfig -> String
(Int -> ArchConfig -> ShowS)
-> (ArchConfig -> String)
-> ([ArchConfig] -> ShowS)
-> Show ArchConfig
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ArchConfig -> ShowS
showsPrec :: Int -> ArchConfig -> ShowS
$cshow :: ArchConfig -> String
show :: ArchConfig -> String
$cshowList :: [ArchConfig] -> ShowS
showList :: [ArchConfig] -> ShowS
Show, ArchConfig -> ArchConfig -> Bool
(ArchConfig -> ArchConfig -> Bool)
-> (ArchConfig -> ArchConfig -> Bool) -> Eq ArchConfig
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ArchConfig -> ArchConfig -> Bool
== :: ArchConfig -> ArchConfig -> Bool
$c/= :: ArchConfig -> ArchConfig -> Bool
/= :: ArchConfig -> ArchConfig -> Bool
Eq, (forall x. ArchConfig -> Rep ArchConfig x)
-> (forall x. Rep ArchConfig x -> ArchConfig) -> Generic ArchConfig
forall x. Rep ArchConfig x -> ArchConfig
forall x. ArchConfig -> Rep ArchConfig x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ArchConfig -> Rep ArchConfig x
from :: forall x. ArchConfig -> Rep ArchConfig x
$cto :: forall x. Rep ArchConfig x -> ArchConfig
to :: forall x. Rep ArchConfig x -> ArchConfig
Generic)

-- | Result of running a benchmark and comparing against golden.
data BenchResult
  = FirstRun !GoldenStats
    -- ^ No golden file existed; baseline created
  | Pass !GoldenStats !GoldenStats ![Warning]
    -- ^ Benchmark passed (golden stats, actual stats, warnings)
  | Regression !GoldenStats !GoldenStats !Double !Double !(Maybe Double)
    -- ^ Performance regression (golden, actual, percent change, tolerance, absolute tolerance)
  | Improvement !GoldenStats !GoldenStats !Double !Double !(Maybe Double)
    -- ^ Performance improvement (golden, actual, percent change, tolerance, absolute tolerance)
  deriving (Int -> BenchResult -> ShowS
[BenchResult] -> ShowS
BenchResult -> String
(Int -> BenchResult -> ShowS)
-> (BenchResult -> String)
-> ([BenchResult] -> ShowS)
-> Show BenchResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BenchResult -> ShowS
showsPrec :: Int -> BenchResult -> ShowS
$cshow :: BenchResult -> String
show :: BenchResult -> String
$cshowList :: [BenchResult] -> ShowS
showList :: [BenchResult] -> ShowS
Show, BenchResult -> BenchResult -> Bool
(BenchResult -> BenchResult -> Bool)
-> (BenchResult -> BenchResult -> Bool) -> Eq BenchResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BenchResult -> BenchResult -> Bool
== :: BenchResult -> BenchResult -> Bool
$c/= :: BenchResult -> BenchResult -> Bool
/= :: BenchResult -> BenchResult -> Bool
Eq)

-- | Warnings that may be emitted during benchmark comparison.
data Warning
  = VarianceIncreased !Double !Double !Double !Double
    -- ^ Stddev increased (golden, actual, percent change, tolerance)
  | VarianceDecreased !Double !Double !Double !Double
    -- ^ Stddev decreased significantly (golden, actual, percent change, tolerance)
  | HighVariance !Double
    -- ^ Current run has unusually high variance
  | OutliersDetected !Int ![Double]
    -- ^ Outliers detected (count, list of outlier timings)
  deriving (Int -> Warning -> ShowS
[Warning] -> ShowS
Warning -> String
(Int -> Warning -> ShowS)
-> (Warning -> String) -> ([Warning] -> ShowS) -> Show Warning
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Warning -> ShowS
showsPrec :: Int -> Warning -> ShowS
$cshow :: Warning -> String
show :: Warning -> String
$cshowList :: [Warning] -> ShowS
showList :: [Warning] -> ShowS
Show, Warning -> Warning -> Bool
(Warning -> Warning -> Bool)
-> (Warning -> Warning -> Bool) -> Eq Warning
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Warning -> Warning -> Bool
== :: Warning -> Warning -> Bool
$c/= :: Warning -> Warning -> Bool
/= :: Warning -> Warning -> Bool
Eq)

-- JSON instances for GoldenStats (stored in golden files)

instance ToJSON GoldenStats where
  toJSON :: GoldenStats -> Value
toJSON GoldenStats{Double
[Double]
[(Int, Double)]
Text
UTCTime
statsMean :: GoldenStats -> Double
statsStddev :: GoldenStats -> Double
statsMedian :: GoldenStats -> Double
statsMin :: GoldenStats -> Double
statsMax :: GoldenStats -> Double
statsPercentiles :: GoldenStats -> [(Int, Double)]
statsArch :: GoldenStats -> Text
statsTimestamp :: GoldenStats -> UTCTime
statsTrimmedMean :: GoldenStats -> Double
statsMAD :: GoldenStats -> Double
statsIQR :: GoldenStats -> Double
statsOutliers :: GoldenStats -> [Double]
statsMean :: Double
statsStddev :: Double
statsMedian :: Double
statsMin :: Double
statsMax :: Double
statsPercentiles :: [(Int, Double)]
statsArch :: Text
statsTimestamp :: UTCTime
statsTrimmedMean :: Double
statsMAD :: Double
statsIQR :: Double
statsOutliers :: [Double]
..} = [Pair] -> Value
object
    [ Key
"mean"        Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsMean
    , Key
"stddev"      Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsStddev
    , Key
"median"      Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsMedian
    , Key
"min"         Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsMin
    , Key
"max"         Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsMax
    , Key
"percentiles" Key -> [(Int, Double)] -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= [(Int, Double)]
statsPercentiles
    , Key
"architecture" Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
statsArch
    , Key
"timestamp"   Key -> UTCTime -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= UTCTime
statsTimestamp
    , Key
"trimmedMean" Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsTrimmedMean
    , Key
"mad"         Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsMAD
    , Key
"iqr"         Key -> Double -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Double
statsIQR
    , Key
"outliers"    Key -> [Double] -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= [Double]
statsOutliers
    ]

instance FromJSON GoldenStats where
  parseJSON :: Value -> Parser GoldenStats
parseJSON = String
-> (Object -> Parser GoldenStats) -> Value -> Parser GoldenStats
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"GoldenStats" ((Object -> Parser GoldenStats) -> Value -> Parser GoldenStats)
-> (Object -> Parser GoldenStats) -> Value -> Parser GoldenStats
forall a b. (a -> b) -> a -> b
$ \Object
v -> Double
-> Double
-> Double
-> Double
-> Double
-> [(Int, Double)]
-> Text
-> UTCTime
-> Double
-> Double
-> Double
-> [Double]
-> GoldenStats
GoldenStats
    (Double
 -> Double
 -> Double
 -> Double
 -> Double
 -> [(Int, Double)]
 -> Text
 -> UTCTime
 -> Double
 -> Double
 -> Double
 -> [Double]
 -> GoldenStats)
-> Parser Double
-> Parser
     (Double
      -> Double
      -> Double
      -> Double
      -> [(Int, Double)]
      -> Text
      -> UTCTime
      -> Double
      -> Double
      -> Double
      -> [Double]
      -> GoldenStats)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"mean"
    Parser
  (Double
   -> Double
   -> Double
   -> Double
   -> [(Int, Double)]
   -> Text
   -> UTCTime
   -> Double
   -> Double
   -> Double
   -> [Double]
   -> GoldenStats)
-> Parser Double
-> Parser
     (Double
      -> Double
      -> Double
      -> [(Int, Double)]
      -> Text
      -> UTCTime
      -> Double
      -> Double
      -> Double
      -> [Double]
      -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"stddev"
    Parser
  (Double
   -> Double
   -> Double
   -> [(Int, Double)]
   -> Text
   -> UTCTime
   -> Double
   -> Double
   -> Double
   -> [Double]
   -> GoldenStats)
-> Parser Double
-> Parser
     (Double
      -> Double
      -> [(Int, Double)]
      -> Text
      -> UTCTime
      -> Double
      -> Double
      -> Double
      -> [Double]
      -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"median"
    Parser
  (Double
   -> Double
   -> [(Int, Double)]
   -> Text
   -> UTCTime
   -> Double
   -> Double
   -> Double
   -> [Double]
   -> GoldenStats)
-> Parser Double
-> Parser
     (Double
      -> [(Int, Double)]
      -> Text
      -> UTCTime
      -> Double
      -> Double
      -> Double
      -> [Double]
      -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"min"
    Parser
  (Double
   -> [(Int, Double)]
   -> Text
   -> UTCTime
   -> Double
   -> Double
   -> Double
   -> [Double]
   -> GoldenStats)
-> Parser Double
-> Parser
     ([(Int, Double)]
      -> Text
      -> UTCTime
      -> Double
      -> Double
      -> Double
      -> [Double]
      -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"max"
    Parser
  ([(Int, Double)]
   -> Text
   -> UTCTime
   -> Double
   -> Double
   -> Double
   -> [Double]
   -> GoldenStats)
-> Parser [(Int, Double)]
-> Parser
     (Text
      -> UTCTime
      -> Double
      -> Double
      -> Double
      -> [Double]
      -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser [(Int, Double)]
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"percentiles"
    Parser
  (Text
   -> UTCTime
   -> Double
   -> Double
   -> Double
   -> [Double]
   -> GoldenStats)
-> Parser Text
-> Parser
     (UTCTime -> Double -> Double -> Double -> [Double] -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"architecture"
    Parser
  (UTCTime -> Double -> Double -> Double -> [Double] -> GoldenStats)
-> Parser UTCTime
-> Parser (Double -> Double -> Double -> [Double] -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser UTCTime
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"timestamp"
    Parser (Double -> Double -> Double -> [Double] -> GoldenStats)
-> Parser Double
-> Parser (Double -> Double -> [Double] -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"trimmedMean"
    Parser (Double -> Double -> [Double] -> GoldenStats)
-> Parser Double -> Parser (Double -> [Double] -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"mad"
    Parser (Double -> [Double] -> GoldenStats)
-> Parser Double -> Parser ([Double] -> GoldenStats)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Double
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"iqr"
    Parser ([Double] -> GoldenStats)
-> Parser [Double] -> Parser GoldenStats
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser [Double]
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"outliers"

instance ToJSON ArchConfig where
  toJSON :: ArchConfig -> Value
toJSON ArchConfig{Maybe Text
Text
archId :: ArchConfig -> Text
archOS :: ArchConfig -> Text
archCPU :: ArchConfig -> Text
archModel :: ArchConfig -> Maybe Text
archId :: Text
archOS :: Text
archCPU :: Text
archModel :: Maybe Text
..} = [Pair] -> Value
object
    [ Key
"id"    Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
archId
    , Key
"os"    Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
archOS
    , Key
"cpu"   Key -> Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Text
archCPU
    , Key
"model" Key -> Maybe Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Text
archModel
    ]

instance FromJSON ArchConfig where
  parseJSON :: Value -> Parser ArchConfig
parseJSON = String
-> (Object -> Parser ArchConfig) -> Value -> Parser ArchConfig
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"ArchConfig" ((Object -> Parser ArchConfig) -> Value -> Parser ArchConfig)
-> (Object -> Parser ArchConfig) -> Value -> Parser ArchConfig
forall a b. (a -> b) -> a -> b
$ \Object
v -> Text -> Text -> Text -> Maybe Text -> ArchConfig
ArchConfig
    (Text -> Text -> Text -> Maybe Text -> ArchConfig)
-> Parser Text -> Parser (Text -> Text -> Maybe Text -> ArchConfig)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id"
    Parser (Text -> Text -> Maybe Text -> ArchConfig)
-> Parser Text -> Parser (Text -> Maybe Text -> ArchConfig)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"os"
    Parser (Text -> Maybe Text -> ArchConfig)
-> Parser Text -> Parser (Maybe Text -> ArchConfig)
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"cpu"
    Parser (Maybe Text -> ArchConfig)
-> Parser (Maybe Text) -> Parser ArchConfig
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser (Maybe Text)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"model"