{-# LANGUAGE BangPatterns #-}

{- | Conversions from individual bytes to numbers in specific formats.
 -}

module Parser.Lathe.Radix
  ( -- | === Base-2
    bin

    -- | === Base-8
  , oct

    -- | === Base-10
  , dec

    -- | === Base-16
  , hex
  , hexUpper
  , hexLower
  ) where

import           Data.Bits
import           Data.Word



{-# INLINE bin #-}
-- | Convert a binary ASCII byte into a number.
bin :: Word8 -> Maybe Word8
bin :: Word8 -> Maybe Word8
bin Word8
a =
  let b :: Word8
b = Word8
a Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
  in if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x02
       then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just Word8
b
       else Maybe Word8
forall a. Maybe a
Nothing



{-# INLINE oct #-}
-- | Convert an octal ASCII byte into a number.
oct :: Word8 -> Maybe Word8
oct :: Word8 -> Maybe Word8
oct Word8
a =
  let b :: Word8
b = Word8
a Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
  in if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x08
       then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just Word8
b
       else Maybe Word8
forall a. Maybe a
Nothing



{-# INLINE dec #-}
-- | Convert a decimal ASCII byte into a number.
dec :: Word8 -> Maybe Word8
dec :: Word8 -> Maybe Word8
dec Word8
a =
  let b :: Word8
b = Word8
a Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
  in if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A
       then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just Word8
b
       else Maybe Word8
forall a. Maybe a
Nothing



{-# INLINE hex #-}
-- | Convert a hexadecimal ASCII byte into a number. Case-insensitive.
hex :: Word8 -> Maybe Word8
hex :: Word8 -> Maybe Word8
hex Word8
a =
  let b :: Word8
b = Word8
a Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30

      c :: Word8
c = Word8
a Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0xDF

  in if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A Bool -> Bool -> Bool
|| Word8
c Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x41 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x6
       then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just (Word8 -> Maybe Word8) -> Word8 -> Maybe Word8
forall a b. (a -> b) -> a -> b
$! if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A
                      then Word8
b
                      else Word8
c Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x37
       else Maybe Word8
forall a. Maybe a
Nothing



{-# INLINE hexUpper #-}
-- | Convert an upper-case hexadecimal ASCII byte into a number.
hexUpper :: Word8 -> Maybe Word8
hexUpper :: Word8 -> Maybe Word8
hexUpper Word8
a =
  let b :: Word8
b = Word8
a Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
  in if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A Bool -> Bool -> Bool
|| Word8
b Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x11 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x6
       then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just (Word8 -> Maybe Word8) -> Word8 -> Maybe Word8
forall a b. (a -> b) -> a -> b
$! if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A
                      then Word8
b
                      else Word8
b Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x07
       else Maybe Word8
forall a. Maybe a
Nothing



{-# INLINE hexLower #-}
-- | Convert a lower-case hexadecimal ASCII byte into a number.
hexLower :: Word8 -> Maybe Word8
hexLower :: Word8 -> Maybe Word8
hexLower Word8
a =
  let b :: Word8
b = Word8
a Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x30
  in if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A Bool -> Bool -> Bool
|| Word8
b Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x31 Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x6
       then Word8 -> Maybe Word8
forall a. a -> Maybe a
Just (Word8 -> Maybe Word8) -> Word8 -> Maybe Word8
forall a b. (a -> b) -> a -> b
$! if Word8
b Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x0A
                      then Word8
b
                      else Word8
b Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Word8
0x27
       else Maybe Word8
forall a. Maybe a
Nothing