{-# language Trustworthy #-}

module NatOptics.Positive
  (
    {- * Type constructor -} Positive,

    {- * Optics -}           refine, natPrism, intPrism,
                             textPrism, stringPrism,

    {- * Re-exports -}       Natural, Integer, Prism',
                             view, review, preview,
  ) where

import Control.Applicative ( (*>) )
import Control.Monad       ( guard )
import Data.Bits           ( Bits, toIntegralSized )
import Data.Function       ( (.) )
import Data.Functor        ( ($>), (<$>) )
import Data.Maybe          ( Maybe )
import Data.Ord            ( Ord, (>) )
import Data.String         ( String )
import Data.Text           ( Text )
import NatOptics.Internal  ( strNat, textStr )
import Numeric.Natural     ( Natural )
import Optics.AffineFold   ( preview )
import Optics.Getter       ( view )
import Optics.Optic        ( (%) )
import Optics.Prism        ( Prism', prism' )
import Optics.Review       ( review )
import Prelude             ( Integer, Integral, Num,
                             fromIntegral, toInteger )

import NatOptics.Positive.Unsafe (Positive (..))

{- | For any numeric type @n@,
     @'Positive' n@ is a subset of @n@.

Examples:

- @'preview' 'refine' (-1 :: 'Integer')@ = @'Nothing'@
- @'preview' 'refine' (0 :: 'Integer')@ = @'Nothing'@
- @'preview' 'refine' (1 :: 'Integer')@ = @'Just' (Positive 1)@
- @'preview' 'refine' (2 :: 'Integer')@ = @'Just' (Positive 2)@
-}
refine :: (Num n, Ord n) => Prism' n (Positive n)
refine :: Prism' n (Positive n)
refine = (Positive n -> n)
-> (n -> Maybe (Positive n)) -> Prism' n (Positive n)
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' Positive n -> n
forall number. Positive number -> number
number n -> Maybe (Positive n)
forall n. (Num n, Ord n) => n -> Maybe (Positive n)
verify

{- | For any integral type @n@,
     @'Positive' n@ is a subset of 'Natural'. -}
natPrism :: (Integral n, Bits n) => Prism' Natural (Positive n)
natPrism :: Prism' Natural (Positive n)
natPrism = (Positive n -> Natural)
-> (Natural -> Maybe (Positive n)) -> Prism' Natural (Positive n)
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' (n -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (n -> Natural) -> (Positive n -> n) -> Positive n -> Natural
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Positive n -> n
forall number. Positive number -> number
number) Natural -> Maybe (Positive n)
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe (Positive b)
verifyAndResize

{- | For any integral type @n@,
     @'Positive' n@ is a subset of 'Integer'. -}
intPrism :: (Integral n, Bits n) => Prism' Integer (Positive n)
intPrism :: Prism' Integer (Positive n)
intPrism = (Positive n -> Integer)
-> (Integer -> Maybe (Positive n)) -> Prism' Integer (Positive n)
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' (n -> Integer
forall a. Integral a => a -> Integer
toInteger (n -> Integer) -> (Positive n -> n) -> Positive n -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Positive n -> n
forall number. Positive number -> number
number) Integer -> Maybe (Positive n)
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe (Positive b)
verifyAndResize

stringPrism :: (Integral n, Bits n) => Prism' String (Positive n)
stringPrism :: Prism' String (Positive n)
stringPrism = Prism' String Natural
strNat Prism' String Natural
-> Optic A_Prism NoIx Natural Natural (Positive n) (Positive n)
-> Prism' String (Positive n)
forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% Optic A_Prism NoIx Natural Natural (Positive n) (Positive n)
forall n. (Integral n, Bits n) => Prism' Natural (Positive n)
natPrism

textPrism :: (Integral n, Bits n) => Prism' Text (Positive n)
textPrism :: Prism' Text (Positive n)
textPrism = Iso' Text String
textStr Iso' Text String
-> Optic A_Prism NoIx String String (Positive n) (Positive n)
-> Prism' Text (Positive n)
forall k l m (is :: IxList) (js :: IxList) (ks :: IxList) s t u v a
       b.
(JoinKinds k l m, AppendIndices is js ks) =>
Optic k is s t u v -> Optic l js u v a b -> Optic m ks s t a b
% Optic A_Prism NoIx String String (Positive n) (Positive n)
forall n. (Integral n, Bits n) => Prism' String (Positive n)
stringPrism

verify :: (Num n, Ord n) => n -> Maybe (Positive n)
verify :: n -> Maybe (Positive n)
verify n
n = Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (n
n n -> n -> Bool
forall a. Ord a => a -> a -> Bool
> n
0) Maybe () -> Positive n -> Maybe (Positive n)
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> n -> Positive n
forall number. number -> Positive number
PositiveUnsafe n
n

verifyAndResize :: (Integral a, Integral b, Bits a, Bits b) => a -> Maybe (Positive b)
verifyAndResize :: a -> Maybe (Positive b)
verifyAndResize a
x = a -> Maybe (Positive a)
forall n. (Num n, Ord n) => n -> Maybe (Positive n)
verify a
x Maybe (Positive a) -> Maybe (Positive b) -> Maybe (Positive b)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (b -> Positive b
forall number. number -> Positive number
PositiveUnsafe (b -> Positive b) -> Maybe b -> Maybe (Positive b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> Maybe b
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
toIntegralSized a
x)