morley-1.3.0: src/Util/Positive.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
-- | Definition of 'Positive' type and related utilities.
module Util.Positive
( Positive (..)
, mkPositive
, lengthNE
, replicateNE
) where
import Data.Aeson (FromJSON, ToJSON)
import Data.Data (Data)
import Fmt (Buildable, pretty)
import Util.Instances ()
-- | Integer values starting from 1.
--
-- We define our own datatype in order to have 'Data' instance for it,
-- which can not be derived for third-party types without exported constructor.
newtype Positive = PositiveUnsafe { unPositive :: Natural }
deriving stock (Eq, Ord, Data, Generic)
deriving newtype (Show, Buildable, ToJSON, FromJSON)
instance NFData Positive
mkPositive :: (Integral i, Buildable i) => i -> Either Text Positive
mkPositive a
| a > 0 = Right $ PositiveUnsafe (fromIntegral a)
| otherwise = Left $ "Number is not positive: " <> pretty a
-- | Count length of non-empty list.
lengthNE :: NonEmpty a -> Positive
lengthNE = PositiveUnsafe . fromIntegral . length
-- | Produce a non empty list consisting of the given value.
replicateNE :: Positive -> a -> NonEmpty a
replicateNE (PositiveUnsafe i) a = a :| replicate (fromIntegral i - 1) a