diff options
author | Louis Pilfold <louis@lpil.uk> | 2023-10-26 12:13:33 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2023-10-26 12:24:40 +0100 |
commit | 82c7406c84e90c1dadb85fc65925565812dd28ae (patch) | |
tree | e11d97e64637464610c0c9cd2c845dd5ba97a1c1 | |
parent | 368252c059ffd951958664013001b4037d6b8953 (diff) | |
download | gleam_stdlib-82c7406c84e90c1dadb85fc65925565812dd28ae.tar.gz gleam_stdlib-82c7406c84e90c1dadb85fc65925565812dd28ae.zip |
Deprecate gleam/base
-rw-r--r-- | src/gleam/base.gleam | 42 | ||||
-rw-r--r-- | src/gleam/bit_array.gleam | 47 | ||||
-rw-r--r-- | src/gleam/string.gleam | 84 | ||||
-rw-r--r-- | src/gleam_stdlib.erl | 57 | ||||
-rw-r--r-- | src/gleam_stdlib.mjs | 5 | ||||
-rw-r--r-- | test/gleam/bit_array_test.gleam | 86 |
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)) +} |