Updates interface to make a lot more generic
We now make use of the Binary interface, instead of relying on the caller to provide ByteString objects himself.
This commit is contained in:
parent
6eea89845d
commit
ff3cab38d9
2 changed files with 51 additions and 55 deletions
|
@ -1,57 +1,48 @@
|
|||
module Data.HexString ( HexString (..)
|
||||
, decodeText
|
||||
, decodeString
|
||||
, encodeText
|
||||
, encodeString ) where
|
||||
module Data.HexString ( HexString
|
||||
, hexString
|
||||
, toHex
|
||||
, fromHex
|
||||
, asText ) where
|
||||
|
||||
import Control.Applicative ((<$>))
|
||||
import Data.Word (Word8)
|
||||
|
||||
import qualified Data.ByteString.Base16.Lazy as BS16L (decode, encode)
|
||||
import qualified Data.ByteString.Lazy.Char8 as BSL8
|
||||
import qualified Data.ByteString.Lazy as BSL
|
||||
import qualified Data.ByteString.Base16 as BS16 (decode, encode)
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as BSL
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as TE
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as TE
|
||||
|
||||
import qualified Data.Binary as B (Binary, decode, encode, get,
|
||||
put)
|
||||
import qualified Data.Binary.Get as B (getRemainingLazyByteString)
|
||||
import qualified Data.Binary.Put as B (putLazyByteString)
|
||||
import qualified Data.Binary as B (Binary, decode, encode)
|
||||
|
||||
-- | Data type representing a HexString.
|
||||
data HexString
|
||||
= HexString BSL.ByteString
|
||||
-- | Represents a Hex string. Guarantees that all characters it contains
|
||||
-- are valid hex characters.
|
||||
data HexString =
|
||||
HexString BS.ByteString
|
||||
deriving ( Show, Eq, Ord )
|
||||
|
||||
-- | Allows us to convert to and from a `B.Binary` representation. Always
|
||||
-- assumes that the entire binary string that is fed to `Binary.decode`
|
||||
-- represents the hex string.
|
||||
instance B.Binary HexString where
|
||||
get = HexString <$> B.getRemainingLazyByteString
|
||||
put (HexString bs) = B.putLazyByteString bs
|
||||
-- | Smart constructor which validates that all the text are actually
|
||||
-- hexadecimal characters.
|
||||
hexString :: BS.ByteString -> HexString
|
||||
hexString bs =
|
||||
let isValidHex :: Word8 -> Bool
|
||||
isValidHex c
|
||||
| (48 <= c) && (c < 58) = True
|
||||
| (97 <= c) && (c < 103) = True
|
||||
| otherwise = False
|
||||
|
||||
-- | Converts a `T.Text` representation to a `HexString`
|
||||
decodeText :: T.Text -> HexString
|
||||
decodeText = decodeByteString . BSL.fromStrict . TE.encodeUtf8
|
||||
in if BS.all isValidHex bs
|
||||
then (HexString bs)
|
||||
else error ("Not a valid hex string: " ++ show bs)
|
||||
|
||||
-- | Converts a `String` representation to a `HexString`
|
||||
decodeString :: String -> HexString
|
||||
decodeString = decodeByteString . BSL8.pack
|
||||
-- | Converts a 'B.Binary' to a 'HexString' value
|
||||
toHex :: B.Binary a => a -> HexString
|
||||
toHex = hexString . BS16.encode . BSL.toStrict . B.encode
|
||||
|
||||
-- | Converts a `HexString` to a `T.Text` representation
|
||||
encodeText :: HexString -> T.Text
|
||||
encodeText = TE.decodeUtf8 . BSL.toStrict . encodeByteString
|
||||
-- | Converts a 'HexString' to a 'B.Binary' value
|
||||
fromHex :: B.Binary a => HexString -> a
|
||||
fromHex (HexString bs) = B.decode . BSL.fromStrict . fst . BS16.decode $ bs
|
||||
|
||||
-- | Converts a `HexString` to a `String` representation
|
||||
encodeString :: HexString -> String
|
||||
encodeString = BSL8.unpack . encodeByteString
|
||||
|
||||
|
||||
|
||||
-- | Internal function that converts a `HexString` to a `BSL.ByteString`
|
||||
encodeByteString :: HexString -> BSL.ByteString
|
||||
encodeByteString = BS16L.encode . B.encode
|
||||
|
||||
-- | Internal funcion that converts `BSL.ByteString` to a `HexString`
|
||||
decodeByteString :: BSL.ByteString -> HexString
|
||||
decodeByteString = B.decode . fst . BS16L.decode
|
||||
-- | Access to a 'T.Text' representation of the 'HexString'
|
||||
asText :: HexString -> T.Text
|
||||
asText (HexString bs) = TE.decodeUtf8 bs
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
module Data.HexStringSpec where
|
||||
|
||||
import Data.HexString
|
||||
import Data.HexString ( hexString
|
||||
, toHex
|
||||
, fromHex
|
||||
, asText )
|
||||
|
||||
import qualified Data.ByteString.Lazy.Char8 as BSL8
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Char8 as BS8
|
||||
import qualified Data.Text as T
|
||||
|
||||
import qualified Data.Binary as B ( encode )
|
||||
|
@ -11,11 +15,12 @@ import Test.Hspec
|
|||
|
||||
spec :: Spec
|
||||
spec = do
|
||||
describe "when decoding hex data" $ do
|
||||
it "should be able to parse basic hex data" $ do
|
||||
(B.encode . decodeString) "ffff" `shouldBe` BSL8.pack "\255\255"
|
||||
(B.encode . decodeText) (T.pack "ffff") `shouldBe` BSL8.pack "\255\255"
|
||||
describe "when constructing a hex string" $ do
|
||||
it "should accept strings that fall within a valid range" $
|
||||
hexString (BS8.pack "0123456789abcdef") `shouldBe` hexString (BS8.pack "0123456789abcdef")
|
||||
|
||||
it "should be able to recode basic hex data to different formats" $ do
|
||||
(encodeText . decodeString) "ffff" `shouldBe` T.pack "ffff"
|
||||
(encodeString . decodeString) "ffff" `shouldBe` "ffff"
|
||||
it "should reject strings outside the range" $ do
|
||||
putStrLn (show (hexString (BS8.pack "/"))) `shouldThrow` anyErrorCall
|
||||
putStrLn (show (hexString (BS8.pack ":"))) `shouldThrow` anyErrorCall
|
||||
putStrLn (show (hexString (BS8.pack "`"))) `shouldThrow` anyErrorCall
|
||||
putStrLn (show (hexString (BS8.pack "g"))) `shouldThrow` anyErrorCall
|
||||
|
|
Loading…
Reference in a new issue