morley-1.16.3: src/Morley/Util/Positive.hs
-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA
-- | Definition of 'Positive' type and related utilities.
module Morley.Util.Positive
( Positive (..)
, mkPositive
, lengthNE
, replicateNE
) where
import Data.Aeson (FromJSON, ToJSON)
import Data.Data (Data)
import Fmt (Buildable, pretty)
import Unsafe qualified (fromIntegral)
import Morley.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 = UnsafePositive { unPositive :: Natural }
deriving stock (Eq, Ord, Data, Generic)
deriving newtype (Show, Buildable, ToJSON, FromJSON)
instance NFData Positive
mkPositive :: forall i. (Integral i, Buildable i) => i -> Either Text Positive
mkPositive a
| a > 0 = Right $ UnsafePositive (Unsafe.fromIntegral @i @Natural a)
| otherwise = Left $ "Number is not positive: " <> pretty a
-- | Count length of non-empty list.
lengthNE :: NonEmpty a -> Positive
lengthNE = UnsafePositive . Unsafe.fromIntegral @Int @Natural . length
-- | Produce a non empty list consisting of the given value.
replicateNE :: Positive -> a -> NonEmpty a
replicateNE (UnsafePositive i) a = a :| replicate (Unsafe.fromIntegral @Natural @Int i - 1) a