{-# language Unsafe, GeneralizedNewtypeDeriving #-}

module D10.Num.Unsafe (D10 (..)) where

import qualified D10.Predicate as Predicate

import Data.Char (chr, ord)
import Data.Hashable (Hashable)
import Data.Monoid (Endo (..))

---------------------------------------------------

-- | A value of some numeric type @a@ between
-- @'fromInteger' 0@ and @'fromInteger' 9@.
newtype D10 a =
    D10_Unsafe a
      -- ^ The constructor's name include the word "unsafe" as a reminder
      --   that you should generally avoid using it directly, because it
      --   allows constructing invalid 'D10' values.
    deriving stock (D10 a -> D10 a -> Bool
forall a. Eq a => D10 a -> D10 a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: D10 a -> D10 a -> Bool
$c/= :: forall a. Eq a => D10 a -> D10 a -> Bool
== :: D10 a -> D10 a -> Bool
$c== :: forall a. Eq a => D10 a -> D10 a -> Bool
Eq, D10 a -> D10 a -> Bool
D10 a -> D10 a -> Ordering
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall {a}. Ord a => Eq (D10 a)
forall a. Ord a => D10 a -> D10 a -> Bool
forall a. Ord a => D10 a -> D10 a -> Ordering
forall a. Ord a => D10 a -> D10 a -> D10 a
min :: D10 a -> D10 a -> D10 a
$cmin :: forall a. Ord a => D10 a -> D10 a -> D10 a
max :: D10 a -> D10 a -> D10 a
$cmax :: forall a. Ord a => D10 a -> D10 a -> D10 a
>= :: D10 a -> D10 a -> Bool
$c>= :: forall a. Ord a => D10 a -> D10 a -> Bool
> :: D10 a -> D10 a -> Bool
$c> :: forall a. Ord a => D10 a -> D10 a -> Bool
<= :: D10 a -> D10 a -> Bool
$c<= :: forall a. Ord a => D10 a -> D10 a -> Bool
< :: D10 a -> D10 a -> Bool
$c< :: forall a. Ord a => D10 a -> D10 a -> Bool
compare :: D10 a -> D10 a -> Ordering
$ccompare :: forall a. Ord a => D10 a -> D10 a -> Ordering
Ord)
    deriving newtype Int -> D10 a -> Int
D10 a -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
forall {a}. Hashable a => Eq (D10 a)
forall a. Hashable a => Int -> D10 a -> Int
forall a. Hashable a => D10 a -> Int
hash :: D10 a -> Int
$chash :: forall a. Hashable a => D10 a -> Int
hashWithSalt :: Int -> D10 a -> Int
$chashWithSalt :: forall a. Hashable a => Int -> D10 a -> Int
Hashable

---------------------------------------------------

instance Num a => Bounded (D10 a)
  where
    minBound :: D10 a
minBound = forall a. a -> D10 a
D10_Unsafe a
0
    maxBound :: D10 a
maxBound = forall a. a -> D10 a
D10_Unsafe a
9

---------------------------------------------------

instance Integral a => Enum (D10 a)
  where
    fromEnum :: D10 a -> Int
    fromEnum :: D10 a -> Int
fromEnum (D10_Unsafe a
x) = forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x

    toEnum :: Int -> D10 a
    toEnum :: Int -> D10 a
toEnum Int
x | Int -> Bool
Predicate.isD10Int Int
x = forall a. a -> D10 a
D10_Unsafe (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x)
             | Bool
otherwise = forall a. HasCallStack => [Char] -> a
error [Char]
"d10 must be between 0 and 9"

    enumFrom :: D10 a -> [D10 a]
    enumFrom :: D10 a -> [D10 a]
enumFrom D10 a
x = forall a. Enum a => a -> a -> [a]
enumFromTo D10 a
x forall a. Bounded a => a
maxBound

    enumFromThen :: D10 a -> D10 a -> [D10 a]
    enumFromThen :: D10 a -> D10 a -> [D10 a]
enumFromThen D10 a
x D10 a
y = forall a. Enum a => a -> a -> a -> [a]
enumFromThenTo D10 a
x D10 a
y D10 a
bound
      where
        bound :: D10 a
bound | forall a. Enum a => a -> Int
fromEnum D10 a
y forall a. Ord a => a -> a -> Bool
>= forall a. Enum a => a -> Int
fromEnum D10 a
x = forall a. Bounded a => a
maxBound
              | Bool
otherwise                = forall a. Bounded a => a
minBound

    succ :: D10 a -> D10 a
succ (D10_Unsafe a
9) = forall a. HasCallStack => [Char] -> a
error [Char]
"D10 overflow"
    succ (D10_Unsafe a
x) = forall a. a -> D10 a
D10_Unsafe (forall a. Enum a => a -> a
succ a
x)

    pred :: D10 a -> D10 a
pred (D10_Unsafe a
0) = forall a. HasCallStack => [Char] -> a
error [Char]
"D10 underflow"
    pred (D10_Unsafe a
x) = forall a. a -> D10 a
D10_Unsafe (forall a. Enum a => a -> a
pred a
x)

---------------------------------------------------

instance Integral a => Show (D10 a) where
    showsPrec :: Int -> D10 a -> ShowS
showsPrec Int
_ D10 a
x = [Char] -> ShowS
showString [Char]
"[d10|"     forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => D10 a -> ShowS
showsChar D10 a
x forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ShowS
showString [Char]
"|]"
    showList :: [D10 a] -> ShowS
showList [D10 a]
xs   = [Char] -> ShowS
showString [Char]
"[d10list|" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => [D10 a] -> ShowS
showsStr [D10 a]
xs forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ShowS
showString [Char]
"|]"

showsChar :: Integral a => D10 a -> ShowS
showsChar :: forall a. Integral a => D10 a -> ShowS
showsChar (D10_Unsafe a
x) = Char -> ShowS
showChar forall a b. (a -> b) -> a -> b
$ Int -> Char
chr (Char -> Int
ord Char
'0' forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x)

showsStr :: Integral a => [D10 a] -> ShowS
showsStr :: forall a. Integral a => [D10 a] -> ShowS
showsStr = forall a. Endo a -> a -> a
appEndo forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (forall a. (a -> a) -> Endo a
Endo forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => D10 a -> ShowS
showsChar)