module Data.Mac
( Mac ()
, readMac
, showMac
, fromOctets
, toOctets
, toWord64
) where
import Control.Applicative
import Data.Bits
import Data.List
import Data.Word
import Foreign
import Numeric (showHex)
import Safe
newtype Mac = Mac { unMac :: Word64 }
deriving (Bounded, Eq, Ord)
instance Storable Mac where
sizeOf _ = 6
alignment _ = 1
peek p = fromOctets <$> (peek $ castPtr p) <*> peekByteOff p 1
<*> peekByteOff p 2 <*> peekByteOff p 3 <*> peekByteOff p 4
<*> peekByteOff p 5
poke p mac = do
poke (castPtr p) a
pokeByteOff p 1 b
pokeByteOff p 2 c
pokeByteOff p 3 d
pokeByteOff p 4 e
pokeByteOff p 5 f
where
(a, b, c, d, e, f) = toOctets mac
toWord64 :: Mac -> Word64
toWord64 = unMac
showMac :: String -> Mac -> String
showMac sep mac = intercalate sep
. map (\n -> pad 2 $ showHex n "")
$ [a, b, c, d, e, f]
where
(a, b, c, d, e, f) = toOctets mac
pad :: Int -> String -> String
pad n str = replicate zeroes '0' ++ str
where
zeroes = max 0 (n length str)
readMac :: String -> Maybe Mac
readMac str = case sequence (go str) of
Just [a, b, c, d, e, f] -> Just $ fromOctets a b c d e f
_ -> Nothing
where
go :: String -> [Maybe Word8]
go [_] = [Nothing]
go [] = []
go s = let (b, rest) = splitAt 2 s in readMay ("0x" ++ b) : go rest
fromOctets :: Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Mac
fromOctets a b c d e f = Mac
$ (fromIntegral a `shiftL` 40)
.|. (fromIntegral b `shiftL` 32)
.|. (fromIntegral c `shiftL` 24)
.|. (fromIntegral d `shiftL` 16)
.|. (fromIntegral e `shiftL` 8)
.|. (fromIntegral f)
toOctets :: Mac -> (Word8, Word8, Word8, Word8, Word8, Word8)
toOctets (Mac word) = ( byte 5 word, byte 4 word, byte 3 word
, byte 2 word, byte 1 word, byte 0 word)
where
byte i w = fromIntegral (w `shiftR` (i * 8))