aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2023-10-26 12:13:33 +0100
committerLouis Pilfold <louis@lpil.uk>2023-10-26 12:24:40 +0100
commit82c7406c84e90c1dadb85fc65925565812dd28ae (patch)
treee11d97e64637464610c0c9cd2c845dd5ba97a1c1
parent368252c059ffd951958664013001b4037d6b8953 (diff)
downloadgleam_stdlib-82c7406c84e90c1dadb85fc65925565812dd28ae.tar.gz
gleam_stdlib-82c7406c84e90c1dadb85fc65925565812dd28ae.zip
Deprecate gleam/base
-rw-r--r--src/gleam/base.gleam42
-rw-r--r--src/gleam/bit_array.gleam47
-rw-r--r--src/gleam/string.gleam84
-rw-r--r--src/gleam_stdlib.erl57
-rw-r--r--src/gleam_stdlib.mjs5
-rw-r--r--test/gleam/bit_array_test.gleam86
6 files changed, 188 insertions, 133 deletions
diff --git a/src/gleam/base.gleam b/src/gleam/base.gleam
index 1cf9985..eab2f0b 100644
--- a/src/gleam/base.gleam
+++ b/src/gleam/base.gleam
@@ -1,47 +1,21 @@
import gleam/bit_array
-import gleam/string
-/// Encodes a BitArray into a base 64 encoded string.
-///
+@deprecated("Please use `base64_encode` in the `gleam/bit_array` module instead.")
pub fn encode64(input: BitArray, padding: Bool) -> String {
- let encoded = do_encode64(input)
- case padding {
- True -> encoded
- False -> string.replace(encoded, "=", "")
- }
+ bit_array.base64_encode(input, padding)
}
-@external(erlang, "base64", "encode")
-@external(javascript, "../gleam_stdlib.mjs", "encode64")
-fn do_encode64(a: BitArray) -> String
-
-/// Decodes a base 64 encoded string into a `BitArray`.
-///
+@deprecated("Please use `base64_decode` in the `gleam/bit_array` module instead.")
pub fn decode64(encoded: String) -> Result(BitArray, Nil) {
- let padded = case bit_array.byte_size(bit_array.from_string(encoded)) % 4 {
- 0 -> encoded
- n -> string.append(encoded, string.repeat("=", 4 - n))
- }
- do_decode64(padded)
+ bit_array.base64_decode(encoded)
}
-@external(erlang, "gleam_stdlib", "base_decode64")
-@external(javascript, "../gleam_stdlib.mjs", "decode64")
-fn do_decode64(a: String) -> Result(BitArray, Nil)
-
-/// Encodes a `BitArray` into a base 64 encoded string with URL and filename safe alphabet.
-///
+@deprecated("Please use `base64_url_encode` in the `gleam/bit_array` module instead.")
pub fn url_encode64(input: BitArray, padding: Bool) -> String {
- encode64(input, padding)
- |> string.replace("+", "-")
- |> string.replace("/", "_")
+ bit_array.base64_url_encode(input, padding)
}
-/// Decodes a base 64 encoded string with URL and filename safe alphabet into a `BitArray`.
-///
+@deprecated("Please use `base64_url_decode` in the `gleam/bit_array` module instead.")
pub fn url_decode64(encoded: String) -> Result(BitArray, Nil) {
- encoded
- |> string.replace("-", "+")
- |> string.replace("_", "/")
- |> decode64()
+ bit_array.base64_url_decode(encoded)
}
diff --git a/src/gleam/bit_array.gleam b/src/gleam/bit_array.gleam
index 4a50c62..b85782d 100644
--- a/src/gleam/bit_array.gleam
+++ b/src/gleam/bit_array.gleam
@@ -1,5 +1,7 @@
//// BitArrays are a sequence of binary data of any length.
+import gleam/string
+
/// Converts a UTF-8 `String` type into a `BitArray`.
///
@external(erlang, "gleam_stdlib", "identity")
@@ -100,3 +102,48 @@ fn do_to_string(a: BitArray) -> Result(String, Nil)
@external(erlang, "gleam_stdlib", "bit_array_concat")
@external(javascript, "../gleam_stdlib.mjs", "bit_array_concat")
pub fn concat(bit_arrays: List(BitArray)) -> BitArray
+
+/// Encodes a BitArray into a base 64 encoded string.
+///
+pub fn base64_encode(input: BitArray, padding: Bool) -> String {
+ let encoded = encode64(input)
+ case padding {
+ True -> encoded
+ False -> string.replace(encoded, "=", "")
+ }
+}
+
+@external(erlang, "base64", "encode")
+@external(javascript, "../gleam_stdlib.mjs", "encode64")
+fn encode64(a: BitArray) -> String
+
+/// Decodes a base 64 encoded string into a `BitArray`.
+///
+pub fn base64_decode(encoded: String) -> Result(BitArray, Nil) {
+ let padded = case byte_size(from_string(encoded)) % 4 {
+ 0 -> encoded
+ n -> string.append(encoded, string.repeat("=", 4 - n))
+ }
+ decode64(padded)
+}
+
+@external(erlang, "gleam_stdlib", "base_decode64")
+@external(javascript, "../gleam_stdlib.mjs", "decode64")
+fn decode64(a: String) -> Result(BitArray, Nil)
+
+/// Encodes a `BitArray` into a base 64 encoded string with URL and filename safe alphabet.
+///
+pub fn base64_url_encode(input: BitArray, padding: Bool) -> String {
+ base64_encode(input, padding)
+ |> string.replace("+", "-")
+ |> string.replace("/", "_")
+}
+
+/// Decodes a base 64 encoded string with URL and filename safe alphabet into a `BitArray`.
+///
+pub fn base64_url_decode(encoded: String) -> Result(BitArray, Nil) {
+ encoded
+ |> string.replace("-", "+")
+ |> string.replace("_", "/")
+ |> base64_decode()
+}
diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam
index 94c9dad..2e31a4b 100644
--- a/src/gleam/string.gleam
+++ b/src/gleam/string.gleam
@@ -6,12 +6,6 @@ import gleam/list
import gleam/option.{type Option, None, Some}
import gleam/order
import gleam/string_builder.{type StringBuilder}
-@target(erlang)
-import gleam/bit_array
-@target(erlang)
-import gleam/dynamic.{type Dynamic}
-@target(erlang)
-import gleam/result
/// Determines if a `String` is empty.
///
@@ -259,25 +253,9 @@ fn do_slice(string: String, idx: Int, len: Int) -> String {
/// "Lone Gunmen"
/// ```
///
-pub fn crop(from string: String, before substring: String) -> String {
- do_crop(string, substring)
-}
-
-@target(erlang)
-fn do_crop(string: String, substring: String) -> String {
- string
- |> erl_contains(substring)
- |> dynamic.string()
- |> result.unwrap(string)
-}
-
-@target(erlang)
-@external(erlang, "string", "find")
-fn erl_contains(a: String, b: String) -> Dynamic
-
-@target(javascript)
+@external(erlang, "gleam_stdlib", "crop_string")
@external(javascript, "../gleam_stdlib.mjs", "crop_string")
-fn do_crop(a: String, b: String) -> String
+pub fn crop(from string: String, before substring: String) -> String
/// Drops *n* graphemes from the left side of a `String`.
///
@@ -330,26 +308,9 @@ pub fn drop_right(from string: String, up_to num_graphemes: Int) -> String {
/// False
/// ```
///
-pub fn contains(does haystack: String, contain needle: String) -> Bool {
- do_contains(haystack, needle)
-}
-
-@target(erlang)
-fn do_contains(haystack: String, needle: String) -> Bool {
- haystack
- |> erl_contains(needle)
- |> dynamic.bit_array
- |> result.is_ok
-}
-
-@target(javascript)
-fn do_contains(haystack: String, needle: String) -> Bool {
- index_of(haystack, needle) != -1
-}
-
-@target(javascript)
-@external(javascript, "../gleam_stdlib.mjs", "index_of")
-fn index_of(a: String, b: String) -> Int
+@external(erlang, "gleam_stdlib", "contains_string")
+@external(javascript, "../gleam_stdlib.mjs", "contains_string")
+pub fn contains(does haystack: String, contain needle: String) -> Bool
/// Checks whether the first `String` starts with the second one.
///
@@ -755,7 +716,7 @@ pub fn to_utf_codepoints(string: String) -> List(UtfCodepoint) {
@target(erlang)
fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) {
- do_to_utf_codepoints_impl(bit_array.from_string(string), [])
+ do_to_utf_codepoints_impl(<<string:utf8>>, [])
|> list.reverse
}
@@ -803,38 +764,9 @@ fn string_to_codepoint_integer_list(a: String) -> List(Int)
/// "abc"
/// ```
///
-pub fn from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String {
- do_from_utf_codepoints(utf_codepoints)
-}
-
-@target(erlang)
-fn do_from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String {
- let assert Ok(string) =
- do_from_utf_codepoints_impl(utf_codepoints, bit_array.from_string(""))
- |> bit_array.to_string
- string
-}
-
-@target(erlang)
-fn do_from_utf_codepoints_impl(
- utf_codepoints: List(UtfCodepoint),
- acc: BitArray,
-) -> BitArray {
- case utf_codepoints {
- [first, ..rest] ->
- do_from_utf_codepoints_impl(rest, <<acc:bits, first:utf8_codepoint>>)
- [] -> acc
- }
-}
-
-@target(javascript)
-fn do_from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String {
- utf_codepoint_list_to_string(utf_codepoints)
-}
-
-@target(javascript)
+@external(erlang, "gleam_stdlib", "utf_codepoint_list_to_string")
@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_list_to_string")
-fn utf_codepoint_list_to_string(a: List(UtfCodepoint)) -> String
+pub fn from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String
/// Converts an integer to a `UtfCodepoint`.
///
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl
index 4c2a859..0ac4747 100644
--- a/src/gleam_stdlib.erl
+++ b/src/gleam_stdlib.erl
@@ -1,31 +1,33 @@
-module(gleam_stdlib).
--export([map_get/2, iodata_append/2, identity/1, decode_int/1, decode_bool/1,
- decode_float/1, decode_list/1, decode_option/2,
- decode_field/2, parse_int/1, parse_float/1, less_than/2,
- string_pop_grapheme/1, string_starts_with/2, wrap_list/1,
- string_ends_with/2, string_pad/4, decode_map/1, uri_parse/1,
- bit_array_int_to_u32/1, bit_array_int_from_u32/1, decode_result/1,
- bit_array_slice/3, decode_bit_array/1, compile_regex/2, regex_scan/2,
- percent_encode/1, percent_decode/1, regex_check/2, regex_split/2,
- base_decode64/1, parse_query/1, bit_array_concat/1, size_of_tuple/1,
- decode_tuple/1, decode_tuple2/1, decode_tuple3/1, decode_tuple4/1,
- 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]).
+-export([
+ map_get/2, iodata_append/2, identity/1, decode_int/1, decode_bool/1,
+ decode_float/1, decode_list/1, decode_option/2, decode_field/2, parse_int/1,
+ parse_float/1, less_than/2, string_pop_grapheme/1, string_starts_with/2,
+ wrap_list/1, string_ends_with/2, string_pad/4, decode_map/1, uri_parse/1,
+ bit_array_int_to_u32/1, bit_array_int_from_u32/1, decode_result/1,
+ bit_array_slice/3, decode_bit_array/1, compile_regex/2, regex_scan/2,
+ percent_encode/1, percent_decode/1, regex_check/2, regex_split/2,
+ base_decode64/1, parse_query/1, bit_array_concat/1, size_of_tuple/1,
+ decode_tuple/1, decode_tuple2/1, decode_tuple3/1, decode_tuple4/1,
+ 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
+]).
%% Taken from OTP's uri_string module
-define(DEC2HEX(X),
- if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0;
- ((X) >= 10) andalso ((X) =< 15) -> (X) + $A - 10
- end).
+ if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0;
+ ((X) >= 10) andalso ((X) =< 15) -> (X) + $A - 10
+ end).
%% Taken from OTP's uri_string module
-define(HEX2DEC(X),
- if ((X) >= $0) andalso ((X) =< $9) -> (X) - $0;
- ((X) >= $A) andalso ((X) =< $F) -> (X) - $A + 10;
- ((X) >= $a) andalso ((X) =< $f) -> (X) - $a + 10
- end).
+ if ((X) >= $0) andalso ((X) =< $9) -> (X) - $0;
+ ((X) >= $A) andalso ((X) =< $F) -> (X) - $A + 10;
+ ((X) >= $a) andalso ((X) =< $f) -> (X) - $a + 10
+ end).
-define(is_lowercase_char(X), (X > 96 andalso X < 123)).
-define(is_underscore_char(X), (X == 95)).
@@ -473,3 +475,18 @@ inspect_maybe_utf8_string(Binary, Acc) ->
float_to_string(Float) when is_float(Float) ->
erlang:iolist_to_binary(io_lib_format:fwrite_g(Float)).
+
+utf_codepoint_list_to_string(List) ->
+ case unicode:characters_to_binary(List) of
+ {error, _} -> erlang:error({gleam_error, {string_invalid_utf8, List}});
+ Binary -> Binary
+ end.
+
+crop_string(String, Prefix) ->
+ case string:find(String, Prefix) of
+ nomatch -> String;
+ New -> New
+ end.
+
+contains_string(String, Substring) ->
+ is_bitstring(string:find(String, Substring)).
diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs
index 5c55b24..645e22a 100644
--- a/src/gleam_stdlib.mjs
+++ b/src/gleam_stdlib.mjs
@@ -9,7 +9,6 @@ import {
toBitArray,
NonEmpty,
CustomType,
- BitArray,
} from "./gleam.mjs";
import {
CompileError as RegexCompileError,
@@ -225,8 +224,8 @@ export function crop_string(string, substring) {
return string.substring(string.indexOf(substring));
}
-export function index_of(haystack, needle) {
- return haystack.indexOf(needle) | 0;
+export function contains_string(haystack, needle) {
+ return haystack.indexOf(needle) >= 0;
}
export function starts_with(haystack, needle) {
diff --git a/test/gleam/bit_array_test.gleam b/test/gleam/bit_array_test.gleam
index 65a8009..7095205 100644
--- a/test/gleam/bit_array_test.gleam
+++ b/test/gleam/bit_array_test.gleam
@@ -133,3 +133,89 @@ pub fn is_utf8_test() {
|> bit_array.is_utf8
|> should.be_false
}
+
+pub fn base64_encode_test() {
+ <<255, 127, 254, 252>>
+ |> bit_array.base64_encode(True)
+ |> should.equal("/3/+/A==")
+
+ <<255, 127, 254, 252>>
+ |> bit_array.base64_encode(False)
+ |> should.equal("/3/+/A")
+
+ <<0, 0, 0>>
+ |> bit_array.base64_encode(True)
+ |> should.equal("AAAA")
+
+ <<>>
+ |> bit_array.base64_encode(True)
+ |> should.equal("")
+}
+
+pub fn base64_decode_test() {
+ "/3/+/A=="
+ |> bit_array.base64_decode()
+ |> should.equal(Ok(<<255, 127, 254, 252>>))
+
+ "/3/+/A"
+ |> bit_array.base64_decode()
+ |> should.equal(Ok(<<255, 127, 254, 252>>))
+
+ "AAAA"
+ |> bit_array.base64_decode()
+ |> should.equal(Ok(<<0, 0, 0>>))
+
+ ""
+ |> bit_array.base64_decode()
+ |> should.equal(Ok(<<>>))
+
+ ")!"
+ |> bit_array.base64_decode()
+ |> should.equal(Error(Nil))
+}
+
+pub fn base64_url_encode_test() {
+ <<255, 127, 254, 252>>
+ |> bit_array.base64_url_encode(True)
+ |> should.equal("_3_-_A==")
+
+ <<255, 127, 254, 252>>
+ |> bit_array.base64_url_encode(False)
+ |> should.equal("_3_-_A")
+
+ <<0, 0, 0>>
+ |> bit_array.base64_url_encode(True)
+ |> should.equal("AAAA")
+
+ <<>>
+ |> bit_array.base64_url_encode(True)
+ |> should.equal("")
+}
+
+pub fn base64_url_decode_test() {
+ "_3_-_A=="
+ |> bit_array.base64_url_decode()
+ |> should.equal(Ok(<<255, 127, 254, 252>>))
+
+ "_3_-_A"
+ |> bit_array.base64_url_decode()
+ |> should.equal(Ok(<<255, 127, 254, 252>>))
+
+ "AAAA"
+ |> bit_array.base64_url_decode()
+ |> should.equal(Ok(<<0, 0, 0>>))
+
+ ""
+ |> bit_array.base64_url_decode()
+ |> should.equal(Ok(<<>>))
+
+ ")!"
+ |> bit_array.base64_url_decode()
+ |> should.equal(Error(Nil))
+}
+
+pub fn decode64_crash_regression_1_test() {
+ "aGktdGhlcmU.uWUWvrAleKQ2jsWcU97H-RPJ5qRRcE_s"
+ |> bit_array.base64_decode()
+ |> should.equal(Error(Nil))
+}