{-# LANGUAGE Safe #-}
{- arch-tag: Bit utilities main file
Copyright (c) 2004-2011 John Goerzen <jgoerzen@complete.org>

All rights reserved.

For license and copyright information, see the file LICENSE
-}

{- |
   Module     : Data.Bits.Utils
   Copyright  : Copyright (C) 2004-2011 John Goerzen
   SPDX-License-Identifier: BSD-3-Clause

   Stability  : stable
   Portability: portable to platforms with rawSystem

  Bit-related utilities

Written by John Goerzen, jgoerzen\@complete.org
-}

module Data.Bits.Utils(getBytes, fromBytes,
                     c2w8, s2w8, w82c, w82s)
where
import safe Data.Bits
    ( Bits((.|.), (.&.), shiftR, bitSizeMaybe, shiftL) )
import safe Data.Word ( Word8 )

{- | Returns a list representing the bytes that comprise a data type.

Example:

> getBytes (0x12345678::Int) -> [0x12, 0x34, 0x56, 0x78]
-}
getBytes :: (Integral a, Bounded a, Bits a) => a -> [a]
getBytes :: forall a. (Integral a, Bounded a, Bits a) => a -> [a]
getBytes a
input
  | Just Int
size <- a -> Maybe Int
forall a. Bits a => a -> Maybe Int
bitSizeMaybe a
input, Int
size Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
8 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 =
      [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ a -> Int -> [a]
forall {t} {t}. (Bits t, Num t, Num t, Eq t) => t -> t -> [t]
getByte a
input (Int -> [a]) -> Int -> [a]
forall a b. (a -> b) -> a -> b
$ Int
size Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
8
  | Bool
otherwise = [Char] -> [a]
forall a. HasCallStack => [Char] -> a
error [Char]
"Input data bit size must be a multiple of 8"
  where
    getByte :: t -> t -> [t]
getByte t
_ t
0 = []
    getByte t
x t
remaining = (t
x t -> t -> t
forall a. Bits a => a -> a -> a
.&. t
0xff) t -> [t] -> [t]
forall a. a -> [a] -> [a]
: t -> t -> [t]
getByte (t -> Int -> t
forall a. Bits a => a -> Int -> a
shiftR t
x Int
8) (t
remaining t -> t -> t
forall a. Num a => a -> a -> a
- t
1)

{- | The opposite of 'getBytes', this function builds a number based on
its component bytes.

Results are undefined if any components of the input list are > 0xff!

-}

fromBytes :: (Bits a, Num a) => [a] -> a
fromBytes :: forall a. (Bits a, Num a) => [a] -> a
fromBytes [a]
input =
    let dofb :: t -> [t] -> t
dofb t
accum []     = t
accum
        dofb t
accum (t
x:[t]
xs) = t -> [t] -> t
dofb ((t -> Int -> t
forall a. Bits a => a -> Int -> a
shiftL t
accum Int
8) t -> t -> t
forall a. Bits a => a -> a -> a
.|. t
x) [t]
xs
        in
        a -> [a] -> a
forall {t}. Bits t => t -> [t] -> t
dofb a
0 [a]
input

{- | Converts a Char to a Word8. -}
c2w8 :: Char -> Word8
c2w8 :: Char -> Word8
c2w8 = Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
forall a. Enum a => a -> Int
fromEnum

{- | Converts a String to a [Word8]. -}
s2w8 :: String -> [Word8]
s2w8 :: [Char] -> [Word8]
s2w8 = (Char -> Word8) -> [Char] -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
c2w8

{- | Converts a Word8 to a Char. -}
w82c :: Word8 -> Char
w82c :: Word8 -> Char
w82c = Int -> Char
forall a. Enum a => Int -> a
toEnum (Int -> Char) -> (Word8 -> Int) -> Word8 -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral

{- | Converts a [Word8] to a String. -}
w82s :: [Word8] -> String
w82s :: [Word8] -> [Char]
w82s = (Word8 -> Char) -> [Word8] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Word8 -> Char
w82c