elm-cardano/x-bytes/1.0.0

NOTE: the latest version is 1.1.0

XBytes

Comparable byte sequences backed by a hex string.

XBytes is an opaque type that wraps a lowercase hex String. Unlike Bytes, two XBytes values can be compared with ==.

Hex conversion

type XBytes

An opaque byte sequence backed by a lowercase hex string. Supports structural equality via ==.

fromHex : String -> Maybe XBytes

Create XBytes from a hex string, validating the input. Returns Nothing if the string has odd length or contains non-hex characters.

fromHex "deadbeef"
    == Just
    ... fromHex "nope"
    == Nothing

Uses a validate-only pass (no intermediate Bytes allocation) followed by a single String.toLower call. Benchmarked 25-43% faster than routing through Hex.toBytes which allocates Encoder nodes and Bytes just to discard them.

Create XBytes from a lowercase hex string without validation. The caller must ensure the input is a valid, even-length, lowercase hex string.

toHex : XBytes -> String

Extract the lowercase hex string from XBytes.

toHex (fromHexUnchecked "deadbeef") == "deadbeef"

Bytes conversion

fromBytes : Bytes -> XBytes

Convert Bytes to XBytes.

toBytes : XBytes -> Bytes

Convert XBytes to Bytes.

Text conversion

fromText : String -> XBytes

Encode a UTF-8 String as XBytes.

toHex (fromText "A") == "41"
toText : XBytes -> Maybe String

Decode XBytes as a UTF-8 String. Returns Nothing if the bytes are not valid UTF-8.

toText (fromHexUnchecked "41") == Just "A"

Common operations

An empty byte sequence.

toHex empty == ""
isEmpty : XBytes -> Bool

Check if the byte sequence is empty.

isEmpty empty == True
width : XBytes -> Int

The number of bytes.

width (fromHexUnchecked "deadbeef") == 2

Reverse the byte order.

toHex (reverse (fromHexUnchecked "0102")) == "0201"

Append two byte sequences.

toHex (append (fromHexUnchecked "dead") (fromHexUnchecked "beef"))
    == "deadbeef"
concat : List XBytes -> XBytes

Concatenate a list of byte sequences.

toHex (concat [ fromHexUnchecked "de", fromHexUnchecked "ad" ])
    == "dead"

Uses List.foldl with (++) instead of List.map + String.concat to avoid allocating an intermediate List String. Benchmarked 63% faster.

join : XBytes -> List XBytes -> XBytes

Join a list of byte sequences with a separator.

toHex (join (fromHexUnchecked "00") [ fromHexUnchecked "aa", fromHexUnchecked "bb" ])
    == "aa00bb"
slice : Int -> Int -> XBytes -> XBytes

Slice bytes from index start (inclusive) to end (exclusive). Indices are byte offsets, following the same semantics as String.slice.

toHex (slice 1 3 (fromHexUnchecked "deadbeef")) == "adbe"
left : Int -> XBytes -> XBytes

Take the first n bytes.

toHex (left 2 (fromHexUnchecked "deadbeef")) == "dead"
dropLeft : Int -> XBytes -> XBytes

Drop the first n bytes.

toHex (dropLeft 1 (fromHexUnchecked "deadbeef")) == "adbeef"
dropRight : Int -> XBytes -> XBytes

Drop the last n bytes.

toHex (dropRight 1 (fromHexUnchecked "deadbeef")) == "deadbe"

Bytes.Decode / Bytes.Encode interop

decoder : Decoder a -> XBytes -> Maybe a

Run a Bytes.Decode.Decoder on the underlying bytes.

decode Bytes.Decode.unsignedInt8 (fromHexUnchecked "ff") == Just 255
encode : Encoder -> XBytes

Run a Bytes.Encode.Encoder and wrap the result as XBytes.

toHex (encode (Bytes.Encode.unsignedInt8 255)) == "ff"

JSON

jsonEncode : XBytes -> Value

Encode XBytes as a JSON string (lowercase hex).

Decode a JSON string as XBytes, validating hex content. Fails if the string is not valid hex.