{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}

module Cardano.Chain.Slotting.SlotNumber (
  SlotNumber (..),
  addSlotCount,
  -- deprecated
  subSlotCount,
)
where

import Cardano.Chain.Slotting.SlotCount (SlotCount (..))
import Cardano.Ledger.Binary (
  DecCBOR (..),
  EncCBOR (..),
  FromCBOR (..),
  ToCBOR (..),
  fromByronCBOR,
  toByronCBOR,
 )
import Cardano.Prelude
import qualified Data.Aeson as Aeson
import Formatting (bprint, int)
import qualified Formatting.Buildable as B
import NoThunks.Class (NoThunks (..))
import Text.JSON.Canonical (FromJSON (..), ToJSON (..))

-- | 'SlotNumber' is an absolute slot number from the beginning of time
--
--   'SlotNumber' is held in a 'Word64'. Assuming a slot every 20 seconds, 'Word64'
--   is sufficient for slot indices for 10^13 years.
newtype SlotNumber = SlotNumber
  { SlotNumber -> Word64
unSlotNumber :: Word64
  }
  deriving (SlotNumber -> SlotNumber -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SlotNumber -> SlotNumber -> Bool
$c/= :: SlotNumber -> SlotNumber -> Bool
== :: SlotNumber -> SlotNumber -> Bool
$c== :: SlotNumber -> SlotNumber -> Bool
Eq, forall x. Rep SlotNumber x -> SlotNumber
forall x. SlotNumber -> Rep SlotNumber x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep SlotNumber x -> SlotNumber
$cfrom :: forall x. SlotNumber -> Rep SlotNumber x
Generic, Eq SlotNumber
SlotNumber -> SlotNumber -> Bool
SlotNumber -> SlotNumber -> Ordering
SlotNumber -> SlotNumber -> SlotNumber
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SlotNumber -> SlotNumber -> SlotNumber
$cmin :: SlotNumber -> SlotNumber -> SlotNumber
max :: SlotNumber -> SlotNumber -> SlotNumber
$cmax :: SlotNumber -> SlotNumber -> SlotNumber
>= :: SlotNumber -> SlotNumber -> Bool
$c>= :: SlotNumber -> SlotNumber -> Bool
> :: SlotNumber -> SlotNumber -> Bool
$c> :: SlotNumber -> SlotNumber -> Bool
<= :: SlotNumber -> SlotNumber -> Bool
$c<= :: SlotNumber -> SlotNumber -> Bool
< :: SlotNumber -> SlotNumber -> Bool
$c< :: SlotNumber -> SlotNumber -> Bool
compare :: SlotNumber -> SlotNumber -> Ordering
$ccompare :: SlotNumber -> SlotNumber -> Ordering
Ord, Int -> SlotNumber -> ShowS
[SlotNumber] -> ShowS
SlotNumber -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SlotNumber] -> ShowS
$cshowList :: [SlotNumber] -> ShowS
show :: SlotNumber -> String
$cshow :: SlotNumber -> String
showsPrec :: Int -> SlotNumber -> ShowS
$cshowsPrec :: Int -> SlotNumber -> ShowS
Show)
  deriving newtype (Integer -> SlotNumber
SlotNumber -> SlotNumber
SlotNumber -> SlotNumber -> SlotNumber
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> SlotNumber
$cfromInteger :: Integer -> SlotNumber
signum :: SlotNumber -> SlotNumber
$csignum :: SlotNumber -> SlotNumber
abs :: SlotNumber -> SlotNumber
$cabs :: SlotNumber -> SlotNumber
negate :: SlotNumber -> SlotNumber
$cnegate :: SlotNumber -> SlotNumber
* :: SlotNumber -> SlotNumber -> SlotNumber
$c* :: SlotNumber -> SlotNumber -> SlotNumber
- :: SlotNumber -> SlotNumber -> SlotNumber
$c- :: SlotNumber -> SlotNumber -> SlotNumber
+ :: SlotNumber -> SlotNumber -> SlotNumber
$c+ :: SlotNumber -> SlotNumber -> SlotNumber
Num)
  deriving anyclass (SlotNumber -> ()
forall a. (a -> ()) -> NFData a
rnf :: SlotNumber -> ()
$crnf :: SlotNumber -> ()
NFData, Context -> SlotNumber -> IO (Maybe ThunkInfo)
Proxy SlotNumber -> String
forall a.
(Context -> a -> IO (Maybe ThunkInfo))
-> (Context -> a -> IO (Maybe ThunkInfo))
-> (Proxy a -> String)
-> NoThunks a
showTypeOf :: Proxy SlotNumber -> String
$cshowTypeOf :: Proxy SlotNumber -> String
wNoThunks :: Context -> SlotNumber -> IO (Maybe ThunkInfo)
$cwNoThunks :: Context -> SlotNumber -> IO (Maybe ThunkInfo)
noThunks :: Context -> SlotNumber -> IO (Maybe ThunkInfo)
$cnoThunks :: Context -> SlotNumber -> IO (Maybe ThunkInfo)
NoThunks)

