    {-# LANGUAGE MultiParamTypeClasses
               , TypeSynonymInstances
               , FlexibleInstances
      #-}

    module Data.ByteString.Nums.Careless.Hex where

    import Prelude hiding (head, tail, drop)
    import Data.Word
    import Data.Int
    import Data.Ratio
    import Data.ByteString hiding (head, pack)
    import Data.ByteString.Char8 hiding (foldl')
    import Data.ByteString.Internal
    import qualified Data.ByteString.Lazy.Char8 as Lazy
    import qualified Data.ByteString.Lazy.Internal as Lazy

    {-| Types that can be read from hexadecimal strings. Characters that are not
        hexadecimal digits are skipped over. One pleasant consequence of this is
        that a leading @0x@ is simply ignored.
     -}
    class (Num n) => Hexable b n where
      hex                       ::  b -> n

    instance Hexable ByteString Word8 where
      hex                        =  strict_hex
    instance Hexable ByteString Word16 where
      hex                        =  strict_hex
    instance Hexable ByteString Word32 where
      hex                        =  strict_hex
    instance Hexable ByteString Word64 where
      hex                        =  strict_hex
    instance Hexable ByteString Word where
      hex                        =  strict_hex
    instance Hexable ByteString Int8 where
      hex                        =  strict_hex
    instance Hexable ByteString Int16 where
      hex                        =  strict_hex
    instance Hexable ByteString Int32 where
      hex                        =  strict_hex
    instance Hexable ByteString Int64 where
      hex                        =  strict_hex
    instance Hexable ByteString Int where
      hex                        =  strict_hex
    instance Hexable ByteString Float where
      hex                        =  strict_hex
    instance Hexable ByteString Double where
      hex                        =  strict_hex
    instance Hexable ByteString Rational where
      hex                        =  strict_hex
    instance Hexable ByteString Integer where
      hex                        =  strict_hex

    instance Hexable Lazy.ByteString Word8 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Word16 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Word32 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Word64 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Word where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Int8 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Int16 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Int32 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Int64 where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Int where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Float where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Double where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Rational where
      hex                        =  lazy_hex
    instance Hexable Lazy.ByteString Integer where
      hex                        =  lazy_hex

    hexalize                    ::  (Num n) => n -> Word8 -> n
    hexalize acc byte
      | between 'a' 'f'          =  place_up (byte + 0x0a - c2w 'a')
      | between 'A' 'F'          =  place_up (byte + 0x0a - c2w 'A')
      | between '0' '9'          =  place_up (byte - c2w '0')
      | otherwise                =  acc
     where
      between a z                =  byte >= c2w a && byte <= c2w z
      place_up b                 =  (0x10 * acc) + fromIntegral b

    strict_hex bytes             =  foldl' hexalize 0 bytes

    lazy_hex bytes               =  Lazy.foldlChunks (foldl' hexalize) 0 bytes