Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/cabal.config
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
# hex-text
# hex-text

`hex-text` is a small library for converting between `ByteString`s and their representations as hexidecimal numbers encoded as `Text`.

A `ByteString` is a list of bytes. A byte is a number between 0 and 255, represented by the `Word8` type. In a fixed-width hexidecimal representation, the lowest byte 0 is represented by the hex string `00`, and the greatest byte 255 is represented by the hex string `ff`. So, for example, the `ByteString` consisting of bytes \[ 1, 2, 3, 253, 254, 255 \] is represented as `010203fdfeff`.

```haskell
λ> import Text.Hex (encodeHex)
λ> import Data.ByteString (pack)

λ> (encodeHex . pack) [1, 2, 3, 253, 254, 255]
"010203fdfeff"
```
Empty file added hex-text/.gitignore
Empty file.
1 change: 1 addition & 0 deletions hex-text/README.md
3 changes: 3 additions & 0 deletions hex-text/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Distribution.Simple

main = defaultMain
49 changes: 49 additions & 0 deletions hex-text/hex-text.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: hex-text
version: 0.1.0.0
category: Text

synopsis: ByteString-Text hexidecimal conversions

description: Encode a ByteString as a hexidecimal Text value,
or decode hexidecimal Text as a ByteString.

homepage: https://github.com/typeclasses/hex-text
bug-reports: https://github.com/typeclasses/hex-text/issues

author: Chris Martin
maintainer: Chris Martin, Julie Moronuki

copyright: 2018 Typeclass Consulting, LLC
license: Apache-2.0
license-file: license.txt

build-type: Simple
cabal-version: >= 1.10

extra-source-files:
README.md

source-repository head
type: git
location: https://github.com/typeclasses/hex-text

library
default-language: Haskell2010
hs-source-dirs: src
build-depends:
base >=4.7 && <5
, base16-bytestring
, bytestring
, text
exposed-modules:
Text.Hex

test-suite doctest
default-language: Haskell2010
hs-source-dirs: test
type: exitcode-stdio-1.0
main-is: doctest.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends:
base >=4.7 && <5
, doctest
1 change: 1 addition & 0 deletions hex-text/license.txt
134 changes: 134 additions & 0 deletions hex-text/src/Text/Hex.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
module Text.Hex
(
-- * Encoding and decoding
encodeHex
, decodeHex
, lazilyEncodeHex

-- * Types
, Text
, LazyText
, ByteString
, LazyByteString

-- * Type conversions
, lazyText
, strictText
, lazyByteString
, strictByteString

) where

-- base16-bytestring
import qualified Data.ByteString.Base16 as Base16
import qualified Data.ByteString.Base16.Lazy as LazyBase16

-- bytestring
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as LazyByteString

-- text
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.Text.Lazy as LazyText
import qualified Data.Text.Lazy.Encoding as LazyText

-- | Strict byte string

type ByteString =
ByteString.ByteString

-- | Lazy byte string

type LazyByteString =
LazyByteString.ByteString

-- | Strict text

type Text =
Text.Text

-- | Lazy text

type LazyText =
LazyText.Text

-- |
-- Encodes a byte string as hexidecimal number represented in text.
-- Each byte of the input is converted into two characters in the
-- resulting text.
--
-- >>> (encodeHex . ByteString.singleton) 192
-- "c0"
--
-- >>> (encodeHex . ByteString.singleton) 168
-- "a8"
--
-- >>> (encodeHex . ByteString.pack) [192, 168, 1, 2]
-- "c0a80102"
--
-- 'Text' produced by @encodeHex@ can be converted back to a
-- 'ByteString' using 'decodeHex'.
--
-- The lazy variant of @encodeHex@ is 'lazilyEncodeHex'.

encodeHex :: ByteString -> Text
encodeHex bs =
Text.decodeUtf8 (Base16.encode bs)

-- |
-- Decodes hexidecimal text as a byte string. If the text contains
-- an even number of characters and consists only of the digits @0@
-- through @9@ and letters @a@ through @f@, then the result is a
-- 'Just' value.
--
-- >>> (fmap ByteString.unpack . decodeHex . Text.pack) "c0a80102"
-- Just [192,168,1,2]
--
-- If the text contains an odd number of characters, decoding fails
-- and produces 'Nothing'.
--
-- >>> (fmap ByteString.unpack . decodeHex . Text.pack) "c0a8010"
-- Nothing
--
-- If the text contains non-hexidecimal characters, decoding fails
-- and produces 'Nothing'.
--
-- >>> (fmap ByteString.unpack . decodeHex . Text.pack) "x0a80102"
-- Nothing
--
-- The letters may be in either upper or lower case. This next
-- example therefore gives the same result as the first one above:
--
-- >>> (fmap ByteString.unpack . decodeHex . Text.pack) "C0A80102"
-- Just [192,168,1,2]

decodeHex :: Text -> Maybe ByteString
decodeHex txt =
let (x, remainder) = Base16.decode (Text.encodeUtf8 txt)
in if ByteString.null remainder then Just x else Nothing

-- |
-- @lazilyEncodeHex@ is the lazy variant of 'encodeHex'.
--
-- With laziness, it is possible to encode byte strings of
-- infinite length:
--
-- >>> (LazyText.take 8 . lazilyEncodeHex . LazyByteString.pack . cycle) [1, 2, 3]
-- "01020301"

lazilyEncodeHex :: LazyByteString -> LazyText
lazilyEncodeHex bs =
LazyText.decodeUtf8 (LazyBase16.encode bs)

lazyText :: Text -> LazyText
lazyText = LazyText.fromStrict

strictText :: LazyText -> Text
strictText = LazyText.toStrict

lazyByteString :: ByteString -> LazyByteString
lazyByteString = LazyByteString.fromStrict

strictByteString :: LazyByteString -> ByteString
strictByteString = LazyByteString.toStrict
5 changes: 5 additions & 0 deletions hex-text/test/doctest.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Test.DocTest

main :: IO ()
main =
doctest [ "-isrc", "src/Text/Hex.hs" ]
13 changes: 13 additions & 0 deletions license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2018 Typeclass Consulting, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
4 changes: 4 additions & 0 deletions stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resolver: lts-10.6

packages:
- hex-text