-- Used for debugging purposes only
instance Aeson.ToJSON SlotNumber

instance ToCBOR SlotNumber where
  toCBOR :: SlotNumber -> Encoding
toCBOR = forall a. EncCBOR a => a -> Encoding
toByronCBOR

instance FromCBOR SlotNumber where
  fromCBOR :: forall s. Decoder s SlotNumber
fromCBOR = forall a s. DecCBOR a => Decoder s a
fromByronCBOR

instance EncCBOR SlotNumber where
  encCBOR :: SlotNumber -> Encoding
encCBOR = forall a. EncCBOR a => a -> Encoding
encCBOR forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlotNumber -> Word64
unSlotNumber
  encodedSizeExpr :: (forall t. EncCBOR t => Proxy t -> Size)
-> Proxy SlotNumber -> Size
encodedSizeExpr forall t. EncCBOR t => Proxy t -> Size
size = forall a.
EncCBOR a =>
(forall t. EncCBOR t => Proxy t -> Size) -> Proxy a -> Size
encodedSizeExpr forall t. EncCBOR t => Proxy t -> Size
size forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap SlotNumber -> Word64
unSlotNumber

instance DecCBOR SlotNumber where
  decCBOR :: forall s. Decoder s SlotNumber
decCBOR = Word64 -> SlotNumber
SlotNumber forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a s. DecCBOR a => Decoder s a
decCBOR

instance Monad m => ToJSON m SlotNumber where
  toJSON :: SlotNumber -> m JSValue
toJSON = forall (m :: * -> *) a. ToJSON m a => a -> m JSValue
toJSON forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. SlotNumber -> Word64
unSlotNumber

instance MonadError SchemaError m => FromJSON m SlotNumber where
  fromJSON :: JSValue -> m SlotNumber
fromJSON JSValue
val = do
    Word64
number <- forall (m :: * -> *) a. FromJSON m a => JSValue -> m a
fromJSON JSValue
val
    forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Word64 -> SlotNumber
SlotNumber Word64
number

instance B.Buildable SlotNumber where
  build :: SlotNumber -> Builder
build SlotNumber
s = forall a. Format Builder a -> a
bprint forall a r. Integral a => Format r (a -> r)
int (SlotNumber -> Word64
unSlotNumber SlotNumber
s)

-- | Increase a 'SlotNumber' by 'SlotCount'
addSlotCount :: SlotCount -> SlotNumber -> SlotNumber
addSlotCount :: SlotCount -> SlotNumber -> SlotNumber
addSlotCount (SlotCount Word64
a) (SlotNumber Word64
b)
  | Word64
a forall a. Ord a => a -> a -> Bool
<= forall a. Bounded a => a
maxBound forall a. Num a => a -> a -> a
- Word64
b = Word64 -> SlotNumber
SlotNumber forall a b. (a -> b) -> a -> b
$ Word64
a forall a. Num a => a -> a -> a
+ Word64
b
  | Bool
otherwise = Word64 -> SlotNumber
SlotNumber forall a. Bounded a => a
maxBound

-- | Decrease a 'SlotNumber' by 'SlotCount', going no lower than 0
{-# DEPRECATED subSlotCount "this function is dangerous and can usually be replaced by addSlotCount" #-}
subSlotCount :: SlotCount -> SlotNumber -> SlotNumber
subSlotCount :: SlotCount -> SlotNumber -> SlotNumber
subSlotCount (SlotCount Word64
a) (SlotNumber Word64
b) =
  if Word64
a forall a. Ord a => a -> a -> Bool
> Word64
b then Word64 -> SlotNumber
SlotNumber Word64
0 else Word64 -> SlotNumber
SlotNumber (Word64
b forall a. Num a => a -> a -> a
- Word64
a)