module Integer.Positive
  ( -- * Type
    Positive,

    -- * Conversion

    -- ** Natural
    toNatural,
    fromNatural,

    -- ** Integer
    toInteger,
    fromInteger,

    -- ** Signed
    toSigned,
    fromSigned,

    -- ** Int
    toInt,
    fromInt,

    -- ** Word
    toWord,
    fromWord,

    -- * Arithmetic

    -- ** Subtraction
    subtract,

    -- ** Increase
    increase,

    -- ** One (1)
    one,
    addOne,
    subtractOne,

    -- * List
    length,
  )
where

import Data.Int (Int)
import Data.List qualified as List
import Data.List.NonEmpty (NonEmpty (..))
import Data.Ord qualified as Ord
import Data.Word (Word)
import Essentials
import Integer.Positive.Unsafe (Positive, addOne, increase, one, toInteger, toNatural)
import Integer.Positive.Unsafe qualified as Unsafe
import Integer.Signed (Signed (..))
import Numeric.Natural (Natural)
import Prelude (Integer)
import Prelude qualified as Bounded (Bounded (..))
import Prelude qualified as Num (Integral (..), Num (..))

fromInteger :: Integer -> Maybe Positive
fromInteger :: Integer -> Maybe Positive
fromInteger Integer
x = if Integer
x forall a. Ord a => a -> a -> Bool
Ord.> Integer
0 then forall a. a -> Maybe a
Just (Integer -> Positive
Unsafe.fromInteger Integer
x) else forall a. Maybe a
Nothing

fromNatural :: Natural -> Maybe Positive
fromNatural :: Natural -> Maybe Positive
fromNatural Natural
x = case Natural
x of Natural
0 -> forall a. Maybe a
Nothing; Natural
_ -> forall a. a -> Maybe a
Just (Natural -> Positive
Unsafe.fromNatural Natural
x)

toInt :: Positive -> Maybe Int
toInt :: Positive -> Maybe Int
toInt Positive
x = if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
x') else forall a. Maybe a
Nothing
  where
    ok :: Bool
ok = Integer
x' forall a. Ord a => a -> a -> Bool
Ord.<= forall a. Integral a => a -> Integer
Num.toInteger (forall a. Bounded a => a
Bounded.maxBound :: Int)
    x' :: Integer
x' = forall a. Integral a => a -> Integer
Num.toInteger Positive
x

fromInt :: Int -> Maybe Positive
fromInt :: Int -> Maybe Positive
fromInt Int
x = if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
x') else forall a. Maybe a
Nothing
  where
    ok :: Bool
ok = Integer
x' forall a. Ord a => a -> a -> Bool
Ord.>= Integer
1
    x' :: Integer
x' = forall a. Integral a => a -> Integer
Num.toInteger Int
x

toWord :: Positive -> Maybe Word
toWord :: Positive -> Maybe Word
toWord Positive
x = if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
x') else forall a. Maybe a
Nothing
  where
    ok :: Bool
ok = Integer
x' forall a. Ord a => a -> a -> Bool
Ord.<= forall a. Integral a => a -> Integer
Num.toInteger (forall a. Bounded a => a
Bounded.maxBound :: Word)
    x' :: Integer
x' = forall a. Integral a => a -> Integer
Num.toInteger Positive
x

fromWord :: Word -> Maybe Positive
fromWord :: Word -> Maybe Positive
fromWord Word
x = if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
x') else forall a. Maybe a
Nothing
  where
    ok :: Bool
ok = Integer
x' forall a. Ord a => a -> a -> Bool
Ord.>= Integer
1
    x' :: Integer
x' = forall a. Integral a => a -> Integer
Num.toInteger Word
x

subtract :: Positive -> Positive -> Signed
subtract :: Positive -> Positive -> Signed
subtract Positive
a Positive
b = case forall a. Ord a => a -> a -> Ordering
Ord.compare Positive
a Positive
b of
  Ordering
Ord.EQ -> Signed
Zero
  Ordering
Ord.GT -> Positive -> Signed
Plus forall a b. (a -> b) -> a -> b
$ Positive -> Positive -> Positive
Unsafe.subtract Positive
a Positive
b
  Ordering
Ord.LT -> Positive -> Signed
Minus forall a b. (a -> b) -> a -> b
$ Positive -> Positive -> Positive
Unsafe.subtract Positive
b Positive
a

subtractOne :: Positive -> Natural
subtractOne :: Positive -> Natural
subtractOne Positive
x = Positive -> Natural
toNatural Positive
x forall a. Num a => a -> a -> a
Num.- Natural
1

toSigned :: Positive -> Signed
toSigned :: Positive -> Signed
toSigned = Positive -> Signed
Plus

fromSigned :: Signed -> Maybe Positive
fromSigned :: Signed -> Maybe Positive
fromSigned (Plus Positive
x) = forall a. a -> Maybe a
Just Positive
x
fromSigned Signed
_ = forall a. Maybe a
Nothing

length :: NonEmpty a -> Positive
length :: forall a. NonEmpty a -> Positive
length (a
_ :| [a]
xs) = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' (\Positive
x a
_ -> Positive
x forall a. Num a => a -> a -> a
Num.+ Positive
1) Positive
1 [a]
xs