diff options
-rw-r--r-- | src/gleam/bit_string.gleam | 35 | ||||
-rw-r--r-- | src/gleam_stdlib.erl | 4 | ||||
-rw-r--r-- | src/gleam_stdlib.js | 14 | ||||
-rw-r--r-- | test/gleam/bit_string_test.gleam | 70 |
4 files changed, 77 insertions, 46 deletions
diff --git a/src/gleam/bit_string.gleam b/src/gleam/bit_string.gleam index 6605ce9..8ed94f8 100644 --- a/src/gleam/bit_string.gleam +++ b/src/gleam/bit_string.gleam @@ -45,19 +45,38 @@ pub fn append(to first: BitString, suffix second: BitString) -> BitString { concat([first, second]) } +/// Extracts a sub-section of a bit string. +/// +/// The slice will start at given position and continue up to specified +/// length. +/// A negative length can be used to extract bytes at the end of a bit string. +/// +/// This function runs in constant time. +/// +pub fn slice( + from string: BitString, + at position: Int, + take length: Int, +) -> Result(BitString, Nil) { + do_slice(string, position, length) +} + if erlang { - /// Extracts part of a bit string. - /// - /// BitString part will start at given position and continue up to specified - /// length. - /// A negative length can be used to extract bytes at the end of a bit string. - /// - pub external fn part( + pub external fn do_slice( + string: BitString, + position: Int, + length: Int, + ) -> Result(BitString, Nil) = + "gleam_stdlib" "bit_string_slice" +} + +if javascript { + pub external fn do_slice( string: BitString, position: Int, length: Int, ) -> Result(BitString, Nil) = - "gleam_stdlib" "bit_string_part_" + "../gleam_stdlib.js" "bit_string_slice" } /// Tests to see whether a bit string is valid UTF-8. diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl index c3aa317..13968d2 100644 --- a/src/gleam_stdlib.erl +++ b/src/gleam_stdlib.erl @@ -9,7 +9,7 @@ string_ends_with/2, string_pad/4, decode_tuple2/1, decode_tuple3/1, decode_tuple4/1, decode_tuple5/1, decode_tuple6/1, decode_map/1, bit_string_int_to_u32/1, bit_string_int_from_u32/1, decode_result/1, - bit_string_part_/3, decode_bit_string/1, compile_regex/2, + bit_string_slice/3, decode_bit_string/1, compile_regex/2, regex_match/2, regex_split/2, regex_scan/2, base_decode64/1, wrap_list/1, bit_string_concat/1]). @@ -174,7 +174,7 @@ string_pop_grapheme(String) -> bit_string_concat(BitStrings) -> iolist_to_binary(BitStrings). -bit_string_part_(Bin, Pos, Len) -> +bit_string_slice(Bin, Pos, Len) -> try {ok, binary:part(Bin, Pos, Len)} catch error:badarg -> {error, nil} end. diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js index b63a4ea..51de04a 100644 --- a/src/gleam_stdlib.js +++ b/src/gleam_stdlib.js @@ -213,8 +213,11 @@ export function log(term) { } export function stringify(data) { - let replacer = (_key, value) => - typeof value === "bigint" ? value.toString() + "n" : value; + let replacer = (_key, value) => { + if (typeof value === "bigint") return value.toString() + "n"; + if (typeof value === "undefined") return null; + return value; + }; try { return JSON.stringify(data, replacer); } catch (_error) { @@ -263,3 +266,10 @@ export function truncate(float) { export function power(base, exponent) { return Math.pow(base, exponent); } + +export function bit_string_slice(bits, position, length) { + let start = Math.min(position, position + length); + let end = Math.max(position, position + length); + if (start < 0 || end > bits.byteLength) return gleam_error(Nil); + return gleam_ok(new Uint8Array(bits.buffer, start, Math.abs(length))); +} diff --git a/test/gleam/bit_string_test.gleam b/test/gleam/bit_string_test.gleam index e86dd5d..a395672 100644 --- a/test/gleam/bit_string_test.gleam +++ b/test/gleam/bit_string_test.gleam @@ -33,40 +33,42 @@ pub fn concat_test() { |> should.equal(<<1, 2, 3, 4>>) } -if erlang { - pub fn part_test() { - bit_string.from_string("hello") - |> bit_string.part(0, 5) - |> should.equal(Ok(bit_string.from_string("hello"))) - - bit_string.from_string("hello") - |> bit_string.part(0, 0) - |> should.equal(Ok(bit_string.from_string(""))) - - bit_string.from_string("hello") - |> bit_string.part(2, 2) - |> should.equal(Ok(bit_string.from_string("ll"))) - - bit_string.from_string("hello") - |> bit_string.part(5, -2) - |> should.equal(Ok(bit_string.from_string("lo"))) - - bit_string.from_string("") - |> bit_string.part(0, 0) - |> should.equal(Ok(bit_string.from_string(""))) - - bit_string.from_string("hello") - |> bit_string.part(6, 0) - |> should.equal(Error(Nil)) - - bit_string.from_string("hello") - |> bit_string.part(-1, 1) - |> should.equal(Error(Nil)) - - bit_string.from_string("hello") - |> bit_string.part(1, 6) - |> should.equal(Error(Nil)) - } +pub fn slice_test() { + <<"hello":utf8>> + |> bit_string.slice(0, 5) + |> should.equal(Ok(<<"hello":utf8>>)) + + <<"hello":utf8>> + |> bit_string.slice(0, 0) + |> should.equal(Ok(<<"":utf8>>)) + + <<"hello":utf8>> + |> bit_string.slice(2, 2) + |> should.equal(Ok(<<"ll":utf8>>)) + + <<"hello":utf8>> + |> bit_string.slice(5, -2) + |> should.equal(Ok(<<"lo":utf8>>)) + + <<"":utf8>> + |> bit_string.slice(0, 0) + |> should.equal(Ok(<<"":utf8>>)) + + <<"hello":utf8>> + |> bit_string.slice(6, 0) + |> should.equal(Error(Nil)) + + <<"hello":utf8>> + |> bit_string.slice(1, -2) + |> should.equal(Error(Nil)) + + bit_string.from_string("hello") + |> bit_string.slice(-1, 1) + |> should.equal(Error(Nil)) + + bit_string.from_string("hello") + |> bit_string.slice(1, 6) + |> should.equal(Error(Nil)) } pub fn to_string_test() { |