{-# LANGUAGE FlexibleContexts #-}

module Saturn.Unstable.Type.Number where

import qualified Data.Bits as Bits
import qualified Data.Coerce as Coerce
import qualified Data.Text.Lazy.Builder as Builder
import qualified Data.Text.Lazy.Builder.Int as Builder
import qualified Data.Word as Word
import qualified Saturn.Unstable.Extra.Ord as Ord
import qualified Text.Parsec as Parsec
import qualified Text.Read as Read

newtype Number
  = Number Word.Word8
  deriving (Number -> Number -> Bool
(Number -> Number -> Bool)
-> (Number -> Number -> Bool) -> Eq Number
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Number -> Number -> Bool
== :: Number -> Number -> Bool
$c/= :: Number -> Number -> Bool
/= :: Number -> Number -> Bool
Eq, Int -> Number -> ShowS
[Number] -> ShowS
Number -> String
(Int -> Number -> ShowS)
-> (Number -> String) -> ([Number] -> ShowS) -> Show Number
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Number -> ShowS
showsPrec :: Int -> Number -> ShowS
$cshow :: Number -> String
show :: Number -> String
$cshowList :: [Number] -> ShowS
showList :: [Number] -> ShowS
Show)

fromWord8 :: Word.Word8 -> Number
fromWord8 :: Word8 -> Number
fromWord8 = Word8 -> Number
forall a b. Coercible a b => a -> b
Coerce.coerce

toWord8 :: Number -> Word.Word8
toWord8 :: Number -> Word8
toWord8 = Number -> Word8
forall a b. Coercible a b => a -> b
Coerce.coerce

parsec :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Number
parsec :: forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Number
parsec = do
  String
string <- ParsecT s u m Char -> ParsecT s u m String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
Parsec.many1 ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
Parsec.digit
  Integer
integer <- ParsecT s u m Integer
-> (Integer -> ParsecT s u m Integer)
-> Maybe Integer
-> ParsecT s u m Integer
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> ParsecT s u m Integer
forall a. String -> ParsecT s u m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"invalidNumber") Integer -> ParsecT s u m Integer
forall a. a -> ParsecT s u m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe Integer -> ParsecT s u m Integer)
-> Maybe Integer -> ParsecT s u m Integer
forall a b. (a -> b) -> a -> b
$ String -> Maybe Integer
forall a. Read a => String -> Maybe a
Read.readMaybe String
string
  ParsecT s u m Number
-> (Word8 -> ParsecT s u m Number)
-> Maybe Word8
-> ParsecT s u m Number
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> ParsecT s u m Number
forall a. String -> ParsecT s u m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"invalidNumber") (Number -> ParsecT s u m Number
forall a. a -> ParsecT s u m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Number -> ParsecT s u m Number)
-> (Word8 -> Number) -> Word8 -> ParsecT s u m Number
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Number
fromWord8) (Maybe Word8 -> ParsecT s u m Number)
-> Maybe Word8 -> ParsecT s u m Number
forall a b. (a -> b) -> a -> b
$
    Integer -> Maybe Word8
forall a b.
(Integral a, Integral b, Bits a, Bits b) =>
a -> Maybe b
Bits.toIntegralSized (Integer
integer :: Integer)

toBuilder :: Number -> Builder.Builder
toBuilder :: Number -> Builder
toBuilder = Word8 -> Builder
forall a. Integral a => a -> Builder
Builder.decimal (Word8 -> Builder) -> (Number -> Word8) -> Number -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Number -> Word8
toWord8

isValid :: (Word.Word8, Word.Word8) -> Number -> Bool
isValid :: (Word8, Word8) -> Number -> Bool
isValid (Word8, Word8)
tuple = (Word8, Word8) -> Word8 -> Bool
forall a. Ord a => (a, a) -> a -> Bool
Ord.within (Word8, Word8)
tuple (Word8 -> Bool) -> (Number -> Word8) -> Number -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Number -> Word8
toWord8