-- 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