diff options
author | Louis Pilfold <louis@lpil.uk> | 2023-10-26 13:03:22 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2023-10-26 13:07:39 +0100 |
commit | e0cefe61b7519d8356885b941c34bbf4763cb71c (patch) | |
tree | c6dbff1309805ecb6f1b0d9df6cb091552ec6970 | |
parent | d55bfcbfc6c6c836013e4b9b45eb70c729d5ca7b (diff) | |
download | gleam_stdlib-e0cefe61b7519d8356885b941c34bbf4763cb71c.tar.gz gleam_stdlib-e0cefe61b7519d8356885b941c34bbf4763cb71c.zip |
Hex!
-rw-r--r-- | src/gleam/bit_array.gleam | 8 | ||||
-rw-r--r-- | src/gleam_stdlib.erl | 9 | ||||
-rw-r--r-- | src/gleam_stdlib.mjs | 19 | ||||
-rw-r--r-- | test/gleam/bit_array_test.gleam | 60 |
4 files changed, 95 insertions, 1 deletions
diff --git a/src/gleam/bit_array.gleam b/src/gleam/bit_array.gleam index b85782d..79860e9 100644 --- a/src/gleam/bit_array.gleam +++ b/src/gleam/bit_array.gleam @@ -147,3 +147,11 @@ pub fn base64_url_decode(encoded: String) -> Result(BitArray, Nil) { |> string.replace("_", "/") |> base64_decode() } + +@external(erlang, "binary", "encode_hex") +@external(javascript, "../gleam_stdlib.mjs", "base16_encode") +pub fn base16_encode(input: BitArray) -> String + +@external(erlang, "gleam_stdlib", "base16_decode") +@external(javascript, "../gleam_stdlib.mjs", "base16_decode") +pub fn base16_decode(input: String) -> Result(BitArray, Nil) diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl index 0ac4747..0e2136f 100644 --- a/src/gleam_stdlib.erl +++ b/src/gleam_stdlib.erl @@ -13,7 +13,7 @@ decode_tuple5/1, decode_tuple6/1, tuple_get/2, classify_dynamic/1, print/1, println/1, print_error/1, println_error/1, inspect/1, float_to_string/1, int_from_base_string/2, utf_codepoint_list_to_string/1, contains_string/2, - crop_string/2 + crop_string/2, base16_decode/1 ]). %% Taken from OTP's uri_string module @@ -490,3 +490,10 @@ crop_string(String, Prefix) -> contains_string(String, Substring) -> is_bitstring(string:find(String, Substring)). + +base16_decode(String) -> + try + {ok, binary:decode_hex(String)} + catch + _:_ -> {error, nil} + end. diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs index 645e22a..2a1a6cf 100644 --- a/src/gleam_stdlib.mjs +++ b/src/gleam_stdlib.mjs @@ -842,3 +842,22 @@ export function inspectBitArray(bits) { export function inspectUtfCodepoint(codepoint) { return `//utfcodepoint(${String.fromCodePoint(codepoint.value)})`; } + +export function base16_encode(bit_array) { + let result = ""; + for (const byte of bit_array.buffer) { + result += byte.toString(16).padStart(2, "0").toUpperCase(); + } + return result; +} + +export function base16_decode(string) { + const bytes = new Uint8Array(string.length / 2); + for (let i = 0; i < string.length; i += 2) { + const a = parseInt(string[i], 16); + const b = parseInt(string[i + 1], 16); + if (isNaN(a) || isNaN(b)) return new Error(Nil); + bytes[i / 2] = a * 16 + b; + } + return new Ok(new BitArray(bytes)); +} diff --git a/test/gleam/bit_array_test.gleam b/test/gleam/bit_array_test.gleam index 7095205..903b0c8 100644 --- a/test/gleam/bit_array_test.gleam +++ b/test/gleam/bit_array_test.gleam @@ -219,3 +219,63 @@ pub fn decode64_crash_regression_1_test() { |> bit_array.base64_decode() |> should.equal(Error(Nil)) } + +pub fn base16_test() { + bit_array.base16_encode(<<"":utf8>>) + |> should.equal("") + + bit_array.base16_encode(<<"f":utf8>>) + |> should.equal("66") + + bit_array.base16_encode(<<"fo":utf8>>) + |> should.equal("666F") + + bit_array.base16_encode(<<"foo":utf8>>) + |> should.equal("666F6F") + + bit_array.base16_encode(<<"foob":utf8>>) + |> should.equal("666F6F62") + + bit_array.base16_encode(<<"fooba":utf8>>) + |> should.equal("666F6F6261") + + bit_array.base16_encode(<<"foobar":utf8>>) + |> should.equal("666F6F626172") + + bit_array.base16_encode(<<161, 178, 195, 212, 229, 246, 120, 145>>) + |> should.equal("A1B2C3D4E5F67891") +} + +pub fn base16_decode_test() { + bit_array.base16_decode("") + |> should.equal(Ok(<<>>)) + + bit_array.base16_decode("66") + |> should.equal(Ok(<<"f":utf8>>)) + + bit_array.base16_decode("666F") + |> should.equal(Ok(<<"fo":utf8>>)) + + bit_array.base16_decode("666F6F") + |> should.equal(Ok(<<"foo":utf8>>)) + + bit_array.base16_decode("666F6F62") + |> should.equal(Ok(<<"foob":utf8>>)) + + bit_array.base16_decode("666F6F6261") + |> should.equal(Ok(<<"fooba":utf8>>)) + + bit_array.base16_decode("666F6F626172") + |> should.equal(Ok(<<"foobar":utf8>>)) + + bit_array.base16_decode("A1B2C3D4E5F67891") + |> should.equal(Ok(<<161, 178, 195, 212, 229, 246, 120, 145>>)) + + // Not a hex string + bit_array.base16_decode("?") + |> should.equal(Error(Nil)) + + // Lowercase hex + bit_array.base16_decode("a1b2c3d4e5f67891") + |> should.equal(Ok(<<161, 178, 195, 212, 229, 246, 120, 145>>)) +} |