content: -- Copyright 2023,2024 Lennart Augustsson
  -- See LICENSE file for full license.
  module Data.Word.Word(Word) where
  import qualified Prelude()              -- do not import Prelude
  import Primitives
  import Control.Error
  import Data.Bits.Base
  import Data.Bool
  import Data.Bounded
  import Data.Char
  import Data.Coerce
  import Data.Enum
  import Data.Eq
  import Data.Function
  --import Data.Int()  -- instances only
  import Data.Integer_Type
  import Data.Integral
  import Data.List
  import Data.Maybe_Type
  import Data.Num
  import Data.Ord
  import Data.Ratio_Type
  import Data.Real
  import Numeric.Show
  import Text.Show
  
  instance Num Word where
    (+)  = primWordAdd
    (-)  = primWordSub
    (*)  = primWordMul
    abs x = x
    signum x = if x == 0 then 0 else 1
    fromInteger = _integerToWord
  
  instance Integral Word where
    quot = primWordQuot
    rem  = primWordRem
    toInteger = _wordToInteger
  
  instance Bounded Word where
    minBound = 0::Word
    maxBound = primWordInv (0::Word)
  
  instance Real Word where
    toRational i = _integerToRational (_wordToInteger i)
  
  instance Show Word where
    showsPrec _ = showUnsigned
  
  -- Avoid showIntegral to avoid Integer
  showUnsigned :: Word -> ShowS
  showUnsigned n r =
    let c = primChr (primOrd '0' + primWordToInt (rem n (10::Word)))
    in  if n < (10::Word) then
          c : r
        else
          showUnsigned (quot n (10::Word)) (c : r)
  
  {- in Text.Read.Internal
  instance Read Word where
    readsPrec = readIntegral
  -}
  
  --------------------------------
  
  eftWord :: Word -> Word -> [Word]
  eftWord x y
    | x `primWordGT` y = []
    | otherwise = go x
    where
      go n = n : if n `primWordEQ` y then [] else go (n `primWordAdd` 1)
  
  efttWordUp :: Word -> Word -> Word -> [Word]
  -- x2 >= x1
  efttWordUp x1 x2 y
    | y `primWordLT` x2 = if y `primWordLT` x1 then [] else [x1]
    | otherwise =
      let
        delta = x2 `primWordSub` x1
        y' = y `primWordSub` delta
        go x = if x `primWordGT` y' then [x] else x : go (x `primWordAdd` delta)
      in x1 : go x2
  
  efttWordDown :: Word -> Word -> Word -> [Word]
  -- x2 <= x1
  efttWordDown x1 x2 y
    | y `primWordGT` x2 = if y `primWordGT` x1 then [] else [x1]
    | otherwise =
      let
        delta = x2 `primWordSub` x1
        y' = y `primWordSub` delta
        go x = if x `primWordLT` y' then [x] else x : go (x `primWordAdd` delta)
      in x1 : go x2
  
  instance Enum Word where
    succ x = if x `primWordEQ` maxBound then error "Word.succ: overflow" else x + 1
    pred x = if x `primWordEQ` minBound then error "Word.pred: underflow" else x - 1
    toEnum = primIntToWord
    fromEnum = primWordToInt
    enumFrom n = eftWord n maxBound
    enumFromThen x1 x2
      | x2 `primWordGE` x1 = efttWordUp x1 x2 maxBound
      | otherwise          = efttWordDown x1 x2 minBound
    enumFromTo = eftWord
    enumFromThenTo x1 x2 y
      | x2 `primWordGE` x1 = efttWordUp x1 x2 y
      | otherwise          = efttWordDown x1 x2 y
  
  --------------------------------
  
  instance Eq Word where
    (==) = primWordEQ
    (/=) = primWordNE
  
  instance Ord Word where
    compare = primWordCompare
    (<)  = primWordLT
    (<=) = primWordLE
    (>)  = primWordGT
    (>=) = primWordGE
  
  --------------------------------
  
  instance Bits Word where
    (.&.) = primWordAnd
    (.|.) = primWordOr
    xor   = primWordXor
    complement = primWordInv
    x `shiftL` i
      | i < 0 = _overflowError
      | i >= _wordSize = 0
      | otherwise = x `primWordShl` i
    unsafeShiftL = primWordShl
    x `shiftR` i
      | i < 0 = _overflowError
      | i >= _wordSize = 0
      | otherwise = x `primWordShr` i
    unsafeShiftR = primWordShr
    bitSizeMaybe _ = Just _wordSize
    bitSize _ = _wordSize
    bit = bitDefault
    testBit = testBitDefault
    popCount = primWordPopcount
    zeroBits = 0
    isSigned _ = False
  
  instance FiniteBits Word where
    finiteBitSize _ = _wordSize
    countLeadingZeros = primWordClz
    countTrailingZeros = primWordCtz
  
  