Compare commits

..

No commits in common. "39d8da7b11a80269454c2f134a5c834e0f3cb9a7" and "29eef5d5df20d6342f5fd8a490c83cd69794579d" have entirely different histories.

7 changed files with 57 additions and 88 deletions

View file

@ -11,8 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- CHANGELOG.md - CHANGELOG.md
- Stack integration - Stack integration
- Borsh serialization for `HexString`
- `Read` implementation for `HexString`
### Changed ### Changed

View file

@ -1,4 +1,9 @@
haskell-hexstring haskell-hexstring
================= =================
[![Build Status](https://travis-ci.org/solatis/haskell-hexstring.png?branch=master)](https://travis-ci.org/solatis/haskell-hexstring)
[![Coverage Status](https://coveralls.io/repos/solatis/haskell-hexstring/badge.svg?branch=master)](https://coveralls.io/r/solatis/haskell-hexstring?branch=master)
[![MIT](http://b.repl.ca/v1/license-MIT-blue.png)](http://en.wikipedia.org/wiki/MIT_License)
[![Haskell](http://b.repl.ca/v1/language-haskell-lightgrey.png)](http://haskell.org)
Fast and safe representation of a hex string Fast and safe representation of a hex string

View file

@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: hexstring name: hexstring
version: 0.12.1.0 version: 0.12.0
synopsis: Fast and safe representation of a hex string synopsis: Fast and safe representation of a hex string
description: Provides an interface for converting any object that has a 'Binary' instance to and from a hexadecimal Text representation. description: Provides an interface for converting any object that has a 'Binary' instance to and from a hexadecimal Text representation.
author: Rene Vergara, author: Rene Vergara,
@ -35,10 +35,7 @@ library
, base >=4.7 && <5 , base >=4.7 && <5
, base16-bytestring , base16-bytestring
, binary , binary
, borsh >=0.2
, bytestring , bytestring
, foreign-rust
, generics-sop
, text , text
default-language: Haskell2010 default-language: Haskell2010

View file

@ -1,5 +1,5 @@
name: hexstring name: hexstring
version: 0.12.1.0 version: 0.12.0
git: "https://git.vergara.tech/Vergara_Tech/haskell-hexstring" git: "https://git.vergara.tech/Vergara_Tech/haskell-hexstring"
license: MIT license: MIT
author: author:
@ -27,9 +27,6 @@ library:
- bytestring - bytestring
- base16-bytestring - base16-bytestring
- aeson - aeson
- generics-sop
- borsh >= 0.2
- foreign-rust
tests: tests:
hextring-test: hextring-test:

View file

@ -1,91 +1,69 @@
{-# LANGUAGE DeriveGeneric #-} module Data.HexString ( HexString
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.HexString
( HexString(..)
, hexString , hexString
, fromRawBytes
, fromBinary , fromBinary
, toBinary
, fromBytes
, toBytes , toBytes
, fromText , toText ) where
, toText
) where
import Codec.Borsh
import Control.Applicative (pure) import Control.Applicative (pure)
import Data.Aeson import Data.Aeson
import Data.Word (Word8) import Data.Word (Word8)
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as BS16 (decode, decodeLenient, encode) import qualified Data.ByteString.Base16 as BS16 (decodeLenient, encode)
import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy as BSL
import Data.Structured
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as TE import qualified Data.Text.Encoding as TE
import qualified Data.Binary as B (Binary, decode, encode) import qualified Data.Binary as B (Binary, decode, encode)
import qualified GHC.Generics as GHC
import qualified Generics.SOP as SOP
import Text.Read
-- | Represents a Hex string. Guarantees that all characters it contains -- | Represents a Hex string. Guarantees that all characters it contains
-- are valid hex characters. -- are valid hex characters.
newtype HexString = HexString data HexString =
{ hexBytes :: BS.ByteString HexString BS.ByteString
} deriving stock (Eq, GHC.Generic) deriving ( Show, Eq, Ord )
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct HexString
instance Prelude.Show HexString where
show = T.unpack . toText
instance Read HexString where
readsPrec _ s = [((fromText . T.pack) s, "")]
instance FromJSON HexString where instance FromJSON HexString where
parseJSON = withText "HexString" $ pure . hexString . TE.encodeUtf8 parseJSON = withText "HexString" $ pure . hexString . TE.encodeUtf8
instance ToJSON HexString where instance ToJSON HexString where
toJSON = Data.Aeson.String . toText toJSON = String . toText
-- | Smart constructor which validates that all the text are actually -- | Smart constructor which validates that all the text are actually
-- hexadecimal characters. -- hexadecimal characters.
hexString :: BS.ByteString -> HexString hexString :: BS.ByteString -> HexString
hexString bs = hexString bs =
case BS16.decode bs of let isValidHex :: Word8 -> Bool
Right s -> HexString s isValidHex c
Left e -> error e | (48 <= c) && (c < 58) = True
| (97 <= c) && (c < 103) = True
| otherwise = False
in if BS.all isValidHex bs
then HexString bs
else error ("Not a valid hex string: " ++ show bs)
-- | Converts a 'B.Binary' to a 'HexString' value -- | Converts a 'B.Binary' to a 'HexString' value
fromBinary :: B.Binary a => a -> HexString fromBinary :: B.Binary a => a -> HexString
fromBinary = HexString . BSL.toStrict . B.encode fromBinary = hexString . BS16.encode . BSL.toStrict . B.encode
-- | Converts a 'HexString' to a 'B.Binary' value -- | Converts a 'HexString' to a 'B.Binary' value
toBinary :: B.Binary a => HexString -> a toBinary :: B.Binary a => HexString -> a
toBinary (HexString bs) = (B.decode . BSL.fromStrict) bs toBinary (HexString bs) = B.decode . BSL.fromStrict . BS16.decodeLenient $ bs
-- | Reads a 'BS.ByteString' as raw bytes and converts to hex representation. We -- | Reads a 'BS.ByteString' as raw bytes and converts to hex representation. We
-- cannot use the instance Binary of 'BS.ByteString' because it provides -- cannot use the instance Binary of 'BS.ByteString' because it provides
-- a leading length, which is not what we want when dealing with raw bytes. -- a leading length, which is not what we want when dealing with raw bytes.
fromRawBytes :: BS.ByteString -> HexString fromBytes :: BS.ByteString -> HexString
fromRawBytes = HexString fromBytes = hexString . BS16.encode
-- | Access to the raw bytes in a 'BS.ByteString' format. -- | Access to the raw bytes in a 'BS.ByteString' format.
toBytes :: HexString -> BS.ByteString toBytes :: HexString -> BS.ByteString
toBytes (HexString bs) = bs toBytes (HexString bs) = BS16.decodeLenient bs
-- | Reads a human-readable hex string into a `HexString`
fromText :: T.Text -> HexString
fromText = hexString . TE.encodeUtf8
-- | Access to a 'T.Text' representation of the 'HexString' -- | Access to a 'T.Text' representation of the 'HexString'
toText :: HexString -> T.Text toText :: HexString -> T.Text
toText (HexString bs) = (TE.decodeUtf8 . BS16.encode) bs toText (HexString bs) = TE.decodeUtf8 bs

View file

@ -2,9 +2,3 @@ resolver: lts-21.22
packages: packages:
- . - .
extra-deps:
- git: https://github.com/well-typed/borsh.git
commit: d2fcfa159e0a844b1ec5e8ed3e232d4b380fa831
- git: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
commit: 787c2e813eb3a5d16c375d4b37dfefbd2adcdf05

View file

@ -1,8 +1,8 @@
{-# LANGUAGE OverloadedStrings #-}
module Data.HexStringSpec where module Data.HexStringSpec where
import Data.HexString (fromRawBytes, fromText, hexString, toBytes, toText) import Data.HexString ( hexString
, fromBytes
, toBytes )
import qualified Data.ByteString.Char8 as BS8 import qualified Data.ByteString.Char8 as BS8
@ -11,17 +11,17 @@ import Test.Hspec
spec :: Spec spec :: Spec
spec = do spec = do
describe "when constructing a hex string" $ do 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 reject strings outside the range" $ do it "should reject strings outside the range" $ do
print (hexString (BS8.pack "/")) `shouldThrow` anyErrorCall putStrLn (show (hexString (BS8.pack "/"))) `shouldThrow` anyErrorCall
print (hexString (BS8.pack ":")) `shouldThrow` anyErrorCall putStrLn (show (hexString (BS8.pack ":"))) `shouldThrow` anyErrorCall
print (hexString (BS8.pack "`")) `shouldThrow` anyErrorCall putStrLn (show (hexString (BS8.pack "`"))) `shouldThrow` anyErrorCall
print (hexString (BS8.pack "g")) `shouldThrow` anyErrorCall putStrLn (show (hexString (BS8.pack "g"))) `shouldThrow` anyErrorCall
describe "when interpreting a hex string" $ do describe "when interpreting a hex string" $ do
it "should convert the hex string properly when interpreting as bytes" $ it "should convert the hex string properly when interpreting as bytes" $
toBytes (hexString "ffff") `shouldBe` BS8.pack "\255\255" toBytes (hexString (BS8.pack "ffff")) `shouldBe` BS8.pack "\255\255"
it "should convert bytes to the proper hex string" $ it "should convert bytes to the proper hex string" $
fromRawBytes (BS8.pack "\255\255") `shouldBe` hexString (BS8.pack "ffff") fromBytes (BS8.pack "\255\255") `shouldBe` hexString (BS8.pack "ffff")
it "should convert the hex string to text" $
toText (hexString "ffff") `shouldBe` "ffff"
it "should read text into the hex string" $
fromText "ffff" `shouldBe` hexString (BS8.pack "ffff")