aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2021-08-08 22:14:56 +0100
committerLouis Pilfold <louis@lpil.uk>2021-08-08 22:14:56 +0100
commit29398e1848b0615afda30fb1da4ec8d81eccc1c5 (patch)
tree5762a473ca246cee13adb1632b7d5850a91fd78c
parentc5a001977a3b76f257a3a7ea4605f6ff61f1a590 (diff)
downloadgleam_stdlib-29398e1848b0615afda30fb1da4ec8d81eccc1c5.tar.gz
gleam_stdlib-29398e1848b0615afda30fb1da4ec8d81eccc1c5.zip
Bit string slice
-rw-r--r--src/gleam/bit_string.gleam35
-rw-r--r--src/gleam_stdlib.erl4
-rw-r--r--src/gleam_stdlib.js14
-rw-r--r--test/gleam/bit_string_test.gleam70
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() {