Add Gleam language integration to Elixir project
- Rename Gleam module from encoding_simple to encoding - Move Gleam files from src/aprs/ to src/aprsme/ to match project namespace - Create custom Mix task for Gleam compilation (lib/mix/tasks/gleam_compile.ex) - Update EncodingUtils to wrap Gleam implementation instead of pure Elixir - Add Gleam dependencies to mix.exs and configure build paths - Update Mix aliases to include Gleam compilation in test and compile tasks - Add Gleam support to GitHub Actions CI workflow with caching - Add GLEAM_INTEGRATION.md documentation - All 357 tests passing with Gleam integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
92585ae34f
commit
00a8f996f4
267 changed files with 42488 additions and 115 deletions
29
.github/workflows/elixir.yaml
vendored
29
.github/workflows/elixir.yaml
vendored
|
|
@ -59,6 +59,31 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Step: Install Gleam
|
||||
- name: Set up Gleam
|
||||
uses: gleam-lang/setup-gleam@v1
|
||||
with:
|
||||
gleam-version: "1.5.1"
|
||||
|
||||
# Step: Install mix_gleam archive
|
||||
- name: Install mix_gleam
|
||||
run: mix archive.install hex mix_gleam 0.6.2 --force
|
||||
|
||||
# Step: Cache Gleam packages
|
||||
- name: Cache Gleam packages
|
||||
id: cache-gleam
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-gleam-packages
|
||||
with:
|
||||
path: |
|
||||
build
|
||||
~/.cache/gleam
|
||||
key: ${{ runner.os }}-gleam-${{ env.cache-name }}-${{ hashFiles('**/gleam.toml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gleam-${{ env.cache-name }}-
|
||||
${{ runner.os }}-gleam-
|
||||
|
||||
# Step: Define how to cache deps. Restores existing cache if present.
|
||||
- name: Cache deps
|
||||
id: cache-deps
|
||||
|
|
@ -104,6 +129,10 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: mix deps.get
|
||||
|
||||
# Step: Compile Gleam code first
|
||||
- name: Compile Gleam code
|
||||
run: mix gleam_compile
|
||||
|
||||
# Step: Compile the project treating any warnings as errors.
|
||||
# Customize this step if a different behavior is desired.
|
||||
- name: Compiles without warnings
|
||||
|
|
|
|||
85
GLEAM_INTEGRATION.md
Normal file
85
GLEAM_INTEGRATION.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Gleam Integration Guide
|
||||
|
||||
This document describes how Gleam has been integrated into the APRS.me Elixir project.
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Mix Gleam Archive**: Installed via `mix archive.install hex mix_gleam`
|
||||
2. **Dependencies**: Added to mix.exs:
|
||||
```elixir
|
||||
{:gleam_stdlib, ">= 0.60.0 and < 1.0.0", app: false, override: true},
|
||||
{:gleeunit, "~> 1.0", only: [:dev, :test], runtime: false, app: false}
|
||||
```
|
||||
3. **Project Configuration**: Added to mix.exs project config:
|
||||
```elixir
|
||||
archives: [mix_gleam: "~> 0.6"],
|
||||
erlc_paths: ["build/dev/erlang/aprsme/_gleam_artefacts", "src"],
|
||||
erlc_include_path: "build/dev/erlang/aprsme/include",
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
- `/src/` - Gleam source files
|
||||
- `/src/aprs/` - APRS-specific Gleam modules
|
||||
- `/gleam.toml` - Gleam project configuration
|
||||
|
||||
## Compilation
|
||||
|
||||
The project is configured to automatically compile Gleam code when running tests or compiling:
|
||||
|
||||
```bash
|
||||
# For development
|
||||
mix compile.gleam && mix compile
|
||||
|
||||
# For tests (automatically compiles Gleam)
|
||||
mix test
|
||||
|
||||
# Manual compilation if needed
|
||||
mix gleam_compile
|
||||
```
|
||||
|
||||
The custom `gleam_compile` task handles:
|
||||
- Running the mix_gleam compiler when available
|
||||
- Falling back to the `gleam` binary if mix_gleam isn't installed
|
||||
- Copying compiled beam files to the appropriate build directory
|
||||
|
||||
## Module Naming
|
||||
|
||||
Gleam modules are compiled with `@` as the separator in BEAM files:
|
||||
- Gleam: `aprs/encoding`
|
||||
- BEAM: `aprs@encoding`
|
||||
- Elixir: `:aprs@encoding`
|
||||
|
||||
## Current Modules
|
||||
|
||||
### encoding.gleam
|
||||
|
||||
A type-safe implementation of encoding utilities:
|
||||
- `sanitize_string/1` - Ensures strings are valid UTF-8, handles Latin-1 conversion
|
||||
- `to_float_safe/1` - Safe string to float conversion with Option type
|
||||
- `to_hex/1` - Convert binary to hex string representation
|
||||
- `has_weather_data/4` - Check if packet contains weather data
|
||||
- `encoding_info/1` - Get encoding information about a binary
|
||||
|
||||
## Elixir Integration
|
||||
|
||||
The `Aprsme.EncodingUtils` module now wraps the Gleam implementation, replacing the original pure Elixir version. The Gleam implementation provides:
|
||||
- Type-safe string sanitization with Latin-1 to UTF-8 conversion
|
||||
- Proper handling of control characters
|
||||
- Safe float conversion with bounds checking
|
||||
- Consistent encoding validation
|
||||
|
||||
The migration was completed with all tests passing and no breaking changes to the API.
|
||||
|
||||
## Testing
|
||||
|
||||
The original test suite at `/test/aprsme/encoding_utils_test.exs` continues to work with the Gleam implementation:
|
||||
```bash
|
||||
mix test test/aprsme/encoding_utils_test.exs
|
||||
```
|
||||
|
||||
## Future Considerations
|
||||
|
||||
1. Add Gleam compiler to Mix.compilers() once the integration is more stable
|
||||
2. Consider migrating more type-critical modules to Gleam
|
||||
3. Explore using Gleam's type system for packet validation
|
||||
100
build/dev/erlang/aprsme/_gleam_artefacts/aprsme@@main.erl
Normal file
100
build/dev/erlang/aprsme/_gleam_artefacts/aprsme@@main.erl
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
-module('aprsme@@main').
|
||||
-export([run/1]).
|
||||
|
||||
-define(red, "\e[31;1m").
|
||||
-define(grey, "\e[90m").
|
||||
-define(reset_color, "\e[39m").
|
||||
-define(reset_all, "\e[0m").
|
||||
|
||||
run(Module) ->
|
||||
io:setopts(standard_io, [binary, {encoding, utf8}]),
|
||||
io:setopts(standard_error, [{encoding, utf8}]),
|
||||
process_flag(trap_exit, true),
|
||||
Pid = spawn_link(fun() -> run_module(Module) end),
|
||||
receive
|
||||
{'EXIT', Pid, {Reason, StackTrace}} ->
|
||||
print_error(exit, Reason, StackTrace),
|
||||
init:stop(1)
|
||||
end.
|
||||
|
||||
run_module(Module) ->
|
||||
try
|
||||
{ok, _} = application:ensure_all_started('aprsme'),
|
||||
erlang:process_flag(trap_exit, false),
|
||||
Module:main(),
|
||||
erlang:halt(0)
|
||||
catch
|
||||
Class:Reason:StackTrace ->
|
||||
print_error(Class, Reason, StackTrace),
|
||||
init:stop(1)
|
||||
end.
|
||||
|
||||
print_error(Class, Error, Stacktrace) ->
|
||||
Printed = [
|
||||
?red, "runtime error", ?reset_color, ": ", error_class(Class, Error), ?reset_all,
|
||||
"\n\n",
|
||||
error_message(Error),
|
||||
"\n\n",
|
||||
error_details(Class, Error),
|
||||
"stacktrace:\n",
|
||||
[error_frame(Line) || Line <- refine_first(Error, Stacktrace)]
|
||||
],
|
||||
io:format(standard_error, "~ts~n", [Printed]).
|
||||
|
||||
refine_first(#{gleam_error := _, line := L}, [{M, F, A, [{file, Fi} | _]} | S]) ->
|
||||
[{M, F, A, [{file, Fi}, {line, L}]} | S];
|
||||
refine_first(_, S) ->
|
||||
S.
|
||||
|
||||
error_class(_, #{gleam_error := panic}) -> "panic";
|
||||
error_class(_, #{gleam_error := todo}) -> "todo";
|
||||
error_class(_, #{gleam_error := let_assert}) -> "let assert";
|
||||
error_class(_, #{gleam_error := assert}) -> "assert";
|
||||
error_class(Class, _) -> ["Erlang ", atom_to_binary(Class)].
|
||||
|
||||
error_message(#{gleam_error := _, message := M}) ->
|
||||
M;
|
||||
error_message(undef) ->
|
||||
<<"A function was called but it did not exist."/utf8 >>;
|
||||
error_message({case_clause, _}) ->
|
||||
<<"No pattern matched in an Erlang case expression."/utf8>>;
|
||||
error_message({badmatch, _}) ->
|
||||
<<"An Erlang assignment pattern did not match."/utf8>>;
|
||||
error_message(function_clause) ->
|
||||
<<"No Erlang function clause matched the arguments it was called with."/utf8>>;
|
||||
error_message(_) ->
|
||||
<<"An error occurred outside of Gleam."/utf8>>.
|
||||
|
||||
error_details(_, #{gleam_error := let_assert, value := V}) ->
|
||||
["unmatched value:\n ", print_term(V), $\n, $\n];
|
||||
error_details(_, {case_clause, V}) ->
|
||||
["unmatched value:\n ", print_term(V), $\n, $\n];
|
||||
error_details(_, {badmatch, V}) ->
|
||||
["unmatched value:\n ", print_term(V), $\n, $\n];
|
||||
error_details(_, #{gleam_error := _}) ->
|
||||
[];
|
||||
error_details(error, function_clause) ->
|
||||
[];
|
||||
error_details(error, undef) ->
|
||||
[];
|
||||
error_details(C, E) ->
|
||||
["erlang:", atom_to_binary(C), $(, print_term(E), $), $\n, $\n].
|
||||
|
||||
print_term(T) ->
|
||||
try
|
||||
gleam@string:inspect(T)
|
||||
catch
|
||||
_:_ -> io_lib:format("~p", [T])
|
||||
end.
|
||||
|
||||
error_frame({?MODULE, _, _, _}) -> [];
|
||||
error_frame({erl_eval, _, _, _}) -> [];
|
||||
error_frame({init, _, _, _}) -> [];
|
||||
error_frame({M, F, _, O}) ->
|
||||
M1 = string:replace(atom_to_binary(M), "@", "/", all),
|
||||
[" ", M1, $., atom_to_binary(F), error_frame_end(O), $\n].
|
||||
|
||||
error_frame_end([{file, Fi}, {line, L} | _]) ->
|
||||
[?grey, $\s, Fi, $:, integer_to_binary(L), ?reset_all];
|
||||
error_frame_end(_) ->
|
||||
[?grey, " unknown source", ?reset_all].
|
||||
BIN
build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache
Normal file
BIN
build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache
Normal file
Binary file not shown.
Binary file not shown.
275
build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.erl
Normal file
275
build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.erl
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
-module(aprsme@encoding).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/aprsme/encoding.gleam").
|
||||
-export([sanitize_string/1, to_float_safe/1, to_hex/1, has_weather_data/4, encoding_info/1]).
|
||||
-export_type([encoding_info/0]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-type encoding_info() :: {encoding_info,
|
||||
boolean(),
|
||||
integer(),
|
||||
gleam@option:option(integer()),
|
||||
gleam@option:option(integer())}.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 29).
|
||||
-spec do_bit_array_to_list(bitstring(), list(integer())) -> list(integer()).
|
||||
do_bit_array_to_list(Input, Acc) ->
|
||||
case erlang:byte_size(Input) of
|
||||
0 ->
|
||||
Acc;
|
||||
|
||||
_ ->
|
||||
case gleam_stdlib:bit_array_slice(Input, 0, 1) of
|
||||
{ok, <<Byte>>} ->
|
||||
case gleam_stdlib:bit_array_slice(
|
||||
Input,
|
||||
1,
|
||||
erlang:byte_size(Input) - 1
|
||||
) of
|
||||
{ok, Rest} ->
|
||||
do_bit_array_to_list(Rest, [Byte | Acc]);
|
||||
|
||||
{error, _} ->
|
||||
[Byte | Acc]
|
||||
end;
|
||||
|
||||
_ ->
|
||||
Acc
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 24).
|
||||
?DOC(" Convert BitArray to list of bytes\n").
|
||||
-spec bit_array_to_list(bitstring()) -> list(integer()).
|
||||
bit_array_to_list(Input) ->
|
||||
_pipe = do_bit_array_to_list(Input, []),
|
||||
lists:reverse(_pipe).
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 48).
|
||||
?DOC(" Convert latin1 encoded bytes to UTF-8 string\n").
|
||||
-spec latin1_to_utf8_string(bitstring()) -> binary().
|
||||
latin1_to_utf8_string(Input) ->
|
||||
_pipe = Input,
|
||||
_pipe@1 = bit_array_to_list(_pipe),
|
||||
_pipe@2 = gleam@list:filter_map(_pipe@1, fun(Byte) -> case Byte of
|
||||
B when B =< 127 ->
|
||||
case gleam@bit_array:to_string(<<B>>) of
|
||||
{ok, S} ->
|
||||
{ok, S};
|
||||
|
||||
{error, _} ->
|
||||
{error, nil}
|
||||
end;
|
||||
|
||||
B@1 ->
|
||||
Byte1 = 192 + (B@1 div 64),
|
||||
Byte2 = 128 + (B@1 rem 64),
|
||||
case gleam@bit_array:to_string(<<Byte1, Byte2>>) of
|
||||
{ok, S@1} ->
|
||||
{ok, S@1};
|
||||
|
||||
{error, _} ->
|
||||
{error, nil}
|
||||
end
|
||||
end end),
|
||||
gleam@string:join(_pipe@2, <<""/utf8>>).
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 77).
|
||||
?DOC(" Remove control characters from a string\n").
|
||||
-spec clean_control_characters(binary()) -> binary().
|
||||
clean_control_characters(S) ->
|
||||
_pipe = S,
|
||||
_pipe@1 = gleam@string:to_graphemes(_pipe),
|
||||
_pipe@2 = gleam@list:filter(
|
||||
_pipe@1,
|
||||
fun(Grapheme) -> case gleam@string:to_utf_codepoints(Grapheme) of
|
||||
[Codepoint] ->
|
||||
Cp = gleam_stdlib:identity(Codepoint),
|
||||
case Cp of
|
||||
9 ->
|
||||
true;
|
||||
|
||||
10 ->
|
||||
true;
|
||||
|
||||
13 ->
|
||||
true;
|
||||
|
||||
C when (C >= 0) andalso (C =< 31) ->
|
||||
false;
|
||||
|
||||
127 ->
|
||||
false;
|
||||
|
||||
C@1 when (C@1 >= 128) andalso (C@1 =< 159) ->
|
||||
false;
|
||||
|
||||
_ ->
|
||||
true
|
||||
end;
|
||||
|
||||
_ ->
|
||||
true
|
||||
end end
|
||||
),
|
||||
_pipe@3 = gleam@string:join(_pipe@2, <<""/utf8>>),
|
||||
gleam@string:trim(_pipe@3).
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 10).
|
||||
?DOC(
|
||||
" Sanitizes a binary to ensure it can be safely JSON encoded\n"
|
||||
" Handles latin1 conversion and removes control characters\n"
|
||||
).
|
||||
-spec sanitize_string(bitstring()) -> binary().
|
||||
sanitize_string(Input) ->
|
||||
case gleam@bit_array:to_string(Input) of
|
||||
{ok, S} ->
|
||||
clean_control_characters(S);
|
||||
|
||||
{error, _} ->
|
||||
_pipe = Input,
|
||||
_pipe@1 = latin1_to_utf8_string(_pipe),
|
||||
clean_control_characters(_pipe@1)
|
||||
end.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 104).
|
||||
?DOC(" Type-safe float conversion with validation\n").
|
||||
-spec to_float_safe(binary()) -> gleam@option:option(float()).
|
||||
to_float_safe(Value) ->
|
||||
Sanitized = begin
|
||||
_pipe = Value,
|
||||
_pipe@1 = gleam@string:trim(_pipe),
|
||||
gleam@string:slice(_pipe@1, 0, 30)
|
||||
end,
|
||||
case gleam_stdlib:parse_float(Sanitized) of
|
||||
{ok, F} ->
|
||||
case F of
|
||||
X when (X > -9.0e15) andalso (X < 9.0e15) ->
|
||||
{some, F};
|
||||
|
||||
_ ->
|
||||
none
|
||||
end;
|
||||
|
||||
{error, _} ->
|
||||
none
|
||||
end.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 129).
|
||||
-spec do_to_hex(bitstring(), list(binary())) -> list(binary()).
|
||||
do_to_hex(Input, Acc) ->
|
||||
case gleam_stdlib:bit_array_slice(Input, 0, 1) of
|
||||
{ok, <<Byte>>} ->
|
||||
Rest = case gleam_stdlib:bit_array_slice(
|
||||
Input,
|
||||
1,
|
||||
erlang:byte_size(Input) - 1
|
||||
) of
|
||||
{ok, R} ->
|
||||
R;
|
||||
|
||||
{error, _} ->
|
||||
<<>>
|
||||
end,
|
||||
Hex = gleam@int:to_base16(Byte),
|
||||
Padded = case string:length(Hex) of
|
||||
1 ->
|
||||
<<"0"/utf8, Hex/binary>>;
|
||||
|
||||
_ ->
|
||||
Hex
|
||||
end,
|
||||
do_to_hex(Rest, [Padded | Acc]);
|
||||
|
||||
_ ->
|
||||
Acc
|
||||
end.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 122).
|
||||
?DOC(" Convert binary to hex string\n").
|
||||
-spec to_hex(bitstring()) -> binary().
|
||||
to_hex(Input) ->
|
||||
_pipe = do_to_hex(Input, []),
|
||||
_pipe@1 = lists:reverse(_pipe),
|
||||
_pipe@2 = gleam@string:join(_pipe@1, <<""/utf8>>),
|
||||
string:uppercase(_pipe@2).
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 148).
|
||||
?DOC(" Check if a value looks like it has weather data\n").
|
||||
-spec has_weather_data(
|
||||
gleam@option:option(float()),
|
||||
gleam@option:option(float()),
|
||||
gleam@option:option(float()),
|
||||
gleam@option:option(float())
|
||||
) -> boolean().
|
||||
has_weather_data(Temperature, Humidity, Wind_speed, Pressure) ->
|
||||
case {Temperature, Humidity, Wind_speed, Pressure} of
|
||||
{{some, _}, _, _, _} ->
|
||||
true;
|
||||
|
||||
{_, {some, _}, _, _} ->
|
||||
true;
|
||||
|
||||
{_, _, {some, _}, _} ->
|
||||
true;
|
||||
|
||||
{_, _, _, {some, _}} ->
|
||||
true;
|
||||
|
||||
{_, _, _, _} ->
|
||||
false
|
||||
end.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 192).
|
||||
-spec find_invalid_byte_position(bitstring(), integer()) -> gleam@option:option(integer()).
|
||||
find_invalid_byte_position(Input, Pos) ->
|
||||
case erlang:byte_size(Input) of
|
||||
0 ->
|
||||
none;
|
||||
|
||||
_ ->
|
||||
case gleam_stdlib:bit_array_slice(Input, 0, 1) of
|
||||
{ok, Byte_slice} ->
|
||||
case gleam@bit_array:to_string(Byte_slice) of
|
||||
{ok, _} ->
|
||||
case gleam_stdlib:bit_array_slice(
|
||||
Input,
|
||||
1,
|
||||
erlang:byte_size(Input) - 1
|
||||
) of
|
||||
{ok, Rest} ->
|
||||
find_invalid_byte_position(Rest, Pos + 1);
|
||||
|
||||
{error, _} ->
|
||||
{some, Pos}
|
||||
end;
|
||||
|
||||
{error, _} ->
|
||||
{some, Pos}
|
||||
end;
|
||||
|
||||
{error, _} ->
|
||||
{some, Pos}
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/aprsme/encoding.gleam", 170).
|
||||
?DOC(" Get encoding information about a binary\n").
|
||||
-spec encoding_info(bitstring()) -> encoding_info().
|
||||
encoding_info(Input) ->
|
||||
Byte_count = erlang:byte_size(Input),
|
||||
case gleam@bit_array:to_string(Input) of
|
||||
{ok, S} ->
|
||||
{encoding_info, true, Byte_count, {some, string:length(S)}, none};
|
||||
|
||||
{error, _} ->
|
||||
Invalid_pos = find_invalid_byte_position(Input, 0),
|
||||
{encoding_info, false, Byte_count, none, Invalid_pos}
|
||||
end.
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import {
|
||||
parseTimestamp,
|
||||
getTrailId,
|
||||
saveMapState,
|
||||
safePushEvent,
|
||||
isLiveViewConnected,
|
||||
getLiveSocket
|
||||
} from '../../../assets/js/map_helpers';
|
||||
|
||||
describe('map_helpers', () => {
|
||||
describe('parseTimestamp', () => {
|
||||
test('returns current time for null/undefined', () => {
|
||||
const before = Date.now();
|
||||
const result = parseTimestamp(null);
|
||||
const after = Date.now();
|
||||
expect(result).toBeGreaterThanOrEqual(before);
|
||||
expect(result).toBeLessThanOrEqual(after);
|
||||
});
|
||||
|
||||
test('returns number timestamp as-is', () => {
|
||||
const timestamp = 1234567890;
|
||||
expect(parseTimestamp(timestamp)).toBe(timestamp);
|
||||
});
|
||||
|
||||
test('parses string timestamp', () => {
|
||||
const dateStr = '2024-01-01T00:00:00Z';
|
||||
const expected = new Date(dateStr).getTime();
|
||||
expect(parseTimestamp(dateStr)).toBe(expected);
|
||||
});
|
||||
|
||||
test('returns current time for invalid input', () => {
|
||||
const before = Date.now();
|
||||
const result = parseTimestamp({});
|
||||
const after = Date.now();
|
||||
expect(result).toBeGreaterThanOrEqual(before);
|
||||
expect(result).toBeLessThanOrEqual(after);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTrailId', () => {
|
||||
test('prioritizes callsign_group', () => {
|
||||
const data = {
|
||||
callsign_group: 'GROUP-1',
|
||||
callsign: 'CALL-1',
|
||||
id: 'ID-1'
|
||||
};
|
||||
expect(getTrailId(data)).toBe('GROUP-1');
|
||||
});
|
||||
|
||||
test('falls back to callsign when no callsign_group', () => {
|
||||
const data = {
|
||||
callsign: 'CALL-1',
|
||||
id: 'ID-1'
|
||||
};
|
||||
expect(getTrailId(data)).toBe('CALL-1');
|
||||
});
|
||||
|
||||
test('falls back to id when no callsign_group or callsign', () => {
|
||||
const data = {
|
||||
id: 'ID-1'
|
||||
};
|
||||
expect(getTrailId(data)).toBe('ID-1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveMapState', () => {
|
||||
let mockMap: any;
|
||||
let mockPushEvent: any;
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock localStorage
|
||||
const localStorageMock = {
|
||||
setItem: vi.fn()
|
||||
};
|
||||
Object.defineProperty(window, 'localStorage', {
|
||||
value: localStorageMock,
|
||||
writable: true
|
||||
});
|
||||
|
||||
// Mock map object
|
||||
mockMap = {
|
||||
getCenter: vi.fn().mockReturnValue({ lat: 40.7128, lng: -74.0060 }),
|
||||
getZoom: vi.fn().mockReturnValue(10),
|
||||
getBounds: vi.fn().mockReturnValue({
|
||||
getNorth: vi.fn().mockReturnValue(41.0),
|
||||
getSouth: vi.fn().mockReturnValue(40.0),
|
||||
getEast: vi.fn().mockReturnValue(-73.0),
|
||||
getWest: vi.fn().mockReturnValue(-75.0)
|
||||
})
|
||||
};
|
||||
|
||||
mockPushEvent = vi.fn();
|
||||
});
|
||||
|
||||
test('saves truncated coordinates to localStorage', () => {
|
||||
saveMapState(mockMap, mockPushEvent);
|
||||
|
||||
expect(localStorage.setItem).toHaveBeenCalledWith(
|
||||
'aprs_map_state',
|
||||
JSON.stringify({ lat: 40.7128, lng: -74.006, zoom: 10 })
|
||||
);
|
||||
});
|
||||
|
||||
test('pushes event with map state and bounds', () => {
|
||||
saveMapState(mockMap, mockPushEvent);
|
||||
|
||||
expect(mockPushEvent).toHaveBeenCalledWith('update_map_state', {
|
||||
center: { lat: 40.7128, lng: -74.006 },
|
||||
zoom: 10,
|
||||
bounds: {
|
||||
north: 41.0,
|
||||
south: 40.0,
|
||||
east: -73.0,
|
||||
west: -75.0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('truncates coordinates to 5 decimal places', () => {
|
||||
mockMap.getCenter.mockReturnValue({ lat: 40.71281234567, lng: -74.00601234567 });
|
||||
|
||||
saveMapState(mockMap, mockPushEvent);
|
||||
|
||||
const call = mockPushEvent.mock.calls[0][1];
|
||||
expect(call.center.lat).toBe(40.71281);
|
||||
expect(call.center.lng).toBe(-74.00601);
|
||||
});
|
||||
});
|
||||
|
||||
describe('safePushEvent', () => {
|
||||
test('calls pushEvent and returns true on success', () => {
|
||||
const mockPushEvent = vi.fn();
|
||||
const result = safePushEvent(mockPushEvent, 'test_event', { data: 'test' });
|
||||
|
||||
expect(mockPushEvent).toHaveBeenCalledWith('test_event', { data: 'test' });
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('returns false when pushEvent is undefined', () => {
|
||||
const result = safePushEvent(undefined, 'test_event', { data: 'test' });
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('catches error and returns false', () => {
|
||||
const mockPushEvent = vi.fn().mockImplementation(() => {
|
||||
throw new Error('LiveView not connected');
|
||||
});
|
||||
|
||||
const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
|
||||
const result = safePushEvent(mockPushEvent, 'test_event', { data: 'test' });
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(consoleSpy).toHaveBeenCalledWith('Unable to send test_event event - LiveView disconnected');
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('LiveView socket helpers', () => {
|
||||
afterEach(() => {
|
||||
// Clean up window.liveSocket
|
||||
delete (window as any).liveSocket;
|
||||
});
|
||||
|
||||
test('isLiveViewConnected returns true when socket exists', () => {
|
||||
(window as any).liveSocket = { connected: true };
|
||||
expect(isLiveViewConnected()).toBe(true);
|
||||
});
|
||||
|
||||
test('isLiveViewConnected returns false when socket missing', () => {
|
||||
expect(isLiveViewConnected()).toBe(false);
|
||||
});
|
||||
|
||||
test('getLiveSocket returns the socket', () => {
|
||||
const mockSocket = { connected: true, pushHistoryPatch: vi.fn() };
|
||||
(window as any).liveSocket = mockSocket;
|
||||
|
||||
expect(getLiveSocket()).toBe(mockSocket);
|
||||
});
|
||||
|
||||
test('getLiveSocket returns undefined when missing', () => {
|
||||
expect(getLiveSocket()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
182
build/dev/erlang/aprsme/_gleam_artefacts/gleam@@compile.erl
Normal file
182
build/dev/erlang/aprsme/_gleam_artefacts/gleam@@compile.erl
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env escript
|
||||
-mode(compile).
|
||||
|
||||
% TODO: Don't concurrently print warnings and errors
|
||||
% TODO: Some tests
|
||||
|
||||
main(_) ->
|
||||
ok = io:setopts([binary, {encoding, utf8}]),
|
||||
ok = configure_logging(),
|
||||
compile_package_loop().
|
||||
|
||||
compile_package_loop() ->
|
||||
case io:get_line("") of
|
||||
eof -> ok;
|
||||
Line ->
|
||||
Chars = unicode:characters_to_list(Line),
|
||||
{ok, Tokens, _} = erl_scan:string(Chars),
|
||||
{ok, {Lib, Out, Modules}} = erl_parse:parse_term(Tokens),
|
||||
case compile_package(Lib, Out, Modules) of
|
||||
{ok, ModuleNames} ->
|
||||
PrintModuleName = fun(ModuleName) ->
|
||||
io:put_chars("gleam-compile-module:" ++ atom_to_list(ModuleName) ++ "\n")
|
||||
end,
|
||||
lists:map(PrintModuleName, ModuleNames),
|
||||
io:put_chars("gleam-compile-result-ok\n");
|
||||
err ->
|
||||
io:put_chars("gleam-compile-result-error\n")
|
||||
end,
|
||||
compile_package_loop()
|
||||
end.
|
||||
|
||||
compile_package(Lib, Out, Modules) ->
|
||||
IsElixirModule = fun(Module) ->
|
||||
filename:extension(Module) =:= ".ex"
|
||||
end,
|
||||
{ElixirModules, ErlangModules} = lists:partition(IsElixirModule, Modules),
|
||||
ok = filelib:ensure_dir([Out, $/]),
|
||||
ok = add_lib_to_erlang_path(Lib),
|
||||
{ErlangOk, ErlangBeams} = compile_erlang(ErlangModules, Out),
|
||||
{ElixirOk, ElixirBeams} = case ErlangOk of
|
||||
true -> compile_elixir(ElixirModules, Out);
|
||||
false -> {false, []}
|
||||
end,
|
||||
ok = del_lib_from_erlang_path(Lib),
|
||||
case ErlangOk andalso ElixirOk of
|
||||
true ->
|
||||
ModuleNames = proplists:get_keys(ErlangBeams ++ ElixirBeams),
|
||||
{ok, ModuleNames};
|
||||
false ->
|
||||
err
|
||||
end.
|
||||
|
||||
compile_erlang(Modules, Out) ->
|
||||
Workers = start_compiler_workers(Out),
|
||||
ok = producer_loop(Modules, Workers),
|
||||
collect_results({true, []}).
|
||||
|
||||
collect_results(Acc = {Result, Beams}) ->
|
||||
receive
|
||||
{compiled, ModuleName, Beam} -> collect_results({Result, [{ModuleName, Beam} | Beams]});
|
||||
failed -> collect_results({false, Beams})
|
||||
after 0 -> Acc
|
||||
end.
|
||||
|
||||
producer_loop([], 0) ->
|
||||
ok;
|
||||
producer_loop([], Workers) ->
|
||||
receive
|
||||
{work_please, _} -> producer_loop([], Workers - 1)
|
||||
end;
|
||||
producer_loop([Module | Modules], Workers) ->
|
||||
receive
|
||||
{work_please, Worker} ->
|
||||
erlang:send(Worker, {module, Module}),
|
||||
producer_loop(Modules, Workers)
|
||||
end.
|
||||
|
||||
start_compiler_workers(Out) ->
|
||||
Parent = self(),
|
||||
NumSchedulers = erlang:system_info(schedulers),
|
||||
SpawnWorker = fun(_) ->
|
||||
erlang:spawn_link(fun() -> worker_loop(Parent, Out) end)
|
||||
end,
|
||||
lists:foreach(SpawnWorker, lists:seq(1, NumSchedulers)),
|
||||
NumSchedulers.
|
||||
|
||||
worker_loop(Parent, Out) ->
|
||||
Options = [report_errors, report_warnings, debug_info, {outdir, Out}],
|
||||
erlang:send(Parent, {work_please, self()}),
|
||||
receive
|
||||
{module, Module} ->
|
||||
log({compiling, Module}),
|
||||
case compile:file(Module, Options) of
|
||||
{ok, ModuleName} ->
|
||||
Beam = filename:join(Out, ModuleName) ++ ".beam",
|
||||
Message = {compiled, ModuleName, Beam},
|
||||
log(Message),
|
||||
erlang:send(Parent, Message);
|
||||
error ->
|
||||
log({failed, Module}),
|
||||
erlang:send(Parent, failed)
|
||||
end,
|
||||
worker_loop(Parent, Out)
|
||||
end.
|
||||
|
||||
compile_elixir(Modules, Out) ->
|
||||
Error = [
|
||||
"The program elixir was not found. Is it installed?",
|
||||
$\n,
|
||||
"Documentation for installing Elixir can be viewed here:",
|
||||
$\n,
|
||||
"https://elixir-lang.org/install.html"
|
||||
],
|
||||
case Modules of
|
||||
[] -> {true, []};
|
||||
_ ->
|
||||
log({starting, "compiler.app"}),
|
||||
ok = application:start(compiler),
|
||||
log({starting, "elixir.app"}),
|
||||
case application:start(elixir) of
|
||||
ok -> do_compile_elixir(Modules, Out);
|
||||
_ ->
|
||||
io:put_chars(standard_error, [Error, $\n]),
|
||||
{false, []}
|
||||
end
|
||||
end.
|
||||
|
||||
do_compile_elixir(Modules, Out) ->
|
||||
ModuleBins = lists:map(fun(Module) ->
|
||||
log({compiling, Module}),
|
||||
list_to_binary(Module)
|
||||
end, Modules),
|
||||
OutBin = list_to_binary(Out),
|
||||
Options = [{dest, OutBin}],
|
||||
% Silence "redefining module" warnings.
|
||||
% Compiled modules in the build directory are added to the code path.
|
||||
% These warnings result from recompiling loaded modules.
|
||||
% TODO: This line can likely be removed if/when the build directory is cleaned before every compilation.
|
||||
'Elixir.Code':compiler_options([{ignore_module_conflict, true}]),
|
||||
case 'Elixir.Kernel.ParallelCompiler':compile_to_path(ModuleBins, OutBin, Options) of
|
||||
{ok, ModuleAtoms, _} ->
|
||||
ToBeam = fun(ModuleAtom) ->
|
||||
Beam = filename:join(Out, atom_to_list(ModuleAtom)) ++ ".beam",
|
||||
log({compiled, Beam}),
|
||||
{ModuleAtom, Beam}
|
||||
end,
|
||||
{true, lists:map(ToBeam, ModuleAtoms)};
|
||||
{error, Errors, _} ->
|
||||
% Log all filenames associated with modules that failed to compile.
|
||||
% Note: The compiler prints compilation errors upon encountering them.
|
||||
ErrorFiles = lists:usort([File || {File, _, _} <- Errors]),
|
||||
Log = fun(File) ->
|
||||
log({failed, binary_to_list(File)})
|
||||
end,
|
||||
lists:foreach(Log, ErrorFiles),
|
||||
{false, []};
|
||||
_ -> {false, []}
|
||||
end.
|
||||
|
||||
add_lib_to_erlang_path(Lib) ->
|
||||
code:add_paths(expand_lib_paths(Lib)).
|
||||
|
||||
-if(?OTP_RELEASE >= 26).
|
||||
del_lib_from_erlang_path(Lib) ->
|
||||
code:del_paths(expand_lib_paths(Lib)).
|
||||
-else.
|
||||
del_lib_from_erlang_path(Lib) ->
|
||||
lists:foreach(fun code:del_path/1, expand_lib_paths(Lib)).
|
||||
-endif.
|
||||
|
||||
expand_lib_paths(Lib) ->
|
||||
filelib:wildcard([Lib, "/*/ebin"]).
|
||||
|
||||
configure_logging() ->
|
||||
Enabled = os:getenv("GLEAM_LOG") /= false,
|
||||
persistent_term:put(gleam_logging_enabled, Enabled).
|
||||
|
||||
log(Term) ->
|
||||
case persistent_term:get(gleam_logging_enabled) of
|
||||
true -> io:fwrite("~p~n", [Term]), ok;
|
||||
false -> ok
|
||||
end.
|
||||
167
build/dev/erlang/aprsme/_gleam_artefacts/support/aprs_is_mock.ex
Normal file
167
build/dev/erlang/aprsme/_gleam_artefacts/support/aprs_is_mock.ex
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
defmodule AprsIsMock do
|
||||
@moduledoc """
|
||||
Mock implementation of Aprs.Is for testing purposes.
|
||||
This ensures no external APRS connections are made during tests.
|
||||
"""
|
||||
|
||||
use GenServer
|
||||
|
||||
require Logger
|
||||
|
||||
def start_link(opts \\ []) do
|
||||
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_opts) do
|
||||
# Mock connection state
|
||||
initial_state = %{
|
||||
connected: false,
|
||||
server: "mock.aprs.test",
|
||||
port: 14_580,
|
||||
connected_at: nil,
|
||||
login_id: "TEST",
|
||||
filter: "r/33/-96/100",
|
||||
packet_stats: %{
|
||||
total_packets: 0,
|
||||
last_packet_at: nil,
|
||||
packets_per_second: 0,
|
||||
last_second_count: 0,
|
||||
last_second_timestamp: System.system_time(:second)
|
||||
},
|
||||
stored_packet_count: 0
|
||||
}
|
||||
|
||||
{:ok, initial_state}
|
||||
end
|
||||
|
||||
# Client API - Mock implementations
|
||||
|
||||
def stop do
|
||||
GenServer.stop(__MODULE__, :normal)
|
||||
end
|
||||
|
||||
def get_status do
|
||||
case Process.whereis(__MODULE__) do
|
||||
nil ->
|
||||
# Mock disconnected state
|
||||
%{
|
||||
connected: false,
|
||||
server: "mock.aprs.test",
|
||||
port: 14_580,
|
||||
connected_at: nil,
|
||||
uptime_seconds: 0,
|
||||
login_id: "TEST",
|
||||
filter: "r/33/-96/100",
|
||||
packet_stats: %{
|
||||
total_packets: 0,
|
||||
last_packet_at: nil,
|
||||
packets_per_second: 0,
|
||||
last_second_count: 0,
|
||||
last_second_timestamp: System.system_time(:second)
|
||||
},
|
||||
stored_packet_count: 0
|
||||
}
|
||||
|
||||
_pid ->
|
||||
try do
|
||||
GenServer.call(__MODULE__, :get_status, 5000)
|
||||
catch
|
||||
:exit, _ ->
|
||||
# Fallback mock state
|
||||
%{
|
||||
connected: false,
|
||||
server: "mock.aprs.test",
|
||||
port: 14_580,
|
||||
connected_at: nil,
|
||||
uptime_seconds: 0,
|
||||
login_id: "TEST",
|
||||
filter: "r/33/-96/100",
|
||||
packet_stats: %{
|
||||
total_packets: 0,
|
||||
last_packet_at: nil,
|
||||
packets_per_second: 0,
|
||||
last_second_count: 0,
|
||||
last_second_timestamp: System.system_time(:second)
|
||||
},
|
||||
stored_packet_count: 0
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_filter(_filter_string) do
|
||||
:ok
|
||||
end
|
||||
|
||||
def list_active_filters do
|
||||
:ok
|
||||
end
|
||||
|
||||
def send_message(_from, _to, _message) do
|
||||
:ok
|
||||
end
|
||||
|
||||
def send_message(message) do
|
||||
GenServer.call(__MODULE__, {:send_message, message})
|
||||
end
|
||||
|
||||
# Server callbacks
|
||||
|
||||
@impl true
|
||||
def handle_call({:send_message, _message}, _from, state) do
|
||||
{:reply, :ok, state}
|
||||
end
|
||||
|
||||
def handle_call(:get_status, _from, state) do
|
||||
uptime_seconds =
|
||||
if state.connected_at do
|
||||
DateTime.diff(DateTime.utc_now(), state.connected_at, :second)
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
mock_status =
|
||||
Map.put(state, :uptime_seconds, uptime_seconds)
|
||||
|
||||
{:reply, mock_status, state}
|
||||
end
|
||||
|
||||
def handle_call({:set_connection_state, connected}, _from, state) do
|
||||
new_state = %{
|
||||
state
|
||||
| connected: connected,
|
||||
connected_at: if(connected, do: DateTime.utc_now())
|
||||
}
|
||||
|
||||
{:reply, :ok, new_state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(_msg, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def terminate(_reason, _state) do
|
||||
:ok
|
||||
end
|
||||
|
||||
# Helper functions for testing
|
||||
|
||||
def simulate_packet(packet_data) do
|
||||
# Simulate receiving an APRS packet for testing purposes.
|
||||
# This can be used in tests to trigger packet processing without
|
||||
# connecting to external servers.
|
||||
|
||||
# Broadcast to live clients like the real implementation would
|
||||
AprsmeWeb.Endpoint.broadcast("aprs_messages", "packet", packet_data)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
def simulate_connection_state(connected \\ true) do
|
||||
# Simulate connection state changes for testing.
|
||||
GenServer.call(__MODULE__, {:set_connection_state, connected})
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
defmodule AprsmeWeb.ConnCase do
|
||||
@moduledoc """
|
||||
This module defines the test case to be used by
|
||||
tests that require setting up a connection.
|
||||
|
||||
Such tests rely on `Phoenix.ConnTest` and also
|
||||
import other functionality to make it easier
|
||||
to build common data structures and query the data layer.
|
||||
|
||||
Finally, if the test case interacts with the database,
|
||||
we enable the SQL sandbox, so changes done to the database
|
||||
are reverted at the end of every test. If you use PostgreSQL, you
|
||||
can even run database tests asynchronously by setting
|
||||
`use AprsmeWeb.ConnCase, async: true`, although
|
||||
this option is not recommended for other databases.
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
using do
|
||||
quote do
|
||||
# The default import for connections
|
||||
use AprsmeWeb, :verified_routes
|
||||
|
||||
import Aprsme.MockHelpers
|
||||
import AprsmeWeb.ConnCase
|
||||
import Phoenix.ConnTest
|
||||
import Plug.Conn
|
||||
|
||||
alias Aprsme.Repo
|
||||
|
||||
# The default endpoint for testing
|
||||
@endpoint AprsmeWeb.Endpoint
|
||||
|
||||
# Import conveniences for testing with connections
|
||||
|
||||
# The default import for Repo
|
||||
end
|
||||
end
|
||||
|
||||
setup tags do
|
||||
Aprsme.DataCase.setup_sandbox(tags)
|
||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
||||
end
|
||||
|
||||
@doc """
|
||||
A helper that sets up the test case.
|
||||
|
||||
use AprsmeWeb.ConnCase, async: true
|
||||
|
||||
"""
|
||||
def setup_sandbox(_tags) do
|
||||
Aprsme.MockHelpers.stub_packets_mock()
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc """
|
||||
A helper that logs in a user.
|
||||
|
||||
setup %{conn: conn} do
|
||||
conn = log_in_user(conn, user)
|
||||
{:ok, conn: conn}
|
||||
end
|
||||
|
||||
"""
|
||||
def log_in_user(conn, user) do
|
||||
token = Aprsme.Accounts.generate_user_session_token(user)
|
||||
|
||||
conn
|
||||
|> Phoenix.ConnTest.init_test_session(%{})
|
||||
|> Plug.Conn.put_session(:user_token, token)
|
||||
|> Plug.Conn.put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}")
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
defmodule Aprsme.DataCase do
|
||||
@moduledoc """
|
||||
This module defines the test case to be used by
|
||||
data tests.
|
||||
|
||||
You may define functions here to be used as helpers in
|
||||
your data tests. See `errors_on/2`'s definition as an example.
|
||||
|
||||
Finally, if the test case interacts with the database,
|
||||
we enable the SQL sandbox, so changes done to the database
|
||||
are reverted at the end of every test. If you use PostgreSQL, you
|
||||
can even run database tests asynchronously by setting
|
||||
`use Aprsme.DataCase, async: true`, although
|
||||
this option is not recommended for other databases.
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
using do
|
||||
quote do
|
||||
import Aprsme.DataCase
|
||||
# Import conveniences for testing with connections
|
||||
import Ecto
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
|
||||
# and other functionality to make calls such as:
|
||||
# import Aprsme.DataCase
|
||||
# Aprsme.DataCase.errors_on(MySchema.changeset(%MySchema{}, %{}))
|
||||
|
||||
# The default import for Repo
|
||||
alias Aprsme.Repo
|
||||
end
|
||||
end
|
||||
|
||||
setup tags do
|
||||
Aprsme.DataCase.setup_sandbox(tags)
|
||||
Aprsme.DevicesSeeder.seed_from_json()
|
||||
:ok
|
||||
end
|
||||
|
||||
@doc """
|
||||
A helper that transforms changeset errors into a map of messages.
|
||||
|
||||
iex> errors_on(MySchema.changeset(%MySchema{}, %{field: bad_value}))
|
||||
%{field: ["has invalid value"]}
|
||||
|
||||
"""
|
||||
def errors_on(changeset) do
|
||||
Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Sets up the sandbox and allows the test case
|
||||
to be run asynchronously.
|
||||
"""
|
||||
def setup_sandbox(tags) do
|
||||
pid = Sandbox.start_owner!(Aprsme.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Sandbox.stop_owner(pid) end)
|
||||
end
|
||||
|
||||
defp translate_error({msg, opts}) do
|
||||
# You can make use of gettext to translate error messages by
|
||||
# uncommenting and adjusting the following code:
|
||||
|
||||
# if count = opts[:count] do
|
||||
# Gettext.dngettext(AprsmeWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
# else
|
||||
# Gettext.dgettext(AprsmeWeb.Gettext, "errors", msg, opts)
|
||||
# end
|
||||
|
||||
Enum.reduce(opts, msg, fn {key, value}, acc ->
|
||||
String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
defmodule Aprsme.AccountsFixtures do
|
||||
@moduledoc """
|
||||
This module defines test helpers for creating
|
||||
entities via the `Aprsme.Accounts` context.
|
||||
"""
|
||||
|
||||
def unique_user_email, do: "user#{System.unique_integer()}@example.com"
|
||||
def valid_user_password, do: "hello world!"
|
||||
|
||||
def unique_user_callsign do
|
||||
num = rem(System.unique_integer([:positive]), 99) + 1
|
||||
"K#{num}ABC"
|
||||
end
|
||||
|
||||
def valid_user_attributes(attrs \\ %{}) do
|
||||
Enum.into(attrs, %{
|
||||
email: unique_user_email(),
|
||||
password: valid_user_password(),
|
||||
callsign: unique_user_callsign()
|
||||
})
|
||||
end
|
||||
|
||||
def user_fixture(attrs \\ %{}) do
|
||||
{:ok, user} =
|
||||
attrs
|
||||
|> valid_user_attributes()
|
||||
|> Aprsme.Accounts.register_user()
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
def extract_user_token(fun) do
|
||||
{:ok, captured_email} = fun.(&"[TOKEN]#{&1}[TOKEN]")
|
||||
[_, token | _] = String.split(captured_email.text_body, "[TOKEN]")
|
||||
token
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
defmodule Aprsme.PacketsFixtures do
|
||||
@moduledoc """
|
||||
This module defines test helpers for creating
|
||||
entities via the `Aprsme.Packets` context.
|
||||
"""
|
||||
|
||||
alias Aprsme.Callsign
|
||||
alias Aprsme.Packet
|
||||
alias Aprsme.Repo
|
||||
|
||||
@doc """
|
||||
Generate a packet.
|
||||
"""
|
||||
def packet_fixture(attrs \\ %{}) do
|
||||
base_attrs = %{
|
||||
sender: "TEST-1",
|
||||
base_callsign: "TEST",
|
||||
ssid: "1",
|
||||
destination: "APRS",
|
||||
received_at: DateTime.utc_now(),
|
||||
lat: Decimal.new("40.7128"),
|
||||
lon: Decimal.new("-74.0060"),
|
||||
has_position: true,
|
||||
raw_packet: "TEST-1>APRS:=4042.77N/07400.36W>Test packet",
|
||||
data_type: "position",
|
||||
path: "APRS",
|
||||
data_extended: %{
|
||||
symbol_table_id: "/",
|
||||
symbol_code: ">",
|
||||
comment: "Test packet"
|
||||
}
|
||||
}
|
||||
|
||||
# Extract base_callsign and ssid from sender if provided
|
||||
final_attrs =
|
||||
case Map.get(attrs, :sender) do
|
||||
nil ->
|
||||
base_attrs
|
||||
|
||||
sender ->
|
||||
{base, ssid} = Callsign.extract_parts(sender)
|
||||
|
||||
Map.merge(base_attrs, %{base_callsign: base, ssid: ssid})
|
||||
end
|
||||
|
||||
{:ok, packet} =
|
||||
attrs
|
||||
|> Enum.into(final_attrs)
|
||||
|> then(&Packet.changeset(%Packet{}, &1))
|
||||
|> Repo.insert()
|
||||
|
||||
packet
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
defmodule Aprsme.MockHelpers do
|
||||
@moduledoc """
|
||||
Helper functions for setting up mocks in tests.
|
||||
"""
|
||||
|
||||
def stub_packets_mock do
|
||||
# Stub the packets module to prevent external calls
|
||||
Mox.stub(Aprsme.PacketsMock, :get_packets_for_callsign, fn _callsign ->
|
||||
{:ok, []}
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_packets_for_callsign_with_limit, fn _callsign, _limit ->
|
||||
{:ok, []}
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_packets_for_callsign_with_date_range, fn _callsign, _start_date, _end_date ->
|
||||
{:ok, []}
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_recent_packets_optimized, fn _opts ->
|
||||
[]
|
||||
end)
|
||||
|
||||
Mox.stub(Aprsme.PacketsMock, :get_nearby_stations, fn _lat, _lon, _exclude, _opts ->
|
||||
[]
|
||||
end)
|
||||
end
|
||||
|
||||
def stub_badpackets_mock do
|
||||
Mox.stub_with(BadPacketsMock, BadPacketsStub)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
defmodule AprsmeWeb.TestHelpers do
|
||||
@moduledoc """
|
||||
Common test helper functions to reduce duplication across test files.
|
||||
"""
|
||||
|
||||
alias Aprsme.Packet
|
||||
alias Aprsme.Repo
|
||||
|
||||
@doc """
|
||||
Creates a test packet with default values that can be overridden.
|
||||
"""
|
||||
def create_test_packet(attrs \\ %{}) do
|
||||
default_attrs = %{
|
||||
sender: "TEST-1",
|
||||
base_callsign: "TEST",
|
||||
ssid: "1",
|
||||
lat: Decimal.new("33.0000"),
|
||||
lon: Decimal.new("-96.0000"),
|
||||
has_position: true,
|
||||
received_at: DateTime.truncate(DateTime.utc_now(), :second),
|
||||
data_type: "position"
|
||||
}
|
||||
|
||||
attrs = Map.merge(default_attrs, attrs)
|
||||
|
||||
Repo.insert(%Packet{
|
||||
sender: attrs.sender,
|
||||
base_callsign: attrs.base_callsign,
|
||||
ssid: attrs.ssid,
|
||||
lat: attrs.lat,
|
||||
lon: attrs.lon,
|
||||
has_position: attrs.has_position,
|
||||
received_at: attrs.received_at,
|
||||
data_type: attrs.data_type,
|
||||
symbol_table_id: Map.get(attrs, :symbol_table_id),
|
||||
symbol_code: Map.get(attrs, :symbol_code),
|
||||
temperature: Map.get(attrs, :temperature),
|
||||
humidity: Map.get(attrs, :humidity),
|
||||
wind_speed: Map.get(attrs, :wind_speed)
|
||||
})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates common test bounds for Texas area.
|
||||
"""
|
||||
def texas_bounds do
|
||||
%{
|
||||
"north" => "33.0",
|
||||
"south" => "32.0",
|
||||
"east" => "-96.0",
|
||||
"west" => "-97.0"
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates common test bounds for a restrictive area.
|
||||
"""
|
||||
def restrictive_bounds do
|
||||
%{
|
||||
"north" => "31.0",
|
||||
"south" => "30.0",
|
||||
"east" => "-95.0",
|
||||
"west" => "-96.0"
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Common time calculations used across tests.
|
||||
"""
|
||||
def hours_ago(hours) when is_number(hours) do
|
||||
DateTime.add(DateTime.utc_now(), -hours * 3600, :second)
|
||||
end
|
||||
|
||||
def minutes_ago(minutes) when is_number(minutes) do
|
||||
DateTime.add(DateTime.utc_now(), -minutes * 60, :second)
|
||||
end
|
||||
|
||||
def days_ago(days) when is_number(days) do
|
||||
DateTime.add(DateTime.utc_now(), -days * 86_400, :second)
|
||||
end
|
||||
end
|
||||
8
build/dev/erlang/aprsme/ebin/aprsme.app
Normal file
8
build/dev/erlang/aprsme/ebin/aprsme.app
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{application, aprsme, [
|
||||
{vsn, "0.2.0"},
|
||||
{applications, [gleam_stdlib,
|
||||
gleeunit]},
|
||||
{description, "APRS packet display with type-safe Gleam modules"},
|
||||
{modules, []},
|
||||
{registered, []}
|
||||
]}.
|
||||
BIN
build/dev/erlang/aprsme/ebin/aprsme@@main.beam
Normal file
BIN
build/dev/erlang/aprsme/ebin/aprsme@@main.beam
Normal file
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
|||
-record(encoding_info, {
|
||||
valid_utf8 :: boolean(),
|
||||
byte_count :: integer(),
|
||||
char_count :: gleam@option:option(integer()),
|
||||
invalid_at :: gleam@option:option(integer())
|
||||
}).
|
||||
1
build/dev/erlang/aprsme/priv
Symbolic link
1
build/dev/erlang/aprsme/priv
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
/Users/graham/dev/aprs.me/priv
|
||||
1
build/dev/erlang/eex
Symbolic link
1
build/dev/erlang/eex
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/eex
|
||||
1
build/dev/erlang/elixir
Symbolic link
1
build/dev/erlang/elixir
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/elixir
|
||||
4
build/dev/erlang/gleam_elixir_paths
Normal file
4
build/dev/erlang/gleam_elixir_paths
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/eex
|
||||
/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/elixir
|
||||
/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/logger
|
||||
/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/mix
|
||||
993
build/dev/erlang/gleam_stdlib/_gleam_artefacts/dict.mjs
Normal file
993
build/dev/erlang/gleam_stdlib/_gleam_artefacts/dict.mjs
Normal file
|
|
@ -0,0 +1,993 @@
|
|||
/**
|
||||
* This file uses jsdoc to annotate types.
|
||||
* These types can be checked using the typescript compiler with "checkjs" option.
|
||||
*/
|
||||
|
||||
import { isEqual } from "./gleam.mjs";
|
||||
|
||||
const referenceMap = /* @__PURE__ */ new WeakMap();
|
||||
const tempDataView = /* @__PURE__ */ new DataView(
|
||||
/* @__PURE__ */ new ArrayBuffer(8),
|
||||
);
|
||||
let referenceUID = 0;
|
||||
/**
|
||||
* hash the object by reference using a weak map and incrementing uid
|
||||
* @param {any} o
|
||||
* @returns {number}
|
||||
*/
|
||||
function hashByReference(o) {
|
||||
const known = referenceMap.get(o);
|
||||
if (known !== undefined) {
|
||||
return known;
|
||||
}
|
||||
const hash = referenceUID++;
|
||||
if (referenceUID === 0x7fffffff) {
|
||||
referenceUID = 0;
|
||||
}
|
||||
referenceMap.set(o, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* merge two hashes in an order sensitive way
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*/
|
||||
function hashMerge(a, b) {
|
||||
return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2))) | 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* standard string hash popularised by java
|
||||
* @param {string} s
|
||||
* @returns {number}
|
||||
*/
|
||||
function hashString(s) {
|
||||
let hash = 0;
|
||||
const len = s.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
hash = (Math.imul(31, hash) + s.charCodeAt(i)) | 0;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* hash a number by converting to two integers and do some jumbling
|
||||
* @param {number} n
|
||||
* @returns {number}
|
||||
*/
|
||||
function hashNumber(n) {
|
||||
tempDataView.setFloat64(0, n);
|
||||
const i = tempDataView.getInt32(0);
|
||||
const j = tempDataView.getInt32(4);
|
||||
return Math.imul(0x45d9f3b, (i >> 16) ^ i) ^ j;
|
||||
}
|
||||
|
||||
/**
|
||||
* hash a BigInt by converting it to a string and hashing that
|
||||
* @param {BigInt} n
|
||||
* @returns {number}
|
||||
*/
|
||||
function hashBigInt(n) {
|
||||
return hashString(n.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* hash any js object
|
||||
* @param {any} o
|
||||
* @returns {number}
|
||||
*/
|
||||
function hashObject(o) {
|
||||
const proto = Object.getPrototypeOf(o);
|
||||
if (proto !== null && typeof proto.hashCode === "function") {
|
||||
try {
|
||||
const code = o.hashCode(o);
|
||||
if (typeof code === "number") {
|
||||
return code;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) {
|
||||
return hashByReference(o);
|
||||
}
|
||||
if (o instanceof Date) {
|
||||
return hashNumber(o.getTime());
|
||||
}
|
||||
let h = 0;
|
||||
if (o instanceof ArrayBuffer) {
|
||||
o = new Uint8Array(o);
|
||||
}
|
||||
if (Array.isArray(o) || o instanceof Uint8Array) {
|
||||
for (let i = 0; i < o.length; i++) {
|
||||
h = (Math.imul(31, h) + getHash(o[i])) | 0;
|
||||
}
|
||||
} else if (o instanceof Set) {
|
||||
o.forEach((v) => {
|
||||
h = (h + getHash(v)) | 0;
|
||||
});
|
||||
} else if (o instanceof Map) {
|
||||
o.forEach((v, k) => {
|
||||
h = (h + hashMerge(getHash(v), getHash(k))) | 0;
|
||||
});
|
||||
} else {
|
||||
const keys = Object.keys(o);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const k = keys[i];
|
||||
const v = o[k];
|
||||
h = (h + hashMerge(getHash(v), hashString(k))) | 0;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* hash any js value
|
||||
* @param {any} u
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getHash(u) {
|
||||
if (u === null) return 0x42108422;
|
||||
if (u === undefined) return 0x42108423;
|
||||
if (u === true) return 0x42108421;
|
||||
if (u === false) return 0x42108420;
|
||||
switch (typeof u) {
|
||||
case "number":
|
||||
return hashNumber(u);
|
||||
case "string":
|
||||
return hashString(u);
|
||||
case "bigint":
|
||||
return hashBigInt(u);
|
||||
case "object":
|
||||
return hashObject(u);
|
||||
case "symbol":
|
||||
return hashByReference(u);
|
||||
case "function":
|
||||
return hashByReference(u);
|
||||
default:
|
||||
return 0; // should be unreachable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {ArrayNode<K,V> | IndexNode<K,V> | CollisionNode<K,V>} Node
|
||||
*/
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {{ type: typeof ENTRY, k: K, v: V }} Entry
|
||||
*/
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {{ type: typeof ARRAY_NODE, size: number, array: (undefined | Entry<K,V> | Node<K,V>)[] }} ArrayNode
|
||||
*/
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry<K,V> | Node<K,V>)[] }} IndexNode
|
||||
*/
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry<K, V>[] }} CollisionNode
|
||||
*/
|
||||
/**
|
||||
* @typedef {{ val: boolean }} Flag
|
||||
*/
|
||||
const SHIFT = 5; // number of bits you need to shift by to get the next bucket
|
||||
const BUCKET_SIZE = Math.pow(2, SHIFT);
|
||||
const MASK = BUCKET_SIZE - 1; // used to zero out all bits not in the bucket
|
||||
const MAX_INDEX_NODE = BUCKET_SIZE / 2; // when does index node grow into array node
|
||||
const MIN_ARRAY_NODE = BUCKET_SIZE / 4; // when does array node shrink to index node
|
||||
const ENTRY = 0;
|
||||
const ARRAY_NODE = 1;
|
||||
const INDEX_NODE = 2;
|
||||
const COLLISION_NODE = 3;
|
||||
|
||||
/** @type {IndexNode<any,any>} */
|
||||
const EMPTY = {
|
||||
type: INDEX_NODE,
|
||||
bitmap: 0,
|
||||
array: [],
|
||||
};
|
||||
/**
|
||||
* Mask the hash to get only the bucket corresponding to shift
|
||||
* @param {number} hash
|
||||
* @param {number} shift
|
||||
* @returns {number}
|
||||
*/
|
||||
function mask(hash, shift) {
|
||||
return (hash >>> shift) & MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set only the Nth bit where N is the masked hash
|
||||
* @param {number} hash
|
||||
* @param {number} shift
|
||||
* @returns {number}
|
||||
*/
|
||||
function bitpos(hash, shift) {
|
||||
return 1 << mask(hash, shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of 1 bits in a number
|
||||
* @param {number} x
|
||||
* @returns {number}
|
||||
*/
|
||||
function bitcount(x) {
|
||||
x -= (x >> 1) & 0x55555555;
|
||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f;
|
||||
x += x >> 8;
|
||||
x += x >> 16;
|
||||
return x & 0x7f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the array index of an item in a bitmap index node
|
||||
* @param {number} bitmap
|
||||
* @param {number} bit
|
||||
* @returns {number}
|
||||
*/
|
||||
function index(bitmap, bit) {
|
||||
return bitcount(bitmap & (bit - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently copy an array and set one value at an index
|
||||
* @template T
|
||||
* @param {T[]} arr
|
||||
* @param {number} at
|
||||
* @param {T} val
|
||||
* @returns {T[]}
|
||||
*/
|
||||
function cloneAndSet(arr, at, val) {
|
||||
const len = arr.length;
|
||||
const out = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
out[i] = arr[i];
|
||||
}
|
||||
out[at] = val;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently copy an array and insert one value at an index
|
||||
* @template T
|
||||
* @param {T[]} arr
|
||||
* @param {number} at
|
||||
* @param {T} val
|
||||
* @returns {T[]}
|
||||
*/
|
||||
function spliceIn(arr, at, val) {
|
||||
const len = arr.length;
|
||||
const out = new Array(len + 1);
|
||||
let i = 0;
|
||||
let g = 0;
|
||||
while (i < at) {
|
||||
out[g++] = arr[i++];
|
||||
}
|
||||
out[g++] = val;
|
||||
while (i < len) {
|
||||
out[g++] = arr[i++];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently copy an array and remove one value at an index
|
||||
* @template T
|
||||
* @param {T[]} arr
|
||||
* @param {number} at
|
||||
* @returns {T[]}
|
||||
*/
|
||||
function spliceOut(arr, at) {
|
||||
const len = arr.length;
|
||||
const out = new Array(len - 1);
|
||||
let i = 0;
|
||||
let g = 0;
|
||||
while (i < at) {
|
||||
out[g++] = arr[i++];
|
||||
}
|
||||
++i;
|
||||
while (i < len) {
|
||||
out[g++] = arr[i++];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new node containing two entries
|
||||
* @template K,V
|
||||
* @param {number} shift
|
||||
* @param {K} key1
|
||||
* @param {V} val1
|
||||
* @param {number} key2hash
|
||||
* @param {K} key2
|
||||
* @param {V} val2
|
||||
* @returns {Node<K,V>}
|
||||
*/
|
||||
function createNode(shift, key1, val1, key2hash, key2, val2) {
|
||||
const key1hash = getHash(key1);
|
||||
if (key1hash === key2hash) {
|
||||
return {
|
||||
type: COLLISION_NODE,
|
||||
hash: key1hash,
|
||||
array: [
|
||||
{ type: ENTRY, k: key1, v: val1 },
|
||||
{ type: ENTRY, k: key2, v: val2 },
|
||||
],
|
||||
};
|
||||
}
|
||||
const addedLeaf = { val: false };
|
||||
return assoc(
|
||||
assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf),
|
||||
shift,
|
||||
key2hash,
|
||||
key2,
|
||||
val2,
|
||||
addedLeaf,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T,K,V
|
||||
* @callback AssocFunction
|
||||
* @param {T} root
|
||||
* @param {number} shift
|
||||
* @param {number} hash
|
||||
* @param {K} key
|
||||
* @param {V} val
|
||||
* @param {Flag} addedLeaf
|
||||
* @returns {Node<K,V>}
|
||||
*/
|
||||
/**
|
||||
* Associate a node with a new entry, creating a new node
|
||||
* @template T,K,V
|
||||
* @type {AssocFunction<Node<K,V>,K,V>}
|
||||
*/
|
||||
function assoc(root, shift, hash, key, val, addedLeaf) {
|
||||
switch (root.type) {
|
||||
case ARRAY_NODE:
|
||||
return assocArray(root, shift, hash, key, val, addedLeaf);
|
||||
case INDEX_NODE:
|
||||
return assocIndex(root, shift, hash, key, val, addedLeaf);
|
||||
case COLLISION_NODE:
|
||||
return assocCollision(root, shift, hash, key, val, addedLeaf);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @template T,K,V
|
||||
* @type {AssocFunction<ArrayNode<K,V>,K,V>}
|
||||
*/
|
||||
function assocArray(root, shift, hash, key, val, addedLeaf) {
|
||||
const idx = mask(hash, shift);
|
||||
const node = root.array[idx];
|
||||
// if the corresponding index is empty set the index to a newly created node
|
||||
if (node === undefined) {
|
||||
addedLeaf.val = true;
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: root.size + 1,
|
||||
array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }),
|
||||
};
|
||||
}
|
||||
if (node.type === ENTRY) {
|
||||
// if keys are equal replace the entry
|
||||
if (isEqual(key, node.k)) {
|
||||
if (val === node.v) {
|
||||
return root;
|
||||
}
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: root.size,
|
||||
array: cloneAndSet(root.array, idx, {
|
||||
type: ENTRY,
|
||||
k: key,
|
||||
v: val,
|
||||
}),
|
||||
};
|
||||
}
|
||||
// otherwise upgrade the entry to a node and insert
|
||||
addedLeaf.val = true;
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: root.size,
|
||||
array: cloneAndSet(
|
||||
root.array,
|
||||
idx,
|
||||
createNode(shift + SHIFT, node.k, node.v, hash, key, val),
|
||||
),
|
||||
};
|
||||
}
|
||||
// otherwise call assoc on the child node
|
||||
const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf);
|
||||
// if the child node hasn't changed just return the old root
|
||||
if (n === node) {
|
||||
return root;
|
||||
}
|
||||
// otherwise set the index to the new node
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: root.size,
|
||||
array: cloneAndSet(root.array, idx, n),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @template T,K,V
|
||||
* @type {AssocFunction<IndexNode<K,V>,K,V>}
|
||||
*/
|
||||
function assocIndex(root, shift, hash, key, val, addedLeaf) {
|
||||
const bit = bitpos(hash, shift);
|
||||
const idx = index(root.bitmap, bit);
|
||||
// if there is already a item at this hash index..
|
||||
if ((root.bitmap & bit) !== 0) {
|
||||
// if there is a node at the index (not an entry), call assoc on the child node
|
||||
const node = root.array[idx];
|
||||
if (node.type !== ENTRY) {
|
||||
const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf);
|
||||
if (n === node) {
|
||||
return root;
|
||||
}
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap,
|
||||
array: cloneAndSet(root.array, idx, n),
|
||||
};
|
||||
}
|
||||
// otherwise there is an entry at the index
|
||||
// if the keys are equal replace the entry with the updated value
|
||||
const nodeKey = node.k;
|
||||
if (isEqual(key, nodeKey)) {
|
||||
if (val === node.v) {
|
||||
return root;
|
||||
}
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap,
|
||||
array: cloneAndSet(root.array, idx, {
|
||||
type: ENTRY,
|
||||
k: key,
|
||||
v: val,
|
||||
}),
|
||||
};
|
||||
}
|
||||
// if the keys are not equal, replace the entry with a new child node
|
||||
addedLeaf.val = true;
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap,
|
||||
array: cloneAndSet(
|
||||
root.array,
|
||||
idx,
|
||||
createNode(shift + SHIFT, nodeKey, node.v, hash, key, val),
|
||||
),
|
||||
};
|
||||
} else {
|
||||
// else there is currently no item at the hash index
|
||||
const n = root.array.length;
|
||||
// if the number of nodes is at the maximum, expand this node into an array node
|
||||
if (n >= MAX_INDEX_NODE) {
|
||||
// create a 32 length array for the new array node (one for each bit in the hash)
|
||||
const nodes = new Array(32);
|
||||
// create and insert a node for the new entry
|
||||
const jdx = mask(hash, shift);
|
||||
nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf);
|
||||
let j = 0;
|
||||
let bitmap = root.bitmap;
|
||||
// place each item in the index node into the correct spot in the array node
|
||||
// loop through all 32 bits / array positions
|
||||
for (let i = 0; i < 32; i++) {
|
||||
if ((bitmap & 1) !== 0) {
|
||||
const node = root.array[j++];
|
||||
nodes[i] = node;
|
||||
}
|
||||
// shift the bitmap to process the next bit
|
||||
bitmap = bitmap >>> 1;
|
||||
}
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: n + 1,
|
||||
array: nodes,
|
||||
};
|
||||
} else {
|
||||
// else there is still space in this index node
|
||||
// simply insert a new entry at the hash index
|
||||
const newArray = spliceIn(root.array, idx, {
|
||||
type: ENTRY,
|
||||
k: key,
|
||||
v: val,
|
||||
});
|
||||
addedLeaf.val = true;
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap | bit,
|
||||
array: newArray,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @template T,K,V
|
||||
* @type {AssocFunction<CollisionNode<K,V>,K,V>}
|
||||
*/
|
||||
function assocCollision(root, shift, hash, key, val, addedLeaf) {
|
||||
// if there is a hash collision
|
||||
if (hash === root.hash) {
|
||||
const idx = collisionIndexOf(root, key);
|
||||
// if this key already exists replace the entry with the new value
|
||||
if (idx !== -1) {
|
||||
const entry = root.array[idx];
|
||||
if (entry.v === val) {
|
||||
return root;
|
||||
}
|
||||
return {
|
||||
type: COLLISION_NODE,
|
||||
hash: hash,
|
||||
array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }),
|
||||
};
|
||||
}
|
||||
// otherwise insert the entry at the end of the array
|
||||
const size = root.array.length;
|
||||
addedLeaf.val = true;
|
||||
return {
|
||||
type: COLLISION_NODE,
|
||||
hash: hash,
|
||||
array: cloneAndSet(root.array, size, { type: ENTRY, k: key, v: val }),
|
||||
};
|
||||
}
|
||||
// if there is no hash collision, upgrade to an index node
|
||||
return assoc(
|
||||
{
|
||||
type: INDEX_NODE,
|
||||
bitmap: bitpos(root.hash, shift),
|
||||
array: [root],
|
||||
},
|
||||
shift,
|
||||
hash,
|
||||
key,
|
||||
val,
|
||||
addedLeaf,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Find the index of a key in the collision node's array
|
||||
* @template K,V
|
||||
* @param {CollisionNode<K,V>} root
|
||||
* @param {K} key
|
||||
* @returns {number}
|
||||
*/
|
||||
function collisionIndexOf(root, key) {
|
||||
const size = root.array.length;
|
||||
for (let i = 0; i < size; i++) {
|
||||
if (isEqual(key, root.array[i].k)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* @template T,K,V
|
||||
* @callback FindFunction
|
||||
* @param {T} root
|
||||
* @param {number} shift
|
||||
* @param {number} hash
|
||||
* @param {K} key
|
||||
* @returns {undefined | Entry<K,V>}
|
||||
*/
|
||||
/**
|
||||
* Return the found entry or undefined if not present in the root
|
||||
* @template K,V
|
||||
* @type {FindFunction<Node<K,V>,K,V>}
|
||||
*/
|
||||
function find(root, shift, hash, key) {
|
||||
switch (root.type) {
|
||||
case ARRAY_NODE:
|
||||
return findArray(root, shift, hash, key);
|
||||
case INDEX_NODE:
|
||||
return findIndex(root, shift, hash, key);
|
||||
case COLLISION_NODE:
|
||||
return findCollision(root, key);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @type {FindFunction<ArrayNode<K,V>,K,V>}
|
||||
*/
|
||||
function findArray(root, shift, hash, key) {
|
||||
const idx = mask(hash, shift);
|
||||
const node = root.array[idx];
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (node.type !== ENTRY) {
|
||||
return find(node, shift + SHIFT, hash, key);
|
||||
}
|
||||
if (isEqual(key, node.k)) {
|
||||
return node;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @type {FindFunction<IndexNode<K,V>,K,V>}
|
||||
*/
|
||||
function findIndex(root, shift, hash, key) {
|
||||
const bit = bitpos(hash, shift);
|
||||
if ((root.bitmap & bit) === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const idx = index(root.bitmap, bit);
|
||||
const node = root.array[idx];
|
||||
if (node.type !== ENTRY) {
|
||||
return find(node, shift + SHIFT, hash, key);
|
||||
}
|
||||
if (isEqual(key, node.k)) {
|
||||
return node;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @param {CollisionNode<K,V>} root
|
||||
* @param {K} key
|
||||
* @returns {undefined | Entry<K,V>}
|
||||
*/
|
||||
function findCollision(root, key) {
|
||||
const idx = collisionIndexOf(root, key);
|
||||
if (idx < 0) {
|
||||
return undefined;
|
||||
}
|
||||
return root.array[idx];
|
||||
}
|
||||
/**
|
||||
* @template T,K,V
|
||||
* @callback WithoutFunction
|
||||
* @param {T} root
|
||||
* @param {number} shift
|
||||
* @param {number} hash
|
||||
* @param {K} key
|
||||
* @returns {undefined | Node<K,V>}
|
||||
*/
|
||||
/**
|
||||
* Remove an entry from the root, returning the updated root.
|
||||
* Returns undefined if the node should be removed from the parent.
|
||||
* @template K,V
|
||||
* @type {WithoutFunction<Node<K,V>,K,V>}
|
||||
* */
|
||||
function without(root, shift, hash, key) {
|
||||
switch (root.type) {
|
||||
case ARRAY_NODE:
|
||||
return withoutArray(root, shift, hash, key);
|
||||
case INDEX_NODE:
|
||||
return withoutIndex(root, shift, hash, key);
|
||||
case COLLISION_NODE:
|
||||
return withoutCollision(root, key);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @type {WithoutFunction<ArrayNode<K,V>,K,V>}
|
||||
*/
|
||||
function withoutArray(root, shift, hash, key) {
|
||||
const idx = mask(hash, shift);
|
||||
const node = root.array[idx];
|
||||
if (node === undefined) {
|
||||
return root; // already empty
|
||||
}
|
||||
let n = undefined;
|
||||
// if node is an entry and the keys are not equal there is nothing to remove
|
||||
// if node is not an entry do a recursive call
|
||||
if (node.type === ENTRY) {
|
||||
if (!isEqual(node.k, key)) {
|
||||
return root; // no changes
|
||||
}
|
||||
} else {
|
||||
n = without(node, shift + SHIFT, hash, key);
|
||||
if (n === node) {
|
||||
return root; // no changes
|
||||
}
|
||||
}
|
||||
// if the recursive call returned undefined the node should be removed
|
||||
if (n === undefined) {
|
||||
// if the number of child nodes is at the minimum, pack into an index node
|
||||
if (root.size <= MIN_ARRAY_NODE) {
|
||||
const arr = root.array;
|
||||
const out = new Array(root.size - 1);
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
let bitmap = 0;
|
||||
while (i < idx) {
|
||||
const nv = arr[i];
|
||||
if (nv !== undefined) {
|
||||
out[j] = nv;
|
||||
bitmap |= 1 << i;
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
++i; // skip copying the removed node
|
||||
while (i < arr.length) {
|
||||
const nv = arr[i];
|
||||
if (nv !== undefined) {
|
||||
out[j] = nv;
|
||||
bitmap |= 1 << i;
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: bitmap,
|
||||
array: out,
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: root.size - 1,
|
||||
array: cloneAndSet(root.array, idx, n),
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: ARRAY_NODE,
|
||||
size: root.size,
|
||||
array: cloneAndSet(root.array, idx, n),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @type {WithoutFunction<IndexNode<K,V>,K,V>}
|
||||
*/
|
||||
function withoutIndex(root, shift, hash, key) {
|
||||
const bit = bitpos(hash, shift);
|
||||
if ((root.bitmap & bit) === 0) {
|
||||
return root; // already empty
|
||||
}
|
||||
const idx = index(root.bitmap, bit);
|
||||
const node = root.array[idx];
|
||||
// if the item is not an entry
|
||||
if (node.type !== ENTRY) {
|
||||
const n = without(node, shift + SHIFT, hash, key);
|
||||
if (n === node) {
|
||||
return root; // no changes
|
||||
}
|
||||
// if not undefined, the child node still has items, so update it
|
||||
if (n !== undefined) {
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap,
|
||||
array: cloneAndSet(root.array, idx, n),
|
||||
};
|
||||
}
|
||||
// otherwise the child node should be removed
|
||||
// if it was the only child node, remove this node from the parent
|
||||
if (root.bitmap === bit) {
|
||||
return undefined;
|
||||
}
|
||||
// otherwise just remove the child node
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap ^ bit,
|
||||
array: spliceOut(root.array, idx),
|
||||
};
|
||||
}
|
||||
// otherwise the item is an entry, remove it if the key matches
|
||||
if (isEqual(key, node.k)) {
|
||||
if (root.bitmap === bit) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
type: INDEX_NODE,
|
||||
bitmap: root.bitmap ^ bit,
|
||||
array: spliceOut(root.array, idx),
|
||||
};
|
||||
}
|
||||
return root;
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @param {CollisionNode<K,V>} root
|
||||
* @param {K} key
|
||||
* @returns {undefined | Node<K,V>}
|
||||
*/
|
||||
function withoutCollision(root, key) {
|
||||
const idx = collisionIndexOf(root, key);
|
||||
// if the key not found, no changes
|
||||
if (idx < 0) {
|
||||
return root;
|
||||
}
|
||||
// otherwise the entry was found, remove it
|
||||
// if it was the only entry in this node, remove the whole node
|
||||
if (root.array.length === 1) {
|
||||
return undefined;
|
||||
}
|
||||
// otherwise just remove the entry
|
||||
return {
|
||||
type: COLLISION_NODE,
|
||||
hash: root.hash,
|
||||
array: spliceOut(root.array, idx),
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @template K,V
|
||||
* @param {undefined | Node<K,V>} root
|
||||
* @param {(value:V,key:K)=>void} fn
|
||||
* @returns {void}
|
||||
*/
|
||||
function forEach(root, fn) {
|
||||
if (root === undefined) {
|
||||
return;
|
||||
}
|
||||
const items = root.array;
|
||||
const size = items.length;
|
||||
for (let i = 0; i < size; i++) {
|
||||
const item = items[i];
|
||||
if (item === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (item.type === ENTRY) {
|
||||
fn(item.v, item.k);
|
||||
continue;
|
||||
}
|
||||
forEach(item, fn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra wrapper to keep track of Dict size and clean up the API
|
||||
* @template K,V
|
||||
*/
|
||||
export default class Dict {
|
||||
/**
|
||||
* @template V
|
||||
* @param {Record<string,V>} o
|
||||
* @returns {Dict<string,V>}
|
||||
*/
|
||||
static fromObject(o) {
|
||||
const keys = Object.keys(o);
|
||||
/** @type Dict<string,V> */
|
||||
let m = Dict.new();
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const k = keys[i];
|
||||
m = m.set(k, o[k]);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template K,V
|
||||
* @param {Map<K,V>} o
|
||||
* @returns {Dict<K,V>}
|
||||
*/
|
||||
static fromMap(o) {
|
||||
/** @type Dict<K,V> */
|
||||
let m = Dict.new();
|
||||
o.forEach((v, k) => {
|
||||
m = m.set(k, v);
|
||||
});
|
||||
return m;
|
||||
}
|
||||
|
||||
static new() {
|
||||
return new Dict(undefined, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {undefined | Node<K,V>} root
|
||||
* @param {number} size
|
||||
*/
|
||||
constructor(root, size) {
|
||||
this.root = root;
|
||||
this.size = size;
|
||||
}
|
||||
/**
|
||||
* @template NotFound
|
||||
* @param {K} key
|
||||
* @param {NotFound} notFound
|
||||
* @returns {NotFound | V}
|
||||
*/
|
||||
get(key, notFound) {
|
||||
if (this.root === undefined) {
|
||||
return notFound;
|
||||
}
|
||||
const found = find(this.root, 0, getHash(key), key);
|
||||
if (found === undefined) {
|
||||
return notFound;
|
||||
}
|
||||
return found.v;
|
||||
}
|
||||
/**
|
||||
* @param {K} key
|
||||
* @param {V} val
|
||||
* @returns {Dict<K,V>}
|
||||
*/
|
||||
set(key, val) {
|
||||
const addedLeaf = { val: false };
|
||||
const root = this.root === undefined ? EMPTY : this.root;
|
||||
const newRoot = assoc(root, 0, getHash(key), key, val, addedLeaf);
|
||||
if (newRoot === this.root) {
|
||||
return this;
|
||||
}
|
||||
return new Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size);
|
||||
}
|
||||
/**
|
||||
* @param {K} key
|
||||
* @returns {Dict<K,V>}
|
||||
*/
|
||||
delete(key) {
|
||||
if (this.root === undefined) {
|
||||
return this;
|
||||
}
|
||||
const newRoot = without(this.root, 0, getHash(key), key);
|
||||
if (newRoot === this.root) {
|
||||
return this;
|
||||
}
|
||||
if (newRoot === undefined) {
|
||||
return Dict.new();
|
||||
}
|
||||
return new Dict(newRoot, this.size - 1);
|
||||
}
|
||||
/**
|
||||
* @param {K} key
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has(key) {
|
||||
if (this.root === undefined) {
|
||||
return false;
|
||||
}
|
||||
return find(this.root, 0, getHash(key), key) !== undefined;
|
||||
}
|
||||
/**
|
||||
* @returns {[K,V][]}
|
||||
*/
|
||||
entries() {
|
||||
if (this.root === undefined) {
|
||||
return [];
|
||||
}
|
||||
/** @type [K,V][] */
|
||||
const result = [];
|
||||
this.forEach((v, k) => result.push([k, v]));
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {(val:V,key:K)=>void} fn
|
||||
*/
|
||||
forEach(fn) {
|
||||
forEach(this.root, fn);
|
||||
}
|
||||
hashCode() {
|
||||
let h = 0;
|
||||
this.forEach((v, k) => {
|
||||
h = (h + hashMerge(getHash(v), getHash(k))) | 0;
|
||||
});
|
||||
return h;
|
||||
}
|
||||
/**
|
||||
* @param {unknown} o
|
||||
* @returns {boolean}
|
||||
*/
|
||||
equals(o) {
|
||||
if (!(o instanceof Dict) || this.size !== o.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.forEach((v, k) => {
|
||||
if (!isEqual(o.get(k, !v), v)) {
|
||||
throw unequalDictSymbol;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e === unequalDictSymbol) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is thrown internally in Dict.equals() so that it returns false as soon
|
||||
// as a non-matching key is found
|
||||
const unequalDictSymbol = /* @__PURE__ */ Symbol();
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env escript
|
||||
-mode(compile).
|
||||
|
||||
% TODO: Don't concurrently print warnings and errors
|
||||
% TODO: Some tests
|
||||
|
||||
main(_) ->
|
||||
ok = io:setopts([binary, {encoding, utf8}]),
|
||||
ok = configure_logging(),
|
||||
compile_package_loop().
|
||||
|
||||
compile_package_loop() ->
|
||||
case io:get_line("") of
|
||||
eof -> ok;
|
||||
Line ->
|
||||
Chars = unicode:characters_to_list(Line),
|
||||
{ok, Tokens, _} = erl_scan:string(Chars),
|
||||
{ok, {Lib, Out, Modules}} = erl_parse:parse_term(Tokens),
|
||||
case compile_package(Lib, Out, Modules) of
|
||||
{ok, ModuleNames} ->
|
||||
PrintModuleName = fun(ModuleName) ->
|
||||
io:put_chars("gleam-compile-module:" ++ atom_to_list(ModuleName) ++ "\n")
|
||||
end,
|
||||
lists:map(PrintModuleName, ModuleNames),
|
||||
io:put_chars("gleam-compile-result-ok\n");
|
||||
err ->
|
||||
io:put_chars("gleam-compile-result-error\n")
|
||||
end,
|
||||
compile_package_loop()
|
||||
end.
|
||||
|
||||
compile_package(Lib, Out, Modules) ->
|
||||
IsElixirModule = fun(Module) ->
|
||||
filename:extension(Module) =:= ".ex"
|
||||
end,
|
||||
{ElixirModules, ErlangModules} = lists:partition(IsElixirModule, Modules),
|
||||
ok = filelib:ensure_dir([Out, $/]),
|
||||
ok = add_lib_to_erlang_path(Lib),
|
||||
{ErlangOk, ErlangBeams} = compile_erlang(ErlangModules, Out),
|
||||
{ElixirOk, ElixirBeams} = case ErlangOk of
|
||||
true -> compile_elixir(ElixirModules, Out);
|
||||
false -> {false, []}
|
||||
end,
|
||||
ok = del_lib_from_erlang_path(Lib),
|
||||
case ErlangOk andalso ElixirOk of
|
||||
true ->
|
||||
ModuleNames = proplists:get_keys(ErlangBeams ++ ElixirBeams),
|
||||
{ok, ModuleNames};
|
||||
false ->
|
||||
err
|
||||
end.
|
||||
|
||||
compile_erlang(Modules, Out) ->
|
||||
Workers = start_compiler_workers(Out),
|
||||
ok = producer_loop(Modules, Workers),
|
||||
collect_results({true, []}).
|
||||
|
||||
collect_results(Acc = {Result, Beams}) ->
|
||||
receive
|
||||
{compiled, ModuleName, Beam} -> collect_results({Result, [{ModuleName, Beam} | Beams]});
|
||||
failed -> collect_results({false, Beams})
|
||||
after 0 -> Acc
|
||||
end.
|
||||
|
||||
producer_loop([], 0) ->
|
||||
ok;
|
||||
producer_loop([], Workers) ->
|
||||
receive
|
||||
{work_please, _} -> producer_loop([], Workers - 1)
|
||||
end;
|
||||
producer_loop([Module | Modules], Workers) ->
|
||||
receive
|
||||
{work_please, Worker} ->
|
||||
erlang:send(Worker, {module, Module}),
|
||||
producer_loop(Modules, Workers)
|
||||
end.
|
||||
|
||||
start_compiler_workers(Out) ->
|
||||
Parent = self(),
|
||||
NumSchedulers = erlang:system_info(schedulers),
|
||||
SpawnWorker = fun(_) ->
|
||||
erlang:spawn_link(fun() -> worker_loop(Parent, Out) end)
|
||||
end,
|
||||
lists:foreach(SpawnWorker, lists:seq(1, NumSchedulers)),
|
||||
NumSchedulers.
|
||||
|
||||
worker_loop(Parent, Out) ->
|
||||
Options = [report_errors, report_warnings, debug_info, {outdir, Out}],
|
||||
erlang:send(Parent, {work_please, self()}),
|
||||
receive
|
||||
{module, Module} ->
|
||||
log({compiling, Module}),
|
||||
case compile:file(Module, Options) of
|
||||
{ok, ModuleName} ->
|
||||
Beam = filename:join(Out, ModuleName) ++ ".beam",
|
||||
Message = {compiled, ModuleName, Beam},
|
||||
log(Message),
|
||||
erlang:send(Parent, Message);
|
||||
error ->
|
||||
log({failed, Module}),
|
||||
erlang:send(Parent, failed)
|
||||
end,
|
||||
worker_loop(Parent, Out)
|
||||
end.
|
||||
|
||||
compile_elixir(Modules, Out) ->
|
||||
Error = [
|
||||
"The program elixir was not found. Is it installed?",
|
||||
$\n,
|
||||
"Documentation for installing Elixir can be viewed here:",
|
||||
$\n,
|
||||
"https://elixir-lang.org/install.html"
|
||||
],
|
||||
case Modules of
|
||||
[] -> {true, []};
|
||||
_ ->
|
||||
log({starting, "compiler.app"}),
|
||||
ok = application:start(compiler),
|
||||
log({starting, "elixir.app"}),
|
||||
case application:start(elixir) of
|
||||
ok -> do_compile_elixir(Modules, Out);
|
||||
_ ->
|
||||
io:put_chars(standard_error, [Error, $\n]),
|
||||
{false, []}
|
||||
end
|
||||
end.
|
||||
|
||||
do_compile_elixir(Modules, Out) ->
|
||||
ModuleBins = lists:map(fun(Module) ->
|
||||
log({compiling, Module}),
|
||||
list_to_binary(Module)
|
||||
end, Modules),
|
||||
OutBin = list_to_binary(Out),
|
||||
Options = [{dest, OutBin}],
|
||||
% Silence "redefining module" warnings.
|
||||
% Compiled modules in the build directory are added to the code path.
|
||||
% These warnings result from recompiling loaded modules.
|
||||
% TODO: This line can likely be removed if/when the build directory is cleaned before every compilation.
|
||||
'Elixir.Code':compiler_options([{ignore_module_conflict, true}]),
|
||||
case 'Elixir.Kernel.ParallelCompiler':compile_to_path(ModuleBins, OutBin, Options) of
|
||||
{ok, ModuleAtoms, _} ->
|
||||
ToBeam = fun(ModuleAtom) ->
|
||||
Beam = filename:join(Out, atom_to_list(ModuleAtom)) ++ ".beam",
|
||||
log({compiled, Beam}),
|
||||
{ModuleAtom, Beam}
|
||||
end,
|
||||
{true, lists:map(ToBeam, ModuleAtoms)};
|
||||
{error, Errors, _} ->
|
||||
% Log all filenames associated with modules that failed to compile.
|
||||
% Note: The compiler prints compilation errors upon encountering them.
|
||||
ErrorFiles = lists:usort([File || {File, _, _} <- Errors]),
|
||||
Log = fun(File) ->
|
||||
log({failed, binary_to_list(File)})
|
||||
end,
|
||||
lists:foreach(Log, ErrorFiles),
|
||||
{false, []};
|
||||
_ -> {false, []}
|
||||
end.
|
||||
|
||||
add_lib_to_erlang_path(Lib) ->
|
||||
code:add_paths(expand_lib_paths(Lib)).
|
||||
|
||||
-if(?OTP_RELEASE >= 26).
|
||||
del_lib_from_erlang_path(Lib) ->
|
||||
code:del_paths(expand_lib_paths(Lib)).
|
||||
-else.
|
||||
del_lib_from_erlang_path(Lib) ->
|
||||
lists:foreach(fun code:del_path/1, expand_lib_paths(Lib)).
|
||||
-endif.
|
||||
|
||||
expand_lib_paths(Lib) ->
|
||||
filelib:wildcard([Lib, "/*/ebin"]).
|
||||
|
||||
configure_logging() ->
|
||||
Enabled = os:getenv("GLEAM_LOG") /= false,
|
||||
persistent_term:put(gleam_logging_enabled, Enabled).
|
||||
|
||||
log(Term) ->
|
||||
case persistent_term:get(gleam_logging_enabled) of
|
||||
true -> io:fwrite("~p~n", [Term]), ok;
|
||||
false -> ok
|
||||
end.
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,346 @@
|
|||
-module(gleam@bit_array).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/bit_array.gleam").
|
||||
-export([from_string/1, bit_size/1, byte_size/1, pad_to_bytes/1, slice/3, is_utf8/1, to_string/1, concat/1, append/2, base64_encode/2, base64_decode/1, base64_url_encode/2, base64_url_decode/1, base16_encode/1, base16_decode/1, inspect/1, compare/2, starts_with/2]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(" BitArrays are a sequence of binary data of any length.\n").
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 11).
|
||||
?DOC(" Converts a UTF-8 `String` type into a `BitArray`.\n").
|
||||
-spec from_string(binary()) -> bitstring().
|
||||
from_string(X) ->
|
||||
gleam_stdlib:identity(X).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 17).
|
||||
?DOC(" Returns an integer which is the number of bits in the bit array.\n").
|
||||
-spec bit_size(bitstring()) -> integer().
|
||||
bit_size(X) ->
|
||||
erlang:bit_size(X).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 23).
|
||||
?DOC(" Returns an integer which is the number of bytes in the bit array.\n").
|
||||
-spec byte_size(bitstring()) -> integer().
|
||||
byte_size(X) ->
|
||||
erlang:byte_size(X).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 29).
|
||||
?DOC(" Pads a bit array with zeros so that it is a whole number of bytes.\n").
|
||||
-spec pad_to_bytes(bitstring()) -> bitstring().
|
||||
pad_to_bytes(X) ->
|
||||
gleam_stdlib:bit_array_pad_to_bytes(X).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 54).
|
||||
?DOC(
|
||||
" Extracts a sub-section of a bit array.\n"
|
||||
"\n"
|
||||
" The slice will start at given position and continue up to specified\n"
|
||||
" length.\n"
|
||||
" A negative length can be used to extract bytes at the end of a bit array.\n"
|
||||
"\n"
|
||||
" This function runs in constant time.\n"
|
||||
).
|
||||
-spec slice(bitstring(), integer(), integer()) -> {ok, bitstring()} |
|
||||
{error, nil}.
|
||||
slice(String, Position, Length) ->
|
||||
gleam_stdlib:bit_array_slice(String, Position, Length).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 67).
|
||||
-spec is_utf8_loop(bitstring()) -> boolean().
|
||||
is_utf8_loop(Bits) ->
|
||||
case Bits of
|
||||
<<>> ->
|
||||
true;
|
||||
|
||||
<<_/utf8, Rest/binary>> ->
|
||||
is_utf8_loop(Rest);
|
||||
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 62).
|
||||
?DOC(" Tests to see whether a bit array is valid UTF-8.\n").
|
||||
-spec is_utf8(bitstring()) -> boolean().
|
||||
is_utf8(Bits) ->
|
||||
is_utf8_loop(Bits).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 88).
|
||||
?DOC(
|
||||
" Converts a bit array to a string.\n"
|
||||
"\n"
|
||||
" Returns an error if the bit array is invalid UTF-8 data.\n"
|
||||
).
|
||||
-spec to_string(bitstring()) -> {ok, binary()} | {error, nil}.
|
||||
to_string(Bits) ->
|
||||
case is_utf8(Bits) of
|
||||
true ->
|
||||
{ok, gleam_stdlib:identity(Bits)};
|
||||
|
||||
false ->
|
||||
{error, nil}
|
||||
end.
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 109).
|
||||
?DOC(
|
||||
" Creates a new bit array by joining multiple binaries.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" concat([from_string(\"butter\"), from_string(\"fly\")])\n"
|
||||
" // -> from_string(\"butterfly\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec concat(list(bitstring())) -> bitstring().
|
||||
concat(Bit_arrays) ->
|
||||
gleam_stdlib:bit_array_concat(Bit_arrays).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 40).
|
||||
?DOC(
|
||||
" Creates a new bit array by joining two bit arrays.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" append(to: from_string(\"butter\"), suffix: from_string(\"fly\"))\n"
|
||||
" // -> from_string(\"butterfly\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec append(bitstring(), bitstring()) -> bitstring().
|
||||
append(First, Second) ->
|
||||
gleam_stdlib:bit_array_concat([First, Second]).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 118).
|
||||
?DOC(
|
||||
" Encodes a BitArray into a base 64 encoded string.\n"
|
||||
"\n"
|
||||
" If the bit array does not contain a whole number of bytes then it is padded\n"
|
||||
" with zero bits prior to being encoded.\n"
|
||||
).
|
||||
-spec base64_encode(bitstring(), boolean()) -> binary().
|
||||
base64_encode(Input, Padding) ->
|
||||
gleam_stdlib:bit_array_base64_encode(Input, Padding).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 122).
|
||||
?DOC(" Decodes a base 64 encoded string into a `BitArray`.\n").
|
||||
-spec base64_decode(binary()) -> {ok, bitstring()} | {error, nil}.
|
||||
base64_decode(Encoded) ->
|
||||
Padded = case erlang:byte_size(gleam_stdlib:identity(Encoded)) rem 4 of
|
||||
0 ->
|
||||
Encoded;
|
||||
|
||||
N ->
|
||||
gleam@string:append(
|
||||
Encoded,
|
||||
gleam@string:repeat(<<"="/utf8>>, 4 - N)
|
||||
)
|
||||
end,
|
||||
gleam_stdlib:base_decode64(Padded).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 140).
|
||||
?DOC(
|
||||
" Encodes a `BitArray` into a base 64 encoded string with URL and filename\n"
|
||||
" safe alphabet.\n"
|
||||
"\n"
|
||||
" If the bit array does not contain a whole number of bytes then it is padded\n"
|
||||
" with zero bits prior to being encoded.\n"
|
||||
).
|
||||
-spec base64_url_encode(bitstring(), boolean()) -> binary().
|
||||
base64_url_encode(Input, Padding) ->
|
||||
_pipe = gleam_stdlib:bit_array_base64_encode(Input, Padding),
|
||||
_pipe@1 = gleam@string:replace(_pipe, <<"+"/utf8>>, <<"-"/utf8>>),
|
||||
gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"_"/utf8>>).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 149).
|
||||
?DOC(
|
||||
" Decodes a base 64 encoded string with URL and filename safe alphabet into a\n"
|
||||
" `BitArray`.\n"
|
||||
).
|
||||
-spec base64_url_decode(binary()) -> {ok, bitstring()} | {error, nil}.
|
||||
base64_url_decode(Encoded) ->
|
||||
_pipe = Encoded,
|
||||
_pipe@1 = gleam@string:replace(_pipe, <<"-"/utf8>>, <<"+"/utf8>>),
|
||||
_pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"/"/utf8>>),
|
||||
base64_decode(_pipe@2).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 163).
|
||||
?DOC(
|
||||
" Encodes a `BitArray` into a base 16 encoded string.\n"
|
||||
"\n"
|
||||
" If the bit array does not contain a whole number of bytes then it is padded\n"
|
||||
" with zero bits prior to being encoded.\n"
|
||||
).
|
||||
-spec base16_encode(bitstring()) -> binary().
|
||||
base16_encode(Input) ->
|
||||
gleam_stdlib:base16_encode(Input).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 169).
|
||||
?DOC(" Decodes a base 16 encoded string into a `BitArray`.\n").
|
||||
-spec base16_decode(binary()) -> {ok, bitstring()} | {error, nil}.
|
||||
base16_decode(Input) ->
|
||||
gleam_stdlib:base16_decode(Input).
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 190).
|
||||
-spec inspect_loop(bitstring(), binary()) -> binary().
|
||||
inspect_loop(Input, Accumulator) ->
|
||||
case Input of
|
||||
<<>> ->
|
||||
Accumulator;
|
||||
|
||||
<<X:1>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X))/binary>>/binary,
|
||||
":size(1)"/utf8>>;
|
||||
|
||||
<<X@1:2>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@1))/binary>>/binary,
|
||||
":size(2)"/utf8>>;
|
||||
|
||||
<<X@2:3>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@2))/binary>>/binary,
|
||||
":size(3)"/utf8>>;
|
||||
|
||||
<<X@3:4>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@3))/binary>>/binary,
|
||||
":size(4)"/utf8>>;
|
||||
|
||||
<<X@4:5>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@4))/binary>>/binary,
|
||||
":size(5)"/utf8>>;
|
||||
|
||||
<<X@5:6>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@5))/binary>>/binary,
|
||||
":size(6)"/utf8>>;
|
||||
|
||||
<<X@6:7>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@6))/binary>>/binary,
|
||||
":size(7)"/utf8>>;
|
||||
|
||||
<<X@7, Rest/bitstring>> ->
|
||||
Suffix = case Rest of
|
||||
<<>> ->
|
||||
<<""/utf8>>;
|
||||
|
||||
_ ->
|
||||
<<", "/utf8>>
|
||||
end,
|
||||
Accumulator@1 = <<<<Accumulator/binary,
|
||||
(erlang:integer_to_binary(X@7))/binary>>/binary,
|
||||
Suffix/binary>>,
|
||||
inspect_loop(Rest, Accumulator@1);
|
||||
|
||||
_ ->
|
||||
Accumulator
|
||||
end.
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 186).
|
||||
?DOC(
|
||||
" Converts a bit array to a string containing the decimal value of each byte.\n"
|
||||
"\n"
|
||||
" Use this over `string.inspect` when you have a bit array you want printed\n"
|
||||
" in the array syntax even if it is valid UTF-8.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" inspect(<<0, 20, 0x20, 255>>)\n"
|
||||
" // -> \"<<0, 20, 32, 255>>\"\n"
|
||||
"\n"
|
||||
" inspect(<<100, 5:3>>)\n"
|
||||
" // -> \"<<100, 5:size(3)>>\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec inspect(bitstring()) -> binary().
|
||||
inspect(Input) ->
|
||||
<<(inspect_loop(Input, <<"<<"/utf8>>))/binary, ">>"/utf8>>.
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 231).
|
||||
?DOC(
|
||||
" Compare two bit arrays as sequences of bytes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(<<1>>, <<2>>)\n"
|
||||
" // -> Lt\n"
|
||||
"\n"
|
||||
" compare(<<\"AB\":utf8>>, <<\"AA\":utf8>>)\n"
|
||||
" // -> Gt\n"
|
||||
"\n"
|
||||
" compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>)\n"
|
||||
" // -> Eq\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec compare(bitstring(), bitstring()) -> gleam@order:order().
|
||||
compare(A, B) ->
|
||||
case {A, B} of
|
||||
{<<First_byte, First_rest/bitstring>>,
|
||||
<<Second_byte, Second_rest/bitstring>>} ->
|
||||
case {First_byte, Second_byte} of
|
||||
{F, S} when F > S ->
|
||||
gt;
|
||||
|
||||
{F@1, S@1} when F@1 < S@1 ->
|
||||
lt;
|
||||
|
||||
{_, _} ->
|
||||
compare(First_rest, Second_rest)
|
||||
end;
|
||||
|
||||
{<<>>, <<>>} ->
|
||||
eq;
|
||||
|
||||
{_, <<>>} ->
|
||||
gt;
|
||||
|
||||
{<<>>, _} ->
|
||||
lt;
|
||||
|
||||
{First, Second} ->
|
||||
case {gleam_stdlib:bit_array_to_int_and_size(First),
|
||||
gleam_stdlib:bit_array_to_int_and_size(Second)} of
|
||||
{{A@1, _}, {B@1, _}} when A@1 > B@1 ->
|
||||
gt;
|
||||
|
||||
{{A@2, _}, {B@2, _}} when A@2 < B@2 ->
|
||||
lt;
|
||||
|
||||
{{_, Size_a}, {_, Size_b}} when Size_a > Size_b ->
|
||||
gt;
|
||||
|
||||
{{_, Size_a@1}, {_, Size_b@1}} when Size_a@1 < Size_b@1 ->
|
||||
lt;
|
||||
|
||||
{_, _} ->
|
||||
eq
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/bit_array.gleam", 272).
|
||||
?DOC(
|
||||
" Checks whether the first `BitArray` starts with the second one.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" starts_with(<<1, 2, 3, 4>>, <<1, 2>>)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec starts_with(bitstring(), bitstring()) -> boolean().
|
||||
starts_with(Bits, Prefix) ->
|
||||
Prefix_size = erlang:bit_size(Prefix),
|
||||
case Bits of
|
||||
<<Pref:Prefix_size/bitstring, _/bitstring>> when Pref =:= Prefix ->
|
||||
true;
|
||||
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache
Normal file
Binary file not shown.
Binary file not shown.
352
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.erl
Normal file
352
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.erl
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
-module(gleam@bool).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/bool.gleam").
|
||||
-export(['and'/2, 'or'/2, negate/1, nor/2, nand/2, exclusive_or/2, exclusive_nor/2, to_string/1, guard/3, lazy_guard/3]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(
|
||||
" A type with two possible values, `True` and `False`. Used to indicate whether\n"
|
||||
" things are... true or false!\n"
|
||||
"\n"
|
||||
" Often is it clearer and offers more type safety to define a custom type\n"
|
||||
" than to use `Bool`. For example, rather than having a `is_teacher: Bool`\n"
|
||||
" field consider having a `role: SchoolRole` field where `SchoolRole` is a custom\n"
|
||||
" type that can be either `Student` or `Teacher`.\n"
|
||||
).
|
||||
|
||||
-file("src/gleam/bool.gleam", 31).
|
||||
?DOC(
|
||||
" Returns the and of two bools, but it evaluates both arguments.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `&&` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" and(True, True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" and(False, True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" False |> and(True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec 'and'(boolean(), boolean()) -> boolean().
|
||||
'and'(A, B) ->
|
||||
A andalso B.
|
||||
|
||||
-file("src/gleam/bool.gleam", 57).
|
||||
?DOC(
|
||||
" Returns the or of two bools, but it evaluates both arguments.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `||` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(True, True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(False, True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" False |> or(True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec 'or'(boolean(), boolean()) -> boolean().
|
||||
'or'(A, B) ->
|
||||
A orelse B.
|
||||
|
||||
-file("src/gleam/bool.gleam", 77).
|
||||
?DOC(
|
||||
" Returns the opposite bool value.\n"
|
||||
"\n"
|
||||
" This is the same as the `!` or `not` operators in some other languages.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(False)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec negate(boolean()) -> boolean().
|
||||
negate(Bool) ->
|
||||
not Bool.
|
||||
|
||||
-file("src/gleam/bool.gleam", 105).
|
||||
?DOC(
|
||||
" Returns the nor of two bools.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nor(False, False)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nor(False, True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nor(True, False)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nor(True, True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec nor(boolean(), boolean()) -> boolean().
|
||||
nor(A, B) ->
|
||||
not (A orelse B).
|
||||
|
||||
-file("src/gleam/bool.gleam", 133).
|
||||
?DOC(
|
||||
" Returns the nand of two bools.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nand(False, False)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nand(False, True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nand(True, False)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" nand(True, True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec nand(boolean(), boolean()) -> boolean().
|
||||
nand(A, B) ->
|
||||
not (A andalso B).
|
||||
|
||||
-file("src/gleam/bool.gleam", 161).
|
||||
?DOC(
|
||||
" Returns the exclusive or of two bools.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_or(False, False)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_or(False, True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_or(True, False)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_or(True, True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec exclusive_or(boolean(), boolean()) -> boolean().
|
||||
exclusive_or(A, B) ->
|
||||
A /= B.
|
||||
|
||||
-file("src/gleam/bool.gleam", 189).
|
||||
?DOC(
|
||||
" Returns the exclusive nor of two bools.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_nor(False, False)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_nor(False, True)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_nor(True, False)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exclusive_nor(True, True)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec exclusive_nor(boolean(), boolean()) -> boolean().
|
||||
exclusive_nor(A, B) ->
|
||||
A =:= B.
|
||||
|
||||
-file("src/gleam/bool.gleam", 207).
|
||||
?DOC(
|
||||
" Returns a string representation of the given bool.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_string(True)\n"
|
||||
" // -> \"True\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_string(False)\n"
|
||||
" // -> \"False\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_string(boolean()) -> binary().
|
||||
to_string(Bool) ->
|
||||
case Bool of
|
||||
false ->
|
||||
<<"False"/utf8>>;
|
||||
|
||||
true ->
|
||||
<<"True"/utf8>>
|
||||
end.
|
||||
|
||||
-file("src/gleam/bool.gleam", 266).
|
||||
?DOC(
|
||||
" Run a callback function if the given bool is `False`, otherwise return a\n"
|
||||
" default value.\n"
|
||||
"\n"
|
||||
" With a `use` expression this function can simulate the early-return pattern\n"
|
||||
" found in some other programming languages.\n"
|
||||
"\n"
|
||||
" In a procedural language:\n"
|
||||
"\n"
|
||||
" ```js\n"
|
||||
" if (predicate) return value;\n"
|
||||
" // ...\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" In Gleam with a `use` expression:\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" use <- guard(when: predicate, return: value)\n"
|
||||
" // ...\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" Like everything in Gleam `use` is an expression, so it short circuits the\n"
|
||||
" current block, not the entire function. As a result you can assign the value\n"
|
||||
" to a variable:\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let x = {\n"
|
||||
" use <- guard(when: predicate, return: value)\n"
|
||||
" // ...\n"
|
||||
" }\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" Note that unlike in procedural languages the `return` value is evaluated\n"
|
||||
" even when the predicate is `False`, so it is advisable not to perform\n"
|
||||
" expensive computation nor side-effects there.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let name = \"\"\n"
|
||||
" use <- guard(when: name == \"\", return: \"Welcome!\")\n"
|
||||
" \"Hello, \" <> name\n"
|
||||
" // -> \"Welcome!\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let name = \"Kamaka\"\n"
|
||||
" use <- guard(when: name == \"\", return: \"Welcome!\")\n"
|
||||
" \"Hello, \" <> name\n"
|
||||
" // -> \"Hello, Kamaka\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec guard(boolean(), BVF, fun(() -> BVF)) -> BVF.
|
||||
guard(Requirement, Consequence, Alternative) ->
|
||||
case Requirement of
|
||||
true ->
|
||||
Consequence;
|
||||
|
||||
false ->
|
||||
Alternative()
|
||||
end.
|
||||
|
||||
-file("src/gleam/bool.gleam", 307).
|
||||
?DOC(
|
||||
" Runs a callback function if the given bool is `True`, otherwise runs an\n"
|
||||
" alternative callback function.\n"
|
||||
"\n"
|
||||
" Useful when further computation should be delayed regardless of the given\n"
|
||||
" bool's value.\n"
|
||||
"\n"
|
||||
" See [`guard`](#guard) for more info.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let name = \"Kamaka\"\n"
|
||||
" let inquiry = fn() { \"How may we address you?\" }\n"
|
||||
" use <- lazy_guard(when: name == \"\", return: inquiry)\n"
|
||||
" \"Hello, \" <> name\n"
|
||||
" // -> \"Hello, Kamaka\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
"\n"
|
||||
" let name = \"\"\n"
|
||||
" let greeting = fn() { \"Hello, \" <> name }\n"
|
||||
" use <- lazy_guard(when: name == \"\", otherwise: greeting)\n"
|
||||
" let number = int.random(99)\n"
|
||||
" let name = \"User \" <> int.to_string(number)\n"
|
||||
" \"Welcome, \" <> name\n"
|
||||
" // -> \"Welcome, User 54\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lazy_guard(boolean(), fun(() -> BVG), fun(() -> BVG)) -> BVG.
|
||||
lazy_guard(Requirement, Consequence, Alternative) ->
|
||||
case Requirement of
|
||||
true ->
|
||||
Consequence();
|
||||
|
||||
false ->
|
||||
Alternative()
|
||||
end.
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,211 @@
|
|||
-module(gleam@bytes_tree).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/bytes_tree.gleam").
|
||||
-export([append_tree/2, prepend_tree/2, concat/1, new/0, from_string/1, prepend_string/2, append_string/2, from_string_tree/1, from_bit_array/1, prepend/2, append/2, concat_bit_arrays/1, to_bit_array/1, byte_size/1]).
|
||||
-export_type([bytes_tree/0]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(
|
||||
" `BytesTree` is a type used for efficiently building binary content to be\n"
|
||||
" written to a file or a socket. Internally it is represented as tree so to\n"
|
||||
" append or prepend to a bytes tree is a constant time operation that\n"
|
||||
" allocates a new node in the tree without copying any of the content. When\n"
|
||||
" writing to an output stream the tree is traversed and the content is sent\n"
|
||||
" directly rather than copying it into a single buffer beforehand.\n"
|
||||
"\n"
|
||||
" If we append one bit array to another the bit arrays must be copied to a\n"
|
||||
" new location in memory so that they can sit together. This behaviour\n"
|
||||
" enables efficient reading of the data but copying can be expensive,\n"
|
||||
" especially if we want to join many bit arrays together.\n"
|
||||
"\n"
|
||||
" BytesTree is different in that it can be joined together in constant\n"
|
||||
" time using minimal memory, and then can be efficiently converted to a\n"
|
||||
" bit array using the `to_bit_array` function.\n"
|
||||
"\n"
|
||||
" Byte trees are always byte aligned, so that a number of bits that is not\n"
|
||||
" divisible by 8 will be padded with 0s.\n"
|
||||
"\n"
|
||||
" On Erlang this type is compatible with Erlang's iolists.\n"
|
||||
).
|
||||
|
||||
-opaque bytes_tree() :: {bytes, bitstring()} |
|
||||
{text, gleam@string_tree:string_tree()} |
|
||||
{many, list(bytes_tree())}.
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 68).
|
||||
?DOC(
|
||||
" Appends a bytes tree onto the end of another.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec append_tree(bytes_tree(), bytes_tree()) -> bytes_tree().
|
||||
append_tree(First, Second) ->
|
||||
gleam_stdlib:iodata_append(First, Second).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 59).
|
||||
?DOC(
|
||||
" Prepends a bytes tree onto the start of another.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec prepend_tree(bytes_tree(), bytes_tree()) -> bytes_tree().
|
||||
prepend_tree(Second, First) ->
|
||||
gleam_stdlib:iodata_append(First, Second).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 98).
|
||||
?DOC(
|
||||
" Joins a list of bytes trees into a single one.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec concat(list(bytes_tree())) -> bytes_tree().
|
||||
concat(Trees) ->
|
||||
gleam_stdlib:identity(Trees).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 35).
|
||||
?DOC(
|
||||
" Create an empty `BytesTree`. Useful as the start of a pipe chaining many\n"
|
||||
" trees together.\n"
|
||||
).
|
||||
-spec new() -> bytes_tree().
|
||||
new() ->
|
||||
gleam_stdlib:identity([]).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 118).
|
||||
?DOC(
|
||||
" Creates a new bytes tree from a string.\n"
|
||||
"\n"
|
||||
" Runs in constant time when running on Erlang.\n"
|
||||
" Runs in linear time otherwise.\n"
|
||||
).
|
||||
-spec from_string(binary()) -> bytes_tree().
|
||||
from_string(String) ->
|
||||
gleam_stdlib:wrap_list(String).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 80).
|
||||
?DOC(
|
||||
" Prepends a string onto the start of a bytes tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time when running on Erlang.\n"
|
||||
" Runs in linear time with the length of the string otherwise.\n"
|
||||
).
|
||||
-spec prepend_string(bytes_tree(), binary()) -> bytes_tree().
|
||||
prepend_string(Second, First) ->
|
||||
gleam_stdlib:iodata_append(gleam_stdlib:wrap_list(First), Second).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 89).
|
||||
?DOC(
|
||||
" Appends a string onto the end of a bytes tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time when running on Erlang.\n"
|
||||
" Runs in linear time with the length of the string otherwise.\n"
|
||||
).
|
||||
-spec append_string(bytes_tree(), binary()) -> bytes_tree().
|
||||
append_string(First, Second) ->
|
||||
gleam_stdlib:iodata_append(First, gleam_stdlib:wrap_list(Second)).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 128).
|
||||
?DOC(
|
||||
" Creates a new bytes tree from a string tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time when running on Erlang.\n"
|
||||
" Runs in linear time otherwise.\n"
|
||||
).
|
||||
-spec from_string_tree(gleam@string_tree:string_tree()) -> bytes_tree().
|
||||
from_string_tree(Tree) ->
|
||||
gleam_stdlib:wrap_list(Tree).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 136).
|
||||
?DOC(
|
||||
" Creates a new bytes tree from a bit array.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec from_bit_array(bitstring()) -> bytes_tree().
|
||||
from_bit_array(Bits) ->
|
||||
_pipe = Bits,
|
||||
_pipe@1 = gleam_stdlib:bit_array_pad_to_bytes(_pipe),
|
||||
gleam_stdlib:wrap_list(_pipe@1).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 43).
|
||||
?DOC(
|
||||
" Prepends a bit array to the start of a bytes tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec prepend(bytes_tree(), bitstring()) -> bytes_tree().
|
||||
prepend(Second, First) ->
|
||||
gleam_stdlib:iodata_append(from_bit_array(First), Second).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 51).
|
||||
?DOC(
|
||||
" Appends a bit array to the end of a bytes tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec append(bytes_tree(), bitstring()) -> bytes_tree().
|
||||
append(First, Second) ->
|
||||
gleam_stdlib:iodata_append(First, from_bit_array(Second)).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 106).
|
||||
?DOC(
|
||||
" Joins a list of bit arrays into a single bytes tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec concat_bit_arrays(list(bitstring())) -> bytes_tree().
|
||||
concat_bit_arrays(Bits) ->
|
||||
_pipe = Bits,
|
||||
_pipe@1 = gleam@list:map(_pipe, fun(B) -> from_bit_array(B) end),
|
||||
gleam_stdlib:identity(_pipe@1).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 162).
|
||||
-spec to_list(list(list(bytes_tree())), list(bitstring())) -> list(bitstring()).
|
||||
to_list(Stack, Acc) ->
|
||||
case Stack of
|
||||
[] ->
|
||||
Acc;
|
||||
|
||||
[[] | Remaining_stack] ->
|
||||
to_list(Remaining_stack, Acc);
|
||||
|
||||
[[{bytes, Bits} | Rest] | Remaining_stack@1] ->
|
||||
to_list([Rest | Remaining_stack@1], [Bits | Acc]);
|
||||
|
||||
[[{text, Tree} | Rest@1] | Remaining_stack@2] ->
|
||||
Bits@1 = gleam_stdlib:identity(unicode:characters_to_binary(Tree)),
|
||||
to_list([Rest@1 | Remaining_stack@2], [Bits@1 | Acc]);
|
||||
|
||||
[[{many, Trees} | Rest@2] | Remaining_stack@3] ->
|
||||
to_list([Trees, Rest@2 | Remaining_stack@3], Acc)
|
||||
end.
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 155).
|
||||
?DOC(
|
||||
" Turns a bytes tree into a bit array.\n"
|
||||
"\n"
|
||||
" Runs in linear time.\n"
|
||||
"\n"
|
||||
" When running on Erlang this function is implemented natively by the\n"
|
||||
" virtual machine and is highly optimised.\n"
|
||||
).
|
||||
-spec to_bit_array(bytes_tree()) -> bitstring().
|
||||
to_bit_array(Tree) ->
|
||||
erlang:list_to_bitstring(Tree).
|
||||
|
||||
-file("src/gleam/bytes_tree.gleam", 186).
|
||||
?DOC(
|
||||
" Returns the size of the bytes tree's content in bytes.\n"
|
||||
"\n"
|
||||
" Runs in linear time.\n"
|
||||
).
|
||||
-spec byte_size(bytes_tree()) -> integer().
|
||||
byte_size(Tree) ->
|
||||
erlang:iolist_size(Tree).
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.cache
Normal file
Binary file not shown.
Binary file not shown.
561
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.erl
Normal file
561
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.erl
Normal file
|
|
@ -0,0 +1,561 @@
|
|||
-module(gleam@dict).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/dict.gleam").
|
||||
-export([size/1, is_empty/1, to_list/1, new/0, get/2, has_key/2, insert/3, from_list/1, keys/1, values/1, take/2, merge/2, delete/2, drop/2, upsert/3, fold/3, map_values/2, filter/2, each/2, combine/3]).
|
||||
-export_type([dict/2]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-type dict(LA, LB) :: any() | {gleam_phantom, LA, LB}.
|
||||
|
||||
-file("src/gleam/dict.gleam", 36).
|
||||
?DOC(
|
||||
" Determines the number of key-value pairs in the dict.\n"
|
||||
" This function runs in constant time and does not need to iterate the dict.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> size\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"key\", \"value\") |> size\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec size(dict(any(), any())) -> integer().
|
||||
size(Dict) ->
|
||||
maps:size(Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 52).
|
||||
?DOC(
|
||||
" Determines whether or not the dict is empty.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> is_empty\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"b\", 1) |> is_empty\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_empty(dict(any(), any())) -> boolean().
|
||||
is_empty(Dict) ->
|
||||
maps:size(Dict) =:= 0.
|
||||
|
||||
-file("src/gleam/dict.gleam", 80).
|
||||
?DOC(
|
||||
" Converts the dict to a list of 2-element tuples `#(key, value)`, one for\n"
|
||||
" each key-value pair in the dict.\n"
|
||||
"\n"
|
||||
" The tuples in the list have no specific order.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" Calling `to_list` on an empty `dict` returns an empty list.\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> to_list\n"
|
||||
" // -> []\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" The ordering of elements in the resulting list is an implementation detail\n"
|
||||
" that should not be relied upon.\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"b\", 1) |> insert(\"a\", 0) |> insert(\"c\", 2) |> to_list\n"
|
||||
" // -> [#(\"a\", 0), #(\"b\", 1), #(\"c\", 2)]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_list(dict(LK, LL)) -> list({LK, LL}).
|
||||
to_list(Dict) ->
|
||||
maps:to_list(Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 129).
|
||||
?DOC(" Creates a fresh dict that contains no values.\n").
|
||||
-spec new() -> dict(any(), any()).
|
||||
new() ->
|
||||
maps:new().
|
||||
|
||||
-file("src/gleam/dict.gleam", 150).
|
||||
?DOC(
|
||||
" Fetches a value from a dict for a given key.\n"
|
||||
"\n"
|
||||
" The dict may not have a value for the key, so the value is wrapped in a\n"
|
||||
" `Result`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"a\", 0) |> get(\"a\")\n"
|
||||
" // -> Ok(0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"a\", 0) |> get(\"b\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec get(dict(MN, MO), MN) -> {ok, MO} | {error, nil}.
|
||||
get(From, Get) ->
|
||||
gleam_stdlib:map_get(From, Get).
|
||||
|
||||
-file("src/gleam/dict.gleam", 116).
|
||||
?DOC(
|
||||
" Determines whether or not a value present in the dict for a given key.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"a\", 0) |> has_key(\"a\")\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"a\", 0) |> has_key(\"b\")\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec has_key(dict(MB, any()), MB) -> boolean().
|
||||
has_key(Dict, Key) ->
|
||||
maps:is_key(Key, Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 169).
|
||||
?DOC(
|
||||
" Inserts a value into the dict with the given key.\n"
|
||||
"\n"
|
||||
" If the dict already has a value for the given key then the value is\n"
|
||||
" replaced with the new value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"a\", 0)\n"
|
||||
" // -> from_list([#(\"a\", 0)])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(\"a\", 0) |> insert(\"a\", 5)\n"
|
||||
" // -> from_list([#(\"a\", 5)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec insert(dict(MT, MU), MT, MU) -> dict(MT, MU).
|
||||
insert(Dict, Key, Value) ->
|
||||
maps:put(Key, Value, Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 92).
|
||||
-spec from_list_loop(list({LU, LV}), dict(LU, LV)) -> dict(LU, LV).
|
||||
from_list_loop(List, Initial) ->
|
||||
case List of
|
||||
[] ->
|
||||
Initial;
|
||||
|
||||
[{Key, Value} | Rest] ->
|
||||
from_list_loop(Rest, insert(Initial, Key, Value))
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 88).
|
||||
?DOC(
|
||||
" Converts a list of 2-element tuples `#(key, value)` to a dict.\n"
|
||||
"\n"
|
||||
" If two tuples have the same key the last one in the list will be the one\n"
|
||||
" that is present in the dict.\n"
|
||||
).
|
||||
-spec from_list(list({LP, LQ})) -> dict(LP, LQ).
|
||||
from_list(List) ->
|
||||
maps:from_list(List).
|
||||
|
||||
-file("src/gleam/dict.gleam", 223).
|
||||
-spec reverse_and_concat(list(OD), list(OD)) -> list(OD).
|
||||
reverse_and_concat(Remaining, Accumulator) ->
|
||||
case Remaining of
|
||||
[] ->
|
||||
Accumulator;
|
||||
|
||||
[First | Rest] ->
|
||||
reverse_and_concat(Rest, [First | Accumulator])
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 216).
|
||||
-spec do_keys_loop(list({NY, any()}), list(NY)) -> list(NY).
|
||||
do_keys_loop(List, Acc) ->
|
||||
case List of
|
||||
[] ->
|
||||
reverse_and_concat(Acc, []);
|
||||
|
||||
[{Key, _} | Rest] ->
|
||||
do_keys_loop(Rest, [Key | Acc])
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 212).
|
||||
?DOC(
|
||||
" Gets a list of all keys in a given dict.\n"
|
||||
"\n"
|
||||
" Dicts are not ordered so the keys are not returned in any specific order. Do\n"
|
||||
" not write code that relies on the order keys are returned by this function\n"
|
||||
" as it may change in later versions of Gleam or Erlang.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> keys\n"
|
||||
" // -> [\"a\", \"b\"]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec keys(dict(NT, any())) -> list(NT).
|
||||
keys(Dict) ->
|
||||
maps:keys(Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 249).
|
||||
-spec do_values_loop(list({any(), ON}), list(ON)) -> list(ON).
|
||||
do_values_loop(List, Acc) ->
|
||||
case List of
|
||||
[] ->
|
||||
reverse_and_concat(Acc, []);
|
||||
|
||||
[{_, Value} | Rest] ->
|
||||
do_values_loop(Rest, [Value | Acc])
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 244).
|
||||
?DOC(
|
||||
" Gets a list of all values in a given dict.\n"
|
||||
"\n"
|
||||
" Dicts are not ordered so the values are not returned in any specific order. Do\n"
|
||||
" not write code that relies on the order values are returned by this function\n"
|
||||
" as it may change in later versions of Gleam or Erlang.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> values\n"
|
||||
" // -> [0, 1]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec values(dict(any(), OI)) -> list(OI).
|
||||
values(Dict) ->
|
||||
maps:values(Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 318).
|
||||
-spec do_take_loop(dict(PR, PS), list(PR), dict(PR, PS)) -> dict(PR, PS).
|
||||
do_take_loop(Dict, Desired_keys, Acc) ->
|
||||
Insert = fun(Taken, Key) -> case gleam_stdlib:map_get(Dict, Key) of
|
||||
{ok, Value} ->
|
||||
insert(Taken, Key, Value);
|
||||
|
||||
{error, _} ->
|
||||
Taken
|
||||
end end,
|
||||
case Desired_keys of
|
||||
[] ->
|
||||
Acc;
|
||||
|
||||
[First | Rest] ->
|
||||
do_take_loop(Dict, Rest, Insert(Acc, First))
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 309).
|
||||
?DOC(
|
||||
" Creates a new dict from a given dict, only including any entries for which the\n"
|
||||
" keys are in a given list.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" |> take([\"b\"])\n"
|
||||
" // -> from_list([#(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" |> take([\"a\", \"b\", \"c\"])\n"
|
||||
" // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec take(dict(PD, PE), list(PD)) -> dict(PD, PE).
|
||||
take(Dict, Desired_keys) ->
|
||||
maps:with(Desired_keys, Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 363).
|
||||
-spec insert_pair(dict(QP, QQ), {QP, QQ}) -> dict(QP, QQ).
|
||||
insert_pair(Dict, Pair) ->
|
||||
insert(Dict, erlang:element(1, Pair), erlang:element(2, Pair)).
|
||||
|
||||
-file("src/gleam/dict.gleam", 356).
|
||||
-spec fold_inserts(list({QI, QJ}), dict(QI, QJ)) -> dict(QI, QJ).
|
||||
fold_inserts(New_entries, Dict) ->
|
||||
case New_entries of
|
||||
[] ->
|
||||
Dict;
|
||||
|
||||
[First | Rest] ->
|
||||
fold_inserts(Rest, insert_pair(Dict, First))
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 350).
|
||||
?DOC(
|
||||
" Creates a new dict from a pair of given dicts by combining their entries.\n"
|
||||
"\n"
|
||||
" If there are entries with the same keys in both dicts the entry from the\n"
|
||||
" second dict takes precedence.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" let b = from_list([#(\"b\", 2), #(\"c\", 3)])\n"
|
||||
" merge(a, b)\n"
|
||||
" // -> from_list([#(\"a\", 0), #(\"b\", 2), #(\"c\", 3)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec merge(dict(QA, QB), dict(QA, QB)) -> dict(QA, QB).
|
||||
merge(Dict, New_entries) ->
|
||||
maps:merge(Dict, New_entries).
|
||||
|
||||
-file("src/gleam/dict.gleam", 382).
|
||||
?DOC(
|
||||
" Creates a new dict from a given dict with all the same entries except for the\n"
|
||||
" one with a given key, if it exists.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"a\")\n"
|
||||
" // -> from_list([#(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"c\")\n"
|
||||
" // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec delete(dict(QV, QW), QV) -> dict(QV, QW).
|
||||
delete(Dict, Key) ->
|
||||
maps:remove(Key, Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 410).
|
||||
?DOC(
|
||||
" Creates a new dict from a given dict with all the same entries except any with\n"
|
||||
" keys found in a given list.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\"])\n"
|
||||
" // -> from_list([#(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"c\"])\n"
|
||||
" // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\", \"b\", \"c\"])\n"
|
||||
" // -> from_list([])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec drop(dict(RH, RI), list(RH)) -> dict(RH, RI).
|
||||
drop(Dict, Disallowed_keys) ->
|
||||
case Disallowed_keys of
|
||||
[] ->
|
||||
Dict;
|
||||
|
||||
[First | Rest] ->
|
||||
drop(delete(Dict, First), Rest)
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 440).
|
||||
?DOC(
|
||||
" Creates a new dict with one entry inserted or updated using a given function.\n"
|
||||
"\n"
|
||||
" If there was not an entry in the dict for the given key then the function\n"
|
||||
" gets `None` as its argument, otherwise it gets `Some(value)`.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let dict = from_list([#(\"a\", 0)])\n"
|
||||
" let increment = fn(x) {\n"
|
||||
" case x {\n"
|
||||
" Some(i) -> i + 1\n"
|
||||
" None -> 0\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" upsert(dict, \"a\", increment)\n"
|
||||
" // -> from_list([#(\"a\", 1)])\n"
|
||||
"\n"
|
||||
" upsert(dict, \"b\", increment)\n"
|
||||
" // -> from_list([#(\"a\", 0), #(\"b\", 0)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec upsert(dict(RO, RP), RO, fun((gleam@option:option(RP)) -> RP)) -> dict(RO, RP).
|
||||
upsert(Dict, Key, Fun) ->
|
||||
case gleam_stdlib:map_get(Dict, Key) of
|
||||
{ok, Value} ->
|
||||
insert(Dict, Key, Fun({some, Value}));
|
||||
|
||||
{error, _} ->
|
||||
insert(Dict, Key, Fun(none))
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 484).
|
||||
-spec fold_loop(list({SA, SB}), SD, fun((SD, SA, SB) -> SD)) -> SD.
|
||||
fold_loop(List, Initial, Fun) ->
|
||||
case List of
|
||||
[] ->
|
||||
Initial;
|
||||
|
||||
[{K, V} | Rest] ->
|
||||
fold_loop(Rest, Fun(Initial, K, V), Fun)
|
||||
end.
|
||||
|
||||
-file("src/gleam/dict.gleam", 476).
|
||||
?DOC(
|
||||
" Combines all entries into a single value by calling a given function on each\n"
|
||||
" one.\n"
|
||||
"\n"
|
||||
" Dicts are not ordered so the values are not returned in any specific order. Do\n"
|
||||
" not write code that relies on the order entries are used by this function\n"
|
||||
" as it may change in later versions of Gleam or Erlang.\n"
|
||||
"\n"
|
||||
" # Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n"
|
||||
" fold(dict, 0, fn(accumulator, key, value) { accumulator + value })\n"
|
||||
" // -> 13\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/string\n"
|
||||
"\n"
|
||||
" let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n"
|
||||
" fold(dict, \"\", fn(accumulator, key, value) {\n"
|
||||
" string.append(accumulator, key)\n"
|
||||
" })\n"
|
||||
" // -> \"abc\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec fold(dict(RV, RW), RZ, fun((RZ, RV, RW) -> RZ)) -> RZ.
|
||||
fold(Dict, Initial, Fun) ->
|
||||
fold_loop(maps:to_list(Dict), Initial, Fun).
|
||||
|
||||
-file("src/gleam/dict.gleam", 188).
|
||||
?DOC(
|
||||
" Updates all values in a given dict by calling a given function on each key\n"
|
||||
" and value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(3, 3), #(2, 4)])\n"
|
||||
" |> map_values(fn(key, value) { key * value })\n"
|
||||
" // -> from_list([#(3, 9), #(2, 8)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map_values(dict(NF, NG), fun((NF, NG) -> NJ)) -> dict(NF, NJ).
|
||||
map_values(Dict, Fun) ->
|
||||
maps:map(Fun, Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 273).
|
||||
?DOC(
|
||||
" Creates a new dict from a given dict, minus any entries that a given function\n"
|
||||
" returns `False` for.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" |> filter(fn(key, value) { value != 0 })\n"
|
||||
" // -> from_list([#(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" |> filter(fn(key, value) { True })\n"
|
||||
" // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec filter(dict(OR, OS), fun((OR, OS) -> boolean())) -> dict(OR, OS).
|
||||
filter(Dict, Predicate) ->
|
||||
maps:filter(Predicate, Dict).
|
||||
|
||||
-file("src/gleam/dict.gleam", 517).
|
||||
?DOC(
|
||||
" Calls a function for each key and value in a dict, discarding the return\n"
|
||||
" value.\n"
|
||||
"\n"
|
||||
" Useful for producing a side effect for every item of a dict.\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/io\n"
|
||||
"\n"
|
||||
" let dict = from_list([#(\"a\", \"apple\"), #(\"b\", \"banana\"), #(\"c\", \"cherry\")])\n"
|
||||
"\n"
|
||||
" each(dict, fn(k, v) {\n"
|
||||
" io.println(key <> \" => \" <> value)\n"
|
||||
" })\n"
|
||||
" // -> Nil\n"
|
||||
" // a => apple\n"
|
||||
" // b => banana\n"
|
||||
" // c => cherry\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" The order of elements in the iteration is an implementation detail that\n"
|
||||
" should not be relied upon.\n"
|
||||
).
|
||||
-spec each(dict(SE, SF), fun((SE, SF) -> any())) -> nil.
|
||||
each(Dict, Fun) ->
|
||||
fold(
|
||||
Dict,
|
||||
nil,
|
||||
fun(Nil, K, V) ->
|
||||
Fun(K, V),
|
||||
Nil
|
||||
end
|
||||
).
|
||||
|
||||
-file("src/gleam/dict.gleam", 538).
|
||||
?DOC(
|
||||
" Creates a new dict from a pair of given dicts by combining their entries.\n"
|
||||
"\n"
|
||||
" If there are entries with the same keys in both dicts the given function is\n"
|
||||
" used to determine the new value to use in the resulting dict.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n"
|
||||
" let b = from_list([#(\"a\", 2), #(\"c\", 3)])\n"
|
||||
" combine(a, b, fn(one, other) { one + other })\n"
|
||||
" // -> from_list([#(\"a\", 2), #(\"b\", 1), #(\"c\", 3)])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec combine(dict(SJ, SK), dict(SJ, SK), fun((SK, SK) -> SK)) -> dict(SJ, SK).
|
||||
combine(Dict, Other, Fun) ->
|
||||
fold(
|
||||
Dict,
|
||||
Other,
|
||||
fun(Acc, Key, Value) -> case gleam_stdlib:map_get(Acc, Key) of
|
||||
{ok, Other_value} ->
|
||||
insert(Acc, Key, Fun(Value, Other_value));
|
||||
|
||||
{error, _} ->
|
||||
insert(Acc, Key, Value)
|
||||
end end
|
||||
).
|
||||
Binary file not shown.
Binary file not shown.
106
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.erl
Normal file
106
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.erl
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
-module(gleam@dynamic).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/dynamic.gleam").
|
||||
-export([classify/1, bool/1, string/1, float/1, int/1, bit_array/1, list/1, array/1, properties/1, nil/0]).
|
||||
-export_type([dynamic_/0]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-type dynamic_() :: any().
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 30).
|
||||
?DOC(
|
||||
" Return a string indicating the type of the dynamic value.\n"
|
||||
"\n"
|
||||
" This function may be useful for constructing error messages or logs. If you\n"
|
||||
" want to turn dynamic data into well typed data then you want the\n"
|
||||
" `gleam/dynamic/decode` module.\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" classify(from(\"Hello\"))\n"
|
||||
" // -> \"String\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec classify(dynamic_()) -> binary().
|
||||
classify(Data) ->
|
||||
gleam_stdlib:classify_dynamic(Data).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 36).
|
||||
?DOC(" Create a dynamic value from a bool.\n").
|
||||
-spec bool(boolean()) -> dynamic_().
|
||||
bool(A) ->
|
||||
gleam_stdlib:identity(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 44).
|
||||
?DOC(
|
||||
" Create a dynamic value from a string.\n"
|
||||
"\n"
|
||||
" On Erlang this will be a binary string rather than a character list.\n"
|
||||
).
|
||||
-spec string(binary()) -> dynamic_().
|
||||
string(A) ->
|
||||
gleam_stdlib:identity(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 50).
|
||||
?DOC(" Create a dynamic value from a float.\n").
|
||||
-spec float(float()) -> dynamic_().
|
||||
float(A) ->
|
||||
gleam_stdlib:identity(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 56).
|
||||
?DOC(" Create a dynamic value from an int.\n").
|
||||
-spec int(integer()) -> dynamic_().
|
||||
int(A) ->
|
||||
gleam_stdlib:identity(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 62).
|
||||
?DOC(" Create a dynamic value from a bit array.\n").
|
||||
-spec bit_array(bitstring()) -> dynamic_().
|
||||
bit_array(A) ->
|
||||
gleam_stdlib:identity(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 68).
|
||||
?DOC(" Create a dynamic value from a list.\n").
|
||||
-spec list(list(dynamic_())) -> dynamic_().
|
||||
list(A) ->
|
||||
gleam_stdlib:identity(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 77).
|
||||
?DOC(
|
||||
" Create a dynamic value from a list, converting it to a sequential runtime\n"
|
||||
" format rather than the regular list format.\n"
|
||||
"\n"
|
||||
" On Erlang this will be a tuple, on JavaScript this will be an array.\n"
|
||||
).
|
||||
-spec array(list(dynamic_())) -> dynamic_().
|
||||
array(A) ->
|
||||
erlang:list_to_tuple(A).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 85).
|
||||
?DOC(
|
||||
" Create a dynamic value made an unordered series of keys and values, where\n"
|
||||
" the keys are unique.\n"
|
||||
"\n"
|
||||
" On Erlang this will be a map, on JavaScript this will be a Gleam dict\n"
|
||||
" object.\n"
|
||||
).
|
||||
-spec properties(list({dynamic_(), dynamic_()})) -> dynamic_().
|
||||
properties(Entries) ->
|
||||
gleam_stdlib:identity(maps:from_list(Entries)).
|
||||
|
||||
-file("src/gleam/dynamic.gleam", 94).
|
||||
?DOC(
|
||||
" A dynamic value representing nothing.\n"
|
||||
"\n"
|
||||
" On Erlang this will be the atom `nil`, on JavaScript this will be\n"
|
||||
" `undefined`.\n"
|
||||
).
|
||||
-spec nil() -> dynamic_().
|
||||
nil() ->
|
||||
gleam_stdlib:identity(nil).
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache
Normal file
Binary file not shown.
Binary file not shown.
744
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.erl
Normal file
744
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.erl
Normal file
|
|
@ -0,0 +1,744 @@
|
|||
-module(gleam@float).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/float.gleam").
|
||||
-export([parse/1, to_string/1, compare/2, min/2, max/2, clamp/3, ceiling/1, floor/1, truncate/1, absolute_value/1, loosely_compare/3, loosely_equals/3, power/2, square_root/1, negate/1, round/1, to_precision/2, sum/1, product/1, random/0, modulo/2, divide/2, add/2, multiply/2, subtract/2, logarithm/1, exponential/1]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(
|
||||
" Functions for working with floats.\n"
|
||||
"\n"
|
||||
" ## Float representation\n"
|
||||
"\n"
|
||||
" Floats are represented as 64 bit floating point numbers on both the Erlang\n"
|
||||
" and JavaScript runtimes. The floating point behaviour is native to their\n"
|
||||
" respective runtimes, so their exact behaviour will be slightly different on\n"
|
||||
" the two runtimes.\n"
|
||||
"\n"
|
||||
" ### Infinity and NaN\n"
|
||||
"\n"
|
||||
" Under the JavaScript runtime, exceeding the maximum (or minimum)\n"
|
||||
" representable value for a floating point value will result in Infinity (or\n"
|
||||
" -Infinity). Should you try to divide two infinities you will get NaN as a\n"
|
||||
" result.\n"
|
||||
"\n"
|
||||
" When running on BEAM, exceeding the maximum (or minimum) representable\n"
|
||||
" value for a floating point value will raise an error.\n"
|
||||
"\n"
|
||||
" ## Division by zero\n"
|
||||
"\n"
|
||||
" Gleam runs on the Erlang virtual machine, which does not follow the IEEE\n"
|
||||
" 754 standard for floating point arithmetic and does not have an `Infinity`\n"
|
||||
" value. In Erlang division by zero results in a crash, however Gleam does\n"
|
||||
" not have partial functions and operators in core so instead division by zero\n"
|
||||
" returns zero, a behaviour taken from Pony, Coq, and Lean.\n"
|
||||
"\n"
|
||||
" This may seem unexpected at first, but it is no less mathematically valid\n"
|
||||
" than crashing or returning a special value. Division by zero is undefined\n"
|
||||
" in mathematics.\n"
|
||||
).
|
||||
|
||||
-file("src/gleam/float.gleam", 51).
|
||||
?DOC(
|
||||
" Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was\n"
|
||||
" not possible.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" parse(\"2.3\")\n"
|
||||
" // -> Ok(2.3)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" parse(\"ABC\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec parse(binary()) -> {ok, float()} | {error, nil}.
|
||||
parse(String) ->
|
||||
gleam_stdlib:parse_float(String).
|
||||
|
||||
-file("src/gleam/float.gleam", 64).
|
||||
?DOC(
|
||||
" Returns the string representation of the provided `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_string(2.3)\n"
|
||||
" // -> \"2.3\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_string(float()) -> binary().
|
||||
to_string(X) ->
|
||||
gleam_stdlib:float_to_string(X).
|
||||
|
||||
-file("src/gleam/float.gleam", 95).
|
||||
?DOC(
|
||||
" Compares two `Float`s, returning an `Order`:\n"
|
||||
" `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(2.0, 2.3)\n"
|
||||
" // -> Lt\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" To handle\n"
|
||||
" [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)\n"
|
||||
" you may use [`loosely_compare`](#loosely_compare) instead.\n"
|
||||
).
|
||||
-spec compare(float(), float()) -> gleam@order:order().
|
||||
compare(A, B) ->
|
||||
case A =:= B of
|
||||
true ->
|
||||
eq;
|
||||
|
||||
false ->
|
||||
case A < B of
|
||||
true ->
|
||||
lt;
|
||||
|
||||
false ->
|
||||
gt
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 176).
|
||||
?DOC(
|
||||
" Compares two `Float`s, returning the smaller of the two.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" min(2.0, 2.3)\n"
|
||||
" // -> 2.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec min(float(), float()) -> float().
|
||||
min(A, B) ->
|
||||
case A < B of
|
||||
true ->
|
||||
A;
|
||||
|
||||
false ->
|
||||
B
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 192).
|
||||
?DOC(
|
||||
" Compares two `Float`s, returning the larger of the two.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" max(2.0, 2.3)\n"
|
||||
" // -> 2.3\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec max(float(), float()) -> float().
|
||||
max(A, B) ->
|
||||
case A > B of
|
||||
true ->
|
||||
A;
|
||||
|
||||
false ->
|
||||
B
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 75).
|
||||
?DOC(
|
||||
" Restricts a `Float` between a lower and upper bound.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" clamp(1.2, min: 1.4, max: 1.6)\n"
|
||||
" // -> 1.4\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec clamp(float(), float(), float()) -> float().
|
||||
clamp(X, Min_bound, Max_bound) ->
|
||||
_pipe = X,
|
||||
_pipe@1 = min(_pipe, Max_bound),
|
||||
max(_pipe@1, Min_bound).
|
||||
|
||||
-file("src/gleam/float.gleam", 210).
|
||||
?DOC(
|
||||
" Rounds the value to the next highest whole number as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" ceiling(2.3)\n"
|
||||
" // -> 3.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec ceiling(float()) -> float().
|
||||
ceiling(X) ->
|
||||
math:ceil(X).
|
||||
|
||||
-file("src/gleam/float.gleam", 223).
|
||||
?DOC(
|
||||
" Rounds the value to the next lowest whole number as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" floor(2.3)\n"
|
||||
" // -> 2.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec floor(float()) -> float().
|
||||
floor(X) ->
|
||||
math:floor(X).
|
||||
|
||||
-file("src/gleam/float.gleam", 261).
|
||||
?DOC(
|
||||
" Returns the value as an `Int`, truncating all decimal digits.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" truncate(2.4343434847383438)\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec truncate(float()) -> integer().
|
||||
truncate(X) ->
|
||||
erlang:trunc(X).
|
||||
|
||||
-file("src/gleam/float.gleam", 311).
|
||||
?DOC(
|
||||
" Returns the absolute value of the input as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" absolute_value(-12.5)\n"
|
||||
" // -> 12.5\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" absolute_value(10.2)\n"
|
||||
" // -> 10.2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec absolute_value(float()) -> float().
|
||||
absolute_value(X) ->
|
||||
case X >= +0.0 of
|
||||
true ->
|
||||
X;
|
||||
|
||||
false ->
|
||||
+0.0 - X
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 125).
|
||||
?DOC(
|
||||
" Compares two `Float`s within a tolerance, returning an `Order`:\n"
|
||||
" `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n"
|
||||
"\n"
|
||||
" This function allows Float comparison while handling\n"
|
||||
" [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n"
|
||||
"\n"
|
||||
" Notice: For `Float`s the tolerance won't be exact:\n"
|
||||
" `5.3 - 5.0` is not exactly `0.3`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" loosely_compare(5.0, with: 5.3, tolerating: 0.5)\n"
|
||||
" // -> Eq\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" If you want to check only for equality you may use\n"
|
||||
" [`loosely_equals`](#loosely_equals) instead.\n"
|
||||
).
|
||||
-spec loosely_compare(float(), float(), float()) -> gleam@order:order().
|
||||
loosely_compare(A, B, Tolerance) ->
|
||||
Difference = absolute_value(A - B),
|
||||
case Difference =< Tolerance of
|
||||
true ->
|
||||
eq;
|
||||
|
||||
false ->
|
||||
compare(A, B)
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 158).
|
||||
?DOC(
|
||||
" Checks for equality of two `Float`s within a tolerance,\n"
|
||||
" returning an `Bool`.\n"
|
||||
"\n"
|
||||
" This function allows Float comparison while handling\n"
|
||||
" [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n"
|
||||
"\n"
|
||||
" Notice: For `Float`s the tolerance won't be exact:\n"
|
||||
" `5.3 - 5.0` is not exactly `0.3`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" loosely_equals(5.0, with: 5.3, tolerating: 0.5)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" loosely_equals(5.0, with: 5.1, tolerating: 0.1)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec loosely_equals(float(), float(), float()) -> boolean().
|
||||
loosely_equals(A, B, Tolerance) ->
|
||||
Difference = absolute_value(A - B),
|
||||
Difference =< Tolerance.
|
||||
|
||||
-file("src/gleam/float.gleam", 348).
|
||||
?DOC(
|
||||
" Returns the results of the base being raised to the power of the\n"
|
||||
" exponent, as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(2.0, -1.0)\n"
|
||||
" // -> Ok(0.5)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(2.0, 2.0)\n"
|
||||
" // -> Ok(4.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(8.0, 1.5)\n"
|
||||
" // -> Ok(22.627416997969522)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 4.0 |> power(of: 2.0)\n"
|
||||
" // -> Ok(16.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(-1.0, 0.5)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec power(float(), float()) -> {ok, float()} | {error, nil}.
|
||||
power(Base, Exponent) ->
|
||||
Fractional = (math:ceil(Exponent) - Exponent) > +0.0,
|
||||
case ((Base < +0.0) andalso Fractional) orelse ((Base =:= +0.0) andalso (Exponent
|
||||
< +0.0)) of
|
||||
true ->
|
||||
{error, nil};
|
||||
|
||||
false ->
|
||||
{ok, math:pow(Base, Exponent)}
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 380).
|
||||
?DOC(
|
||||
" Returns the square root of the input as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" square_root(4.0)\n"
|
||||
" // -> Ok(2.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" square_root(-16.0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec square_root(float()) -> {ok, float()} | {error, nil}.
|
||||
square_root(X) ->
|
||||
power(X, 0.5).
|
||||
|
||||
-file("src/gleam/float.gleam", 393).
|
||||
?DOC(
|
||||
" Returns the negative of the value provided.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(1.0)\n"
|
||||
" // -> -1.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec negate(float()) -> float().
|
||||
negate(X) ->
|
||||
-1.0 * X.
|
||||
|
||||
-file("src/gleam/float.gleam", 240).
|
||||
?DOC(
|
||||
" Rounds the value to the nearest whole number as an `Int`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" round(2.3)\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" round(2.5)\n"
|
||||
" // -> 3\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec round(float()) -> integer().
|
||||
round(X) ->
|
||||
erlang:round(X).
|
||||
|
||||
-file("src/gleam/float.gleam", 280).
|
||||
?DOC(
|
||||
" Converts the value to a given precision as a `Float`.\n"
|
||||
" The precision is the number of allowed decimal places.\n"
|
||||
" Negative precisions are allowed and force rounding\n"
|
||||
" to the nearest tenth, hundredth, thousandth etc.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_precision(2.43434348473, precision: 2)\n"
|
||||
" // -> 2.43\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_precision(547890.453444, precision: -3)\n"
|
||||
" // -> 548000.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_precision(float(), integer()) -> float().
|
||||
to_precision(X, Precision) ->
|
||||
case Precision =< 0 of
|
||||
true ->
|
||||
Factor = math:pow(10.0, erlang:float(- Precision)),
|
||||
erlang:float(erlang:round(case Factor of
|
||||
+0.0 -> +0.0;
|
||||
-0.0 -> -0.0;
|
||||
Gleam@denominator -> X / Gleam@denominator
|
||||
end)) * Factor;
|
||||
|
||||
false ->
|
||||
Factor@1 = math:pow(10.0, erlang:float(Precision)),
|
||||
case Factor@1 of
|
||||
+0.0 -> +0.0;
|
||||
-0.0 -> -0.0;
|
||||
Gleam@denominator@1 -> erlang:float(erlang:round(X * Factor@1))
|
||||
/ Gleam@denominator@1
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 410).
|
||||
-spec sum_loop(list(float()), float()) -> float().
|
||||
sum_loop(Numbers, Initial) ->
|
||||
case Numbers of
|
||||
[First | Rest] ->
|
||||
sum_loop(Rest, First + Initial);
|
||||
|
||||
[] ->
|
||||
Initial
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 406).
|
||||
?DOC(
|
||||
" Sums a list of `Float`s.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" sum([1.0, 2.2, 3.3])\n"
|
||||
" // -> 6.5\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec sum(list(float())) -> float().
|
||||
sum(Numbers) ->
|
||||
sum_loop(Numbers, +0.0).
|
||||
|
||||
-file("src/gleam/float.gleam", 430).
|
||||
-spec product_loop(list(float()), float()) -> float().
|
||||
product_loop(Numbers, Initial) ->
|
||||
case Numbers of
|
||||
[First | Rest] ->
|
||||
product_loop(Rest, First * Initial);
|
||||
|
||||
[] ->
|
||||
Initial
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 426).
|
||||
?DOC(
|
||||
" Multiplies a list of `Float`s and returns the product.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" product([2.5, 3.2, 4.2])\n"
|
||||
" // -> 33.6\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec product(list(float())) -> float().
|
||||
product(Numbers) ->
|
||||
product_loop(Numbers, 1.0).
|
||||
|
||||
-file("src/gleam/float.gleam", 452).
|
||||
?DOC(
|
||||
" Generates a random float between the given zero (inclusive) and one\n"
|
||||
" (exclusive).\n"
|
||||
"\n"
|
||||
" On Erlang this updates the random state in the process dictionary.\n"
|
||||
" See: <https://www.erlang.org/doc/man/rand.html#uniform-0>\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" random()\n"
|
||||
" // -> 0.646355926896028\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec random() -> float().
|
||||
random() ->
|
||||
rand:uniform().
|
||||
|
||||
-file("src/gleam/float.gleam", 481).
|
||||
?DOC(
|
||||
" Computes the modulo of an float division of inputs as a `Result`.\n"
|
||||
"\n"
|
||||
" Returns division of the inputs as a `Result`: If the given divisor equals\n"
|
||||
" `0`, this function returns an `Error`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(13.3, by: 3.3)\n"
|
||||
" // -> Ok(0.1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(-13.3, by: 3.3)\n"
|
||||
" // -> Ok(3.2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(13.3, by: -3.3)\n"
|
||||
" // -> Ok(-3.2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(-13.3, by: -3.3)\n"
|
||||
" // -> Ok(-0.1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec modulo(float(), float()) -> {ok, float()} | {error, nil}.
|
||||
modulo(Dividend, Divisor) ->
|
||||
case Divisor of
|
||||
+0.0 ->
|
||||
{error, nil};
|
||||
|
||||
_ ->
|
||||
{ok, Dividend - (math:floor(case Divisor of
|
||||
+0.0 -> +0.0;
|
||||
-0.0 -> -0.0;
|
||||
Gleam@denominator -> Dividend / Gleam@denominator
|
||||
end) * Divisor)}
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 502).
|
||||
?DOC(
|
||||
" Returns division of the inputs as a `Result`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" divide(0.0, 1.0)\n"
|
||||
" // -> Ok(0.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" divide(1.0, 0.0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec divide(float(), float()) -> {ok, float()} | {error, nil}.
|
||||
divide(A, B) ->
|
||||
case B of
|
||||
+0.0 ->
|
||||
{error, nil};
|
||||
|
||||
B@1 ->
|
||||
{ok, case B@1 of
|
||||
+0.0 -> +0.0;
|
||||
-0.0 -> -0.0;
|
||||
Gleam@denominator -> A / Gleam@denominator
|
||||
end}
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 533).
|
||||
?DOC(
|
||||
" Adds two floats together.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `+.` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" add(1.0, 2.0)\n"
|
||||
" // -> 3.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" list.fold([1.0, 2.0, 3.0], 0.0, add)\n"
|
||||
" // -> 6.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3.0 |> add(2.0)\n"
|
||||
" // -> 5.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec add(float(), float()) -> float().
|
||||
add(A, B) ->
|
||||
A + B.
|
||||
|
||||
-file("src/gleam/float.gleam", 561).
|
||||
?DOC(
|
||||
" Multiplies two floats together.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `*.` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" multiply(2.0, 4.0)\n"
|
||||
" // -> 8.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" list.fold([2.0, 3.0, 4.0], 1.0, multiply)\n"
|
||||
" // -> 24.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3.0 |> multiply(2.0)\n"
|
||||
" // -> 6.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec multiply(float(), float()) -> float().
|
||||
multiply(A, B) ->
|
||||
A * B.
|
||||
|
||||
-file("src/gleam/float.gleam", 594).
|
||||
?DOC(
|
||||
" Subtracts one float from another.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `-.` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" subtract(3.0, 1.0)\n"
|
||||
" // -> 2.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" list.fold([1.0, 2.0, 3.0], 10.0, subtract)\n"
|
||||
" // -> 4.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3.0 |> subtract(_, 2.0)\n"
|
||||
" // -> 1.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3.0 |> subtract(2.0, _)\n"
|
||||
" // -> -1.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec subtract(float(), float()) -> float().
|
||||
subtract(A, B) ->
|
||||
A - B.
|
||||
|
||||
-file("src/gleam/float.gleam", 623).
|
||||
?DOC(
|
||||
" Returns the natural logarithm (base e) of the given as a `Result`. If the\n"
|
||||
" input is less than or equal to 0, returns `Error(Nil)`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" logarithm(1.0)\n"
|
||||
" // -> Ok(0.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" logarithm(2.718281828459045) // e\n"
|
||||
" // -> Ok(1.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" logarithm(0.0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" logarithm(-1.0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec logarithm(float()) -> {ok, float()} | {error, nil}.
|
||||
logarithm(X) ->
|
||||
case X =< +0.0 of
|
||||
true ->
|
||||
{error, nil};
|
||||
|
||||
false ->
|
||||
{ok, math:log(X)}
|
||||
end.
|
||||
|
||||
-file("src/gleam/float.gleam", 661).
|
||||
?DOC(
|
||||
" Returns e (Euler's number) raised to the power of the given exponent, as\n"
|
||||
" a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exponential(0.0)\n"
|
||||
" // -> Ok(1.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exponential(1.0)\n"
|
||||
" // -> Ok(2.718281828459045)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" exponential(-1.0)\n"
|
||||
" // -> Ok(0.36787944117144233)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec exponential(float()) -> float().
|
||||
exponential(X) ->
|
||||
math:exp(X).
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,30 @@
|
|||
-module(gleam@function).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/function.gleam").
|
||||
-export([identity/1, tap/2]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-file("src/gleam/function.gleam", 3).
|
||||
?DOC(" Takes a single argument and always returns its input value.\n").
|
||||
-spec identity(CNY) -> CNY.
|
||||
identity(X) ->
|
||||
X.
|
||||
|
||||
-file("src/gleam/function.gleam", 12).
|
||||
?DOC(
|
||||
" Takes an argument and a single function, calls that function with that\n"
|
||||
" argument and returns that argument instead of the function return value.\n"
|
||||
"\n"
|
||||
" Useful for running synchronous side effects in a pipeline.\n"
|
||||
).
|
||||
-spec tap(CNZ, fun((CNZ) -> any())) -> CNZ.
|
||||
tap(Arg, Effect) ->
|
||||
Effect(Arg),
|
||||
Arg.
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.cache
Normal file
Binary file not shown.
Binary file not shown.
984
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.erl
Normal file
984
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.erl
Normal file
|
|
@ -0,0 +1,984 @@
|
|||
-module(gleam@int).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/int.gleam").
|
||||
-export([absolute_value/1, parse/1, base_parse/2, to_string/1, to_base_string/2, to_base2/1, to_base8/1, to_base16/1, to_base36/1, to_float/1, power/2, square_root/1, compare/2, min/2, max/2, clamp/3, is_even/1, is_odd/1, negate/1, sum/1, product/1, digits/2, undigits/2, random/1, divide/2, remainder/2, modulo/2, floor_divide/2, add/2, multiply/2, subtract/2, bitwise_and/2, bitwise_not/1, bitwise_or/2, bitwise_exclusive_or/2, bitwise_shift_left/2, bitwise_shift_right/2]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(
|
||||
" Functions for working with integers.\n"
|
||||
"\n"
|
||||
" ## Division by zero\n"
|
||||
"\n"
|
||||
" In Erlang division by zero results in a crash, however Gleam does not have\n"
|
||||
" partial functions and operators in core so instead division by zero returns\n"
|
||||
" zero, a behaviour taken from Pony, Coq, and Lean.\n"
|
||||
"\n"
|
||||
" This may seem unexpected at first, but it is no less mathematically valid\n"
|
||||
" than crashing or returning a special value. Division by zero is undefined\n"
|
||||
" in mathematics.\n"
|
||||
).
|
||||
|
||||
-file("src/gleam/int.gleam", 30).
|
||||
?DOC(
|
||||
" Returns the absolute value of the input.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" absolute_value(-12)\n"
|
||||
" // -> 12\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" absolute_value(10)\n"
|
||||
" // -> 10\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec absolute_value(integer()) -> integer().
|
||||
absolute_value(X) ->
|
||||
case X >= 0 of
|
||||
true ->
|
||||
X;
|
||||
|
||||
false ->
|
||||
X * -1
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 107).
|
||||
?DOC(
|
||||
" Parses a given string as an int if possible.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" parse(\"2\")\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" parse(\"ABC\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec parse(binary()) -> {ok, integer()} | {error, nil}.
|
||||
parse(String) ->
|
||||
gleam_stdlib:parse_int(String).
|
||||
|
||||
-file("src/gleam/int.gleam", 139).
|
||||
?DOC(
|
||||
" Parses a given string as an int in a given base if possible.\n"
|
||||
" Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" base_parse(\"10\", 2)\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" base_parse(\"30\", 16)\n"
|
||||
" // -> Ok(48)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" base_parse(\"1C\", 36)\n"
|
||||
" // -> Ok(48)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" base_parse(\"48\", 1)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" base_parse(\"48\", 37)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec base_parse(binary(), integer()) -> {ok, integer()} | {error, nil}.
|
||||
base_parse(String, Base) ->
|
||||
case (Base >= 2) andalso (Base =< 36) of
|
||||
true ->
|
||||
gleam_stdlib:int_from_base_string(String, Base);
|
||||
|
||||
false ->
|
||||
{error, nil}
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 161).
|
||||
?DOC(
|
||||
" Prints a given int to a string.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_string(2)\n"
|
||||
" // -> \"2\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_string(integer()) -> binary().
|
||||
to_string(X) ->
|
||||
erlang:integer_to_binary(X).
|
||||
|
||||
-file("src/gleam/int.gleam", 194).
|
||||
?DOC(
|
||||
" Prints a given int to a string using the base number provided.\n"
|
||||
" Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.\n"
|
||||
" For common bases (2, 8, 16, 36), use the `to_baseN` functions.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base_string(2, 2)\n"
|
||||
" // -> Ok(\"10\")\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base_string(48, 16)\n"
|
||||
" // -> Ok(\"30\")\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base_string(48, 36)\n"
|
||||
" // -> Ok(\"1C\")\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base_string(48, 1)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base_string(48, 37)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_base_string(integer(), integer()) -> {ok, binary()} | {error, nil}.
|
||||
to_base_string(X, Base) ->
|
||||
case (Base >= 2) andalso (Base =< 36) of
|
||||
true ->
|
||||
{ok, erlang:integer_to_binary(X, Base)};
|
||||
|
||||
false ->
|
||||
{error, nil}
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 214).
|
||||
?DOC(
|
||||
" Prints a given int to a string using base-2.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base2(2)\n"
|
||||
" // -> \"10\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_base2(integer()) -> binary().
|
||||
to_base2(X) ->
|
||||
erlang:integer_to_binary(X, 2).
|
||||
|
||||
-file("src/gleam/int.gleam", 227).
|
||||
?DOC(
|
||||
" Prints a given int to a string using base-8.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base8(15)\n"
|
||||
" // -> \"17\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_base8(integer()) -> binary().
|
||||
to_base8(X) ->
|
||||
erlang:integer_to_binary(X, 8).
|
||||
|
||||
-file("src/gleam/int.gleam", 240).
|
||||
?DOC(
|
||||
" Prints a given int to a string using base-16.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base16(48)\n"
|
||||
" // -> \"30\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_base16(integer()) -> binary().
|
||||
to_base16(X) ->
|
||||
erlang:integer_to_binary(X, 16).
|
||||
|
||||
-file("src/gleam/int.gleam", 253).
|
||||
?DOC(
|
||||
" Prints a given int to a string using base-36.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_base36(48)\n"
|
||||
" // -> \"1C\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_base36(integer()) -> binary().
|
||||
to_base36(X) ->
|
||||
erlang:integer_to_binary(X, 36).
|
||||
|
||||
-file("src/gleam/int.gleam", 278).
|
||||
?DOC(
|
||||
" Takes an int and returns its value as a float.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_float(5)\n"
|
||||
" // -> 5.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_float(0)\n"
|
||||
" // -> 0.0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_float(-3)\n"
|
||||
" // -> -3.0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_float(integer()) -> float().
|
||||
to_float(X) ->
|
||||
erlang:float(X).
|
||||
|
||||
-file("src/gleam/int.gleam", 67).
|
||||
?DOC(
|
||||
" Returns the results of the base being raised to the power of the\n"
|
||||
" exponent, as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(2, -1.0)\n"
|
||||
" // -> Ok(0.5)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(2, 2.0)\n"
|
||||
" // -> Ok(4.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(8, 1.5)\n"
|
||||
" // -> Ok(22.627416997969522)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 4 |> power(of: 2.0)\n"
|
||||
" // -> Ok(16.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" power(-1, 0.5)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec power(integer(), float()) -> {ok, float()} | {error, nil}.
|
||||
power(Base, Exponent) ->
|
||||
_pipe = erlang:float(Base),
|
||||
gleam@float:power(_pipe, Exponent).
|
||||
|
||||
-file("src/gleam/int.gleam", 86).
|
||||
?DOC(
|
||||
" Returns the square root of the input as a `Float`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" square_root(4)\n"
|
||||
" // -> Ok(2.0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" square_root(-16)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec square_root(integer()) -> {ok, float()} | {error, nil}.
|
||||
square_root(X) ->
|
||||
_pipe = erlang:float(X),
|
||||
gleam@float:square_root(_pipe).
|
||||
|
||||
-file("src/gleam/int.gleam", 314).
|
||||
?DOC(
|
||||
" Compares two ints, returning an order.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(2, 3)\n"
|
||||
" // -> Lt\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(4, 3)\n"
|
||||
" // -> Gt\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(3, 3)\n"
|
||||
" // -> Eq\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec compare(integer(), integer()) -> gleam@order:order().
|
||||
compare(A, B) ->
|
||||
case A =:= B of
|
||||
true ->
|
||||
eq;
|
||||
|
||||
false ->
|
||||
case A < B of
|
||||
true ->
|
||||
lt;
|
||||
|
||||
false ->
|
||||
gt
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 334).
|
||||
?DOC(
|
||||
" Compares two ints, returning the smaller of the two.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" min(2, 3)\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec min(integer(), integer()) -> integer().
|
||||
min(A, B) ->
|
||||
case A < B of
|
||||
true ->
|
||||
A;
|
||||
|
||||
false ->
|
||||
B
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 350).
|
||||
?DOC(
|
||||
" Compares two ints, returning the larger of the two.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" max(2, 3)\n"
|
||||
" // -> 3\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec max(integer(), integer()) -> integer().
|
||||
max(A, B) ->
|
||||
case A > B of
|
||||
true ->
|
||||
A;
|
||||
|
||||
false ->
|
||||
B
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 289).
|
||||
?DOC(
|
||||
" Restricts an int between a lower and upper bound.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" clamp(40, min: 50, max: 60)\n"
|
||||
" // -> 50\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec clamp(integer(), integer(), integer()) -> integer().
|
||||
clamp(X, Min_bound, Max_bound) ->
|
||||
_pipe = X,
|
||||
_pipe@1 = min(_pipe, Max_bound),
|
||||
max(_pipe@1, Min_bound).
|
||||
|
||||
-file("src/gleam/int.gleam", 371).
|
||||
?DOC(
|
||||
" Returns whether the value provided is even.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_even(2)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_even(3)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_even(integer()) -> boolean().
|
||||
is_even(X) ->
|
||||
(X rem 2) =:= 0.
|
||||
|
||||
-file("src/gleam/int.gleam", 389).
|
||||
?DOC(
|
||||
" Returns whether the value provided is odd.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_odd(3)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_odd(2)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_odd(integer()) -> boolean().
|
||||
is_odd(X) ->
|
||||
(X rem 2) /= 0.
|
||||
|
||||
-file("src/gleam/int.gleam", 402).
|
||||
?DOC(
|
||||
" Returns the negative of the value provided.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(1)\n"
|
||||
" // -> -1\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec negate(integer()) -> integer().
|
||||
negate(X) ->
|
||||
-1 * X.
|
||||
|
||||
-file("src/gleam/int.gleam", 419).
|
||||
-spec sum_loop(list(integer()), integer()) -> integer().
|
||||
sum_loop(Numbers, Initial) ->
|
||||
case Numbers of
|
||||
[First | Rest] ->
|
||||
sum_loop(Rest, First + Initial);
|
||||
|
||||
[] ->
|
||||
Initial
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 415).
|
||||
?DOC(
|
||||
" Sums a list of ints.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" sum([1, 2, 3])\n"
|
||||
" // -> 6\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec sum(list(integer())) -> integer().
|
||||
sum(Numbers) ->
|
||||
sum_loop(Numbers, 0).
|
||||
|
||||
-file("src/gleam/int.gleam", 439).
|
||||
-spec product_loop(list(integer()), integer()) -> integer().
|
||||
product_loop(Numbers, Initial) ->
|
||||
case Numbers of
|
||||
[First | Rest] ->
|
||||
product_loop(Rest, First * Initial);
|
||||
|
||||
[] ->
|
||||
Initial
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 435).
|
||||
?DOC(
|
||||
" Multiplies a list of ints and returns the product.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" product([2, 3, 4])\n"
|
||||
" // -> 24\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec product(list(integer())) -> integer().
|
||||
product(Numbers) ->
|
||||
product_loop(Numbers, 1).
|
||||
|
||||
-file("src/gleam/int.gleam", 454).
|
||||
-spec digits_loop(integer(), integer(), list(integer())) -> list(integer()).
|
||||
digits_loop(X, Base, Acc) ->
|
||||
case absolute_value(X) < Base of
|
||||
true ->
|
||||
[X | Acc];
|
||||
|
||||
false ->
|
||||
digits_loop(case Base of
|
||||
0 -> 0;
|
||||
Gleam@denominator -> X div Gleam@denominator
|
||||
end, Base, [case Base of
|
||||
0 -> 0;
|
||||
Gleam@denominator@1 -> X rem Gleam@denominator@1
|
||||
end | Acc])
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 447).
|
||||
-spec digits(integer(), integer()) -> {ok, list(integer())} | {error, nil}.
|
||||
digits(X, Base) ->
|
||||
case Base < 2 of
|
||||
true ->
|
||||
{error, nil};
|
||||
|
||||
false ->
|
||||
{ok, digits_loop(X, Base, [])}
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 469).
|
||||
-spec undigits_loop(list(integer()), integer(), integer()) -> {ok, integer()} |
|
||||
{error, nil}.
|
||||
undigits_loop(Numbers, Base, Acc) ->
|
||||
case Numbers of
|
||||
[] ->
|
||||
{ok, Acc};
|
||||
|
||||
[Digit | _] when Digit >= Base ->
|
||||
{error, nil};
|
||||
|
||||
[Digit@1 | Rest] ->
|
||||
undigits_loop(Rest, Base, (Acc * Base) + Digit@1)
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 462).
|
||||
-spec undigits(list(integer()), integer()) -> {ok, integer()} | {error, nil}.
|
||||
undigits(Numbers, Base) ->
|
||||
case Base < 2 of
|
||||
true ->
|
||||
{error, nil};
|
||||
|
||||
false ->
|
||||
undigits_loop(Numbers, Base, 0)
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 498).
|
||||
?DOC(
|
||||
" Generates a random int between zero and the given maximum.\n"
|
||||
"\n"
|
||||
" The lower number is inclusive, the upper number is exclusive.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" random(10)\n"
|
||||
" // -> 4\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" random(1)\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" random(-1)\n"
|
||||
" // -> -1\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec random(integer()) -> integer().
|
||||
random(Max) ->
|
||||
_pipe = (rand:uniform() * erlang:float(Max)),
|
||||
_pipe@1 = math:floor(_pipe),
|
||||
erlang:round(_pipe@1).
|
||||
|
||||
-file("src/gleam/int.gleam", 531).
|
||||
?DOC(
|
||||
" Performs a truncated integer division.\n"
|
||||
"\n"
|
||||
" Returns division of the inputs as a `Result`: If the given divisor equals\n"
|
||||
" `0`, this function returns an `Error`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" divide(0, 1)\n"
|
||||
" // -> Ok(0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" divide(1, 0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" divide(5, 2)\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" divide(-99, 2)\n"
|
||||
" // -> Ok(-49)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}.
|
||||
divide(Dividend, Divisor) ->
|
||||
case Divisor of
|
||||
0 ->
|
||||
{error, nil};
|
||||
|
||||
Divisor@1 ->
|
||||
{ok, case Divisor@1 of
|
||||
0 -> 0;
|
||||
Gleam@denominator -> Dividend div Gleam@denominator
|
||||
end}
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 583).
|
||||
?DOC(
|
||||
" Computes the remainder of an integer division of inputs as a `Result`.\n"
|
||||
"\n"
|
||||
" Returns division of the inputs as a `Result`: If the given divisor equals\n"
|
||||
" `0`, this function returns an `Error`.\n"
|
||||
"\n"
|
||||
" Most the time you will want to use the `%` operator instead of this\n"
|
||||
" function.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(3, 2)\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(1, 0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(10, -1)\n"
|
||||
" // -> Ok(0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(13, by: 3)\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(-13, by: 3)\n"
|
||||
" // -> Ok(-1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(13, by: -3)\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" remainder(-13, by: -3)\n"
|
||||
" // -> Ok(-1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec remainder(integer(), integer()) -> {ok, integer()} | {error, nil}.
|
||||
remainder(Dividend, Divisor) ->
|
||||
case Divisor of
|
||||
0 ->
|
||||
{error, nil};
|
||||
|
||||
Divisor@1 ->
|
||||
{ok, case Divisor@1 of
|
||||
0 -> 0;
|
||||
Gleam@denominator -> Dividend rem Gleam@denominator
|
||||
end}
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 625).
|
||||
?DOC(
|
||||
" Computes the modulo of an integer division of inputs as a `Result`.\n"
|
||||
"\n"
|
||||
" Returns division of the inputs as a `Result`: If the given divisor equals\n"
|
||||
" `0`, this function returns an `Error`.\n"
|
||||
"\n"
|
||||
" Most the time you will want to use the `%` operator instead of this\n"
|
||||
" function.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(3, 2)\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(1, 0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(10, -1)\n"
|
||||
" // -> Ok(0)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(13, by: 3)\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" modulo(-13, by: 3)\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec modulo(integer(), integer()) -> {ok, integer()} | {error, nil}.
|
||||
modulo(Dividend, Divisor) ->
|
||||
case Divisor of
|
||||
0 ->
|
||||
{error, nil};
|
||||
|
||||
_ ->
|
||||
Remainder = case Divisor of
|
||||
0 -> 0;
|
||||
Gleam@denominator -> Dividend rem Gleam@denominator
|
||||
end,
|
||||
case (Remainder * Divisor) < 0 of
|
||||
true ->
|
||||
{ok, Remainder + Divisor};
|
||||
|
||||
false ->
|
||||
{ok, Remainder}
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 669).
|
||||
?DOC(
|
||||
" Performs a *floored* integer division, which means that the result will\n"
|
||||
" always be rounded towards negative infinity.\n"
|
||||
"\n"
|
||||
" If you want to perform truncated integer division (rounding towards zero),\n"
|
||||
" use `int.divide()` or the `/` operator instead.\n"
|
||||
"\n"
|
||||
" Returns division of the inputs as a `Result`: If the given divisor equals\n"
|
||||
" `0`, this function returns an `Error`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" floor_divide(1, 0)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" floor_divide(5, 2)\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" floor_divide(6, -4)\n"
|
||||
" // -> Ok(-2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" floor_divide(-99, 2)\n"
|
||||
" // -> Ok(-50)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec floor_divide(integer(), integer()) -> {ok, integer()} | {error, nil}.
|
||||
floor_divide(Dividend, Divisor) ->
|
||||
case Divisor of
|
||||
0 ->
|
||||
{error, nil};
|
||||
|
||||
Divisor@1 ->
|
||||
case ((Dividend * Divisor@1) < 0) andalso ((case Divisor@1 of
|
||||
0 -> 0;
|
||||
Gleam@denominator -> Dividend rem Gleam@denominator
|
||||
end) /= 0) of
|
||||
true ->
|
||||
{ok, (case Divisor@1 of
|
||||
0 -> 0;
|
||||
Gleam@denominator@1 -> Dividend div Gleam@denominator@1
|
||||
end) - 1};
|
||||
|
||||
false ->
|
||||
{ok, case Divisor@1 of
|
||||
0 -> 0;
|
||||
Gleam@denominator@2 -> Dividend div Gleam@denominator@2
|
||||
end}
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/int.gleam", 703).
|
||||
?DOC(
|
||||
" Adds two integers together.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `+` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" add(1, 2)\n"
|
||||
" // -> 3\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/list\n"
|
||||
" list.fold([1, 2, 3], 0, add)\n"
|
||||
" // -> 6\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3 |> add(2)\n"
|
||||
" // -> 5\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec add(integer(), integer()) -> integer().
|
||||
add(A, B) ->
|
||||
A + B.
|
||||
|
||||
-file("src/gleam/int.gleam", 731).
|
||||
?DOC(
|
||||
" Multiplies two integers together.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `*` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" multiply(2, 4)\n"
|
||||
" // -> 8\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" list.fold([2, 3, 4], 1, multiply)\n"
|
||||
" // -> 24\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3 |> multiply(2)\n"
|
||||
" // -> 6\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec multiply(integer(), integer()) -> integer().
|
||||
multiply(A, B) ->
|
||||
A * B.
|
||||
|
||||
-file("src/gleam/int.gleam", 764).
|
||||
?DOC(
|
||||
" Subtracts one int from another.\n"
|
||||
"\n"
|
||||
" It's the function equivalent of the `-` operator.\n"
|
||||
" This function is useful in higher order functions or pipes.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" subtract(3, 1)\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" list.fold([1, 2, 3], 10, subtract)\n"
|
||||
" // -> 4\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3 |> subtract(2)\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" 3 |> subtract(2, _)\n"
|
||||
" // -> -1\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec subtract(integer(), integer()) -> integer().
|
||||
subtract(A, B) ->
|
||||
A - B.
|
||||
|
||||
-file("src/gleam/int.gleam", 776).
|
||||
?DOC(
|
||||
" Calculates the bitwise AND of its arguments.\n"
|
||||
"\n"
|
||||
" The exact behaviour of this function depends on the target platform.\n"
|
||||
" On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n"
|
||||
" is equivalent to bitwise operations on big-ints.\n"
|
||||
).
|
||||
-spec bitwise_and(integer(), integer()) -> integer().
|
||||
bitwise_and(X, Y) ->
|
||||
erlang:'band'(X, Y).
|
||||
|
||||
-file("src/gleam/int.gleam", 786).
|
||||
?DOC(
|
||||
" Calculates the bitwise NOT of its argument.\n"
|
||||
"\n"
|
||||
" The exact behaviour of this function depends on the target platform.\n"
|
||||
" On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n"
|
||||
" is equivalent to bitwise operations on big-ints.\n"
|
||||
).
|
||||
-spec bitwise_not(integer()) -> integer().
|
||||
bitwise_not(X) ->
|
||||
erlang:'bnot'(X).
|
||||
|
||||
-file("src/gleam/int.gleam", 796).
|
||||
?DOC(
|
||||
" Calculates the bitwise OR of its arguments.\n"
|
||||
"\n"
|
||||
" The exact behaviour of this function depends on the target platform.\n"
|
||||
" On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n"
|
||||
" is equivalent to bitwise operations on big-ints.\n"
|
||||
).
|
||||
-spec bitwise_or(integer(), integer()) -> integer().
|
||||
bitwise_or(X, Y) ->
|
||||
erlang:'bor'(X, Y).
|
||||
|
||||
-file("src/gleam/int.gleam", 806).
|
||||
?DOC(
|
||||
" Calculates the bitwise XOR of its arguments.\n"
|
||||
"\n"
|
||||
" The exact behaviour of this function depends on the target platform.\n"
|
||||
" On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n"
|
||||
" is equivalent to bitwise operations on big-ints.\n"
|
||||
).
|
||||
-spec bitwise_exclusive_or(integer(), integer()) -> integer().
|
||||
bitwise_exclusive_or(X, Y) ->
|
||||
erlang:'bxor'(X, Y).
|
||||
|
||||
-file("src/gleam/int.gleam", 816).
|
||||
?DOC(
|
||||
" Calculates the result of an arithmetic left bitshift.\n"
|
||||
"\n"
|
||||
" The exact behaviour of this function depends on the target platform.\n"
|
||||
" On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n"
|
||||
" is equivalent to bitwise operations on big-ints.\n"
|
||||
).
|
||||
-spec bitwise_shift_left(integer(), integer()) -> integer().
|
||||
bitwise_shift_left(X, Y) ->
|
||||
erlang:'bsl'(X, Y).
|
||||
|
||||
-file("src/gleam/int.gleam", 826).
|
||||
?DOC(
|
||||
" Calculates the result of an arithmetic right bitshift.\n"
|
||||
"\n"
|
||||
" The exact behaviour of this function depends on the target platform.\n"
|
||||
" On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n"
|
||||
" is equivalent to bitwise operations on big-ints.\n"
|
||||
).
|
||||
-spec bitwise_shift_right(integer(), integer()) -> integer().
|
||||
bitwise_shift_right(X, Y) ->
|
||||
erlang:'bsr'(X, Y).
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache
Normal file
Binary file not shown.
Binary file not shown.
80
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.erl
Normal file
80
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.erl
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
-module(gleam@io).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/io.gleam").
|
||||
-export([print/1, print_error/1, println/1, println_error/1]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-file("src/gleam/io.gleam", 15).
|
||||
?DOC(
|
||||
" Writes a string to standard output (stdout).\n"
|
||||
"\n"
|
||||
" If you want your output to be printed on its own line see `println`.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" io.print(\"Hi mum\")\n"
|
||||
" // -> Nil\n"
|
||||
" // Hi mum\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec print(binary()) -> nil.
|
||||
print(String) ->
|
||||
gleam_stdlib:print(String).
|
||||
|
||||
-file("src/gleam/io.gleam", 31).
|
||||
?DOC(
|
||||
" Writes a string to standard error (stderr).\n"
|
||||
"\n"
|
||||
" If you want your output to be printed on its own line see `println_error`.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```\n"
|
||||
" io.print_error(\"Hi pop\")\n"
|
||||
" // -> Nil\n"
|
||||
" // Hi pop\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec print_error(binary()) -> nil.
|
||||
print_error(String) ->
|
||||
gleam_stdlib:print_error(String).
|
||||
|
||||
-file("src/gleam/io.gleam", 45).
|
||||
?DOC(
|
||||
" Writes a string to standard output (stdout), appending a newline to the end.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" io.println(\"Hi mum\")\n"
|
||||
" // -> Nil\n"
|
||||
" // Hi mum\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec println(binary()) -> nil.
|
||||
println(String) ->
|
||||
gleam_stdlib:println(String).
|
||||
|
||||
-file("src/gleam/io.gleam", 59).
|
||||
?DOC(
|
||||
" Writes a string to standard error (stderr), appending a newline to the end.\n"
|
||||
"\n"
|
||||
" ## Example\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" io.println_error(\"Hi pop\")\n"
|
||||
" // -> Nil\n"
|
||||
" // Hi pop\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec println_error(binary()) -> nil.
|
||||
println_error(String) ->
|
||||
gleam_stdlib:println_error(String).
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.cache
Normal file
Binary file not shown.
Binary file not shown.
2860
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.erl
Normal file
2860
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.erl
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
413
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.erl
Normal file
413
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.erl
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
-module(gleam@option).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/option.gleam").
|
||||
-export([all/1, is_some/1, is_none/1, to_result/2, from_result/1, unwrap/2, lazy_unwrap/2, map/2, flatten/1, then/2, 'or'/2, lazy_or/2, values/1]).
|
||||
-export_type([option/1]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-type option(GA) :: {some, GA} | none.
|
||||
|
||||
-file("src/gleam/option.gleam", 59).
|
||||
-spec reverse_and_prepend(list(GP), list(GP)) -> list(GP).
|
||||
reverse_and_prepend(Prefix, Suffix) ->
|
||||
case Prefix of
|
||||
[] ->
|
||||
Suffix;
|
||||
|
||||
[First | Rest] ->
|
||||
reverse_and_prepend(Rest, [First | Suffix])
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 44).
|
||||
-spec all_loop(list(option(GG)), list(GG)) -> option(list(GG)).
|
||||
all_loop(List, Acc) ->
|
||||
case List of
|
||||
[] ->
|
||||
{some, lists:reverse(Acc)};
|
||||
|
||||
[none | _] ->
|
||||
none;
|
||||
|
||||
[{some, First} | Rest] ->
|
||||
all_loop(Rest, [First | Acc])
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 40).
|
||||
?DOC(
|
||||
" Combines a list of `Option`s into a single `Option`.\n"
|
||||
" If all elements in the list are `Some` then returns a `Some` holding the list of values.\n"
|
||||
" If any element is `None` then returns`None`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" all([Some(1), Some(2)])\n"
|
||||
" // -> Some([1, 2])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" all([Some(1), None])\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec all(list(option(GB))) -> option(list(GB)).
|
||||
all(List) ->
|
||||
all_loop(List, []).
|
||||
|
||||
-file("src/gleam/option.gleam", 80).
|
||||
?DOC(
|
||||
" Checks whether the `Option` is a `Some` value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_some(Some(1))\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_some(None)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_some(option(any())) -> boolean().
|
||||
is_some(Option) ->
|
||||
Option /= none.
|
||||
|
||||
-file("src/gleam/option.gleam", 98).
|
||||
?DOC(
|
||||
" Checks whether the `Option` is a `None` value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_none(Some(1))\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_none(None)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_none(option(any())) -> boolean().
|
||||
is_none(Option) ->
|
||||
Option =:= none.
|
||||
|
||||
-file("src/gleam/option.gleam", 116).
|
||||
?DOC(
|
||||
" Converts an `Option` type to a `Result` type.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_result(Some(1), \"some_error\")\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_result(None, \"some_error\")\n"
|
||||
" // -> Error(\"some_error\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_result(option(GX), HA) -> {ok, GX} | {error, HA}.
|
||||
to_result(Option, E) ->
|
||||
case Option of
|
||||
{some, A} ->
|
||||
{ok, A};
|
||||
|
||||
none ->
|
||||
{error, E}
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 137).
|
||||
?DOC(
|
||||
" Converts a `Result` type to an `Option` type.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_result(Ok(1))\n"
|
||||
" // -> Some(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_result(Error(\"some_error\"))\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec from_result({ok, HD} | {error, any()}) -> option(HD).
|
||||
from_result(Result) ->
|
||||
case Result of
|
||||
{ok, A} ->
|
||||
{some, A};
|
||||
|
||||
{error, _} ->
|
||||
none
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 158).
|
||||
?DOC(
|
||||
" Extracts the value from an `Option`, returning a default value if there is none.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap(Some(1), 0)\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap(None, 0)\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec unwrap(option(HI), HI) -> HI.
|
||||
unwrap(Option, Default) ->
|
||||
case Option of
|
||||
{some, X} ->
|
||||
X;
|
||||
|
||||
none ->
|
||||
Default
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 179).
|
||||
?DOC(
|
||||
" Extracts the value from an `Option`, evaluating the default function if the option is `None`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_unwrap(Some(1), fn() { 0 })\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_unwrap(None, fn() { 0 })\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lazy_unwrap(option(HK), fun(() -> HK)) -> HK.
|
||||
lazy_unwrap(Option, Default) ->
|
||||
case Option of
|
||||
{some, X} ->
|
||||
X;
|
||||
|
||||
none ->
|
||||
Default()
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 204).
|
||||
?DOC(
|
||||
" Updates a value held within the `Some` of an `Option` by calling a given function\n"
|
||||
" on it.\n"
|
||||
"\n"
|
||||
" If the `Option` is a `None` rather than `Some`, the function is not called and the\n"
|
||||
" `Option` stays the same.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" map(over: Some(1), with: fn(x) { x + 1 })\n"
|
||||
" // -> Some(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" map(over: None, with: fn(x) { x + 1 })\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map(option(HM), fun((HM) -> HO)) -> option(HO).
|
||||
map(Option, Fun) ->
|
||||
case Option of
|
||||
{some, X} ->
|
||||
{some, Fun(X)};
|
||||
|
||||
none ->
|
||||
none
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 230).
|
||||
?DOC(
|
||||
" Merges a nested `Option` into a single layer.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" flatten(Some(Some(1)))\n"
|
||||
" // -> Some(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" flatten(Some(None))\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" flatten(None)\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec flatten(option(option(HQ))) -> option(HQ).
|
||||
flatten(Option) ->
|
||||
case Option of
|
||||
{some, X} ->
|
||||
X;
|
||||
|
||||
none ->
|
||||
none
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 269).
|
||||
?DOC(
|
||||
" Updates a value held within the `Some` of an `Option` by calling a given function\n"
|
||||
" on it, where the given function also returns an `Option`. The two options are\n"
|
||||
" then merged together into one `Option`.\n"
|
||||
"\n"
|
||||
" If the `Option` is a `None` rather than `Some` the function is not called and the\n"
|
||||
" option stays the same.\n"
|
||||
"\n"
|
||||
" This function is the equivalent of calling `map` followed by `flatten`, and\n"
|
||||
" it is useful for chaining together multiple functions that return `Option`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" then(Some(1), fn(x) { Some(x + 1) })\n"
|
||||
" // -> Some(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" then(Some(1), fn(x) { Some(#(\"a\", x)) })\n"
|
||||
" // -> Some(#(\"a\", 1))\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" then(Some(1), fn(_) { None })\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" then(None, fn(x) { Some(x + 1) })\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec then(option(HU), fun((HU) -> option(HW))) -> option(HW).
|
||||
then(Option, Fun) ->
|
||||
case Option of
|
||||
{some, X} ->
|
||||
Fun(X);
|
||||
|
||||
none ->
|
||||
none
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 300).
|
||||
?DOC(
|
||||
" Returns the first value if it is `Some`, otherwise returns the second value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(Some(1), Some(2))\n"
|
||||
" // -> Some(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(Some(1), None)\n"
|
||||
" // -> Some(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(None, Some(2))\n"
|
||||
" // -> Some(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(None, None)\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec 'or'(option(HZ), option(HZ)) -> option(HZ).
|
||||
'or'(First, Second) ->
|
||||
case First of
|
||||
{some, _} ->
|
||||
First;
|
||||
|
||||
none ->
|
||||
Second
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 331).
|
||||
?DOC(
|
||||
" Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(Some(1), fn() { Some(2) })\n"
|
||||
" // -> Some(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(Some(1), fn() { None })\n"
|
||||
" // -> Some(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(None, fn() { Some(2) })\n"
|
||||
" // -> Some(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(None, fn() { None })\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lazy_or(option(ID), fun(() -> option(ID))) -> option(ID).
|
||||
lazy_or(First, Second) ->
|
||||
case First of
|
||||
{some, _} ->
|
||||
First;
|
||||
|
||||
none ->
|
||||
Second()
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 352).
|
||||
-spec values_loop(list(option(IL)), list(IL)) -> list(IL).
|
||||
values_loop(List, Acc) ->
|
||||
case List of
|
||||
[] ->
|
||||
lists:reverse(Acc);
|
||||
|
||||
[none | Rest] ->
|
||||
values_loop(Rest, Acc);
|
||||
|
||||
[{some, First} | Rest@1] ->
|
||||
values_loop(Rest@1, [First | Acc])
|
||||
end.
|
||||
|
||||
-file("src/gleam/option.gleam", 348).
|
||||
?DOC(
|
||||
" Given a list of `Option`s,\n"
|
||||
" returns only the values inside `Some`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" values([Some(1), None, Some(3)])\n"
|
||||
" // -> [1, 3]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec values(list(option(IH))) -> list(IH).
|
||||
values(Options) ->
|
||||
values_loop(Options, []).
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache
Normal file
Binary file not shown.
Binary file not shown.
200
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.erl
Normal file
200
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.erl
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
-module(gleam@order).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/order.gleam").
|
||||
-export([negate/1, to_int/1, compare/2, reverse/1, break_tie/2, lazy_break_tie/2]).
|
||||
-export_type([order/0]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-type order() :: lt | eq | gt.
|
||||
|
||||
-file("src/gleam/order.gleam", 35).
|
||||
?DOC(
|
||||
" Inverts an order, so less-than becomes greater-than and greater-than\n"
|
||||
" becomes less-than.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(Lt)\n"
|
||||
" // -> Gt\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(Eq)\n"
|
||||
" // -> Eq\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" negate(Gt)\n"
|
||||
" // -> Lt\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec negate(order()) -> order().
|
||||
negate(Order) ->
|
||||
case Order of
|
||||
lt ->
|
||||
gt;
|
||||
|
||||
eq ->
|
||||
eq;
|
||||
|
||||
gt ->
|
||||
lt
|
||||
end.
|
||||
|
||||
-file("src/gleam/order.gleam", 62).
|
||||
?DOC(
|
||||
" Produces a numeric representation of the order.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_int(Lt)\n"
|
||||
" // -> -1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_int(Eq)\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_int(Gt)\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_int(order()) -> integer().
|
||||
to_int(Order) ->
|
||||
case Order of
|
||||
lt ->
|
||||
-1;
|
||||
|
||||
eq ->
|
||||
0;
|
||||
|
||||
gt ->
|
||||
1
|
||||
end.
|
||||
|
||||
-file("src/gleam/order.gleam", 79).
|
||||
?DOC(
|
||||
" Compares two `Order` values to one another, producing a new `Order`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(Eq, with: Lt)\n"
|
||||
" // -> Gt\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec compare(order(), order()) -> order().
|
||||
compare(A, B) ->
|
||||
case {A, B} of
|
||||
{X, Y} when X =:= Y ->
|
||||
eq;
|
||||
|
||||
{lt, _} ->
|
||||
lt;
|
||||
|
||||
{eq, gt} ->
|
||||
lt;
|
||||
|
||||
{_, _} ->
|
||||
gt
|
||||
end.
|
||||
|
||||
-file("src/gleam/order.gleam", 100).
|
||||
?DOC(
|
||||
" Inverts an ordering function, so less-than becomes greater-than and greater-than\n"
|
||||
" becomes less-than.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" list.sort([1, 5, 4], by: reverse(int.compare))\n"
|
||||
" // -> [5, 4, 1]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec reverse(fun((I, I) -> order())) -> fun((I, I) -> order()).
|
||||
reverse(Orderer) ->
|
||||
fun(A, B) -> Orderer(B, A) end.
|
||||
|
||||
-file("src/gleam/order.gleam", 122).
|
||||
?DOC(
|
||||
" Return a fallback `Order` in case the first argument is `Eq`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
"\n"
|
||||
" break_tie(in: int.compare(1, 1), with: Lt)\n"
|
||||
" // -> Lt\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
"\n"
|
||||
" break_tie(in: int.compare(1, 0), with: Eq)\n"
|
||||
" // -> Gt\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec break_tie(order(), order()) -> order().
|
||||
break_tie(Order, Other) ->
|
||||
case Order of
|
||||
lt ->
|
||||
Order;
|
||||
|
||||
gt ->
|
||||
Order;
|
||||
|
||||
eq ->
|
||||
Other
|
||||
end.
|
||||
|
||||
-file("src/gleam/order.gleam", 151).
|
||||
?DOC(
|
||||
" Invokes a fallback function returning an `Order` in case the first argument\n"
|
||||
" is `Eq`.\n"
|
||||
"\n"
|
||||
" This can be useful when the fallback comparison might be expensive and it\n"
|
||||
" needs to be delayed until strictly necessary.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
"\n"
|
||||
" lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt })\n"
|
||||
" // -> Lt\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
"\n"
|
||||
" lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq })\n"
|
||||
" // -> Gt\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lazy_break_tie(order(), fun(() -> order())) -> order().
|
||||
lazy_break_tie(Order, Comparison) ->
|
||||
case Order of
|
||||
lt ->
|
||||
Order;
|
||||
|
||||
gt ->
|
||||
Order;
|
||||
|
||||
eq ->
|
||||
Comparison()
|
||||
end.
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache
Normal file
Binary file not shown.
Binary file not shown.
110
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.erl
Normal file
110
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.erl
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
-module(gleam@pair).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/pair.gleam").
|
||||
-export([first/1, second/1, swap/1, map_first/2, map_second/2, new/2]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-file("src/gleam/pair.gleam", 10).
|
||||
?DOC(
|
||||
" Returns the first element in a pair.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" first(#(1, 2))\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec first({COH, any()}) -> COH.
|
||||
first(Pair) ->
|
||||
{A, _} = Pair,
|
||||
A.
|
||||
|
||||
-file("src/gleam/pair.gleam", 24).
|
||||
?DOC(
|
||||
" Returns the second element in a pair.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" second(#(1, 2))\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec second({any(), COK}) -> COK.
|
||||
second(Pair) ->
|
||||
{_, A} = Pair,
|
||||
A.
|
||||
|
||||
-file("src/gleam/pair.gleam", 38).
|
||||
?DOC(
|
||||
" Returns a new pair with the elements swapped.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" swap(#(1, 2))\n"
|
||||
" // -> #(2, 1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec swap({COL, COM}) -> {COM, COL}.
|
||||
swap(Pair) ->
|
||||
{A, B} = Pair,
|
||||
{B, A}.
|
||||
|
||||
-file("src/gleam/pair.gleam", 53).
|
||||
?DOC(
|
||||
" Returns a new pair with the first element having had `with` applied to\n"
|
||||
" it.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" #(1, 2) |> map_first(fn(n) { n * 2 })\n"
|
||||
" // -> #(2, 2)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map_first({CON, COO}, fun((CON) -> COP)) -> {COP, COO}.
|
||||
map_first(Pair, Fun) ->
|
||||
{A, B} = Pair,
|
||||
{Fun(A), B}.
|
||||
|
||||
-file("src/gleam/pair.gleam", 68).
|
||||
?DOC(
|
||||
" Returns a new pair with the second element having had `with` applied to\n"
|
||||
" it.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" #(1, 2) |> map_second(fn(n) { n * 2 })\n"
|
||||
" // -> #(1, 4)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map_second({COQ, COR}, fun((COR) -> COS)) -> {COQ, COS}.
|
||||
map_second(Pair, Fun) ->
|
||||
{A, B} = Pair,
|
||||
{A, Fun(B)}.
|
||||
|
||||
-file("src/gleam/pair.gleam", 83).
|
||||
?DOC(
|
||||
" Returns a new pair with the given elements. This can also be done using the dedicated\n"
|
||||
" syntax instead: `new(1, 2) == #(1, 2)`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new(1, 2)\n"
|
||||
" // -> #(1, 2)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec new(COT, COU) -> {COT, COU}.
|
||||
new(First, Second) ->
|
||||
{First, Second}.
|
||||
Binary file not shown.
Binary file not shown.
566
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.erl
Normal file
566
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.erl
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
-module(gleam@result).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/result.gleam").
|
||||
-export([is_ok/1, is_error/1, map/2, map_error/2, flatten/1, 'try'/2, then/2, unwrap/2, lazy_unwrap/2, unwrap_error/2, unwrap_both/1, 'or'/2, lazy_or/2, all/1, partition/1, replace/2, replace_error/2, values/1, try_recover/2]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(
|
||||
" Result represents the result of something that may succeed or not.\n"
|
||||
" `Ok` means it was successful, `Error` means it was not successful.\n"
|
||||
).
|
||||
|
||||
-file("src/gleam/result.gleam", 20).
|
||||
?DOC(
|
||||
" Checks whether the result is an `Ok` value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_ok(Ok(1))\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_ok(Error(Nil))\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_ok({ok, any()} | {error, any()}) -> boolean().
|
||||
is_ok(Result) ->
|
||||
case Result of
|
||||
{error, _} ->
|
||||
false;
|
||||
|
||||
{ok, _} ->
|
||||
true
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 41).
|
||||
?DOC(
|
||||
" Checks whether the result is an `Error` value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_error(Ok(1))\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_error(Error(Nil))\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_error({ok, any()} | {error, any()}) -> boolean().
|
||||
is_error(Result) ->
|
||||
case Result of
|
||||
{ok, _} ->
|
||||
false;
|
||||
|
||||
{error, _} ->
|
||||
true
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 66).
|
||||
?DOC(
|
||||
" Updates a value held within the `Ok` of a result by calling a given function\n"
|
||||
" on it.\n"
|
||||
"\n"
|
||||
" If the result is an `Error` rather than `Ok` the function is not called and the\n"
|
||||
" result stays the same.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" map(over: Ok(1), with: fn(x) { x + 1 })\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" map(over: Error(1), with: fn(x) { x + 1 })\n"
|
||||
" // -> Error(1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map({ok, CPE} | {error, CPF}, fun((CPE) -> CPI)) -> {ok, CPI} |
|
||||
{error, CPF}.
|
||||
map(Result, Fun) ->
|
||||
case Result of
|
||||
{ok, X} ->
|
||||
{ok, Fun(X)};
|
||||
|
||||
{error, E} ->
|
||||
{error, E}
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 91).
|
||||
?DOC(
|
||||
" Updates a value held within the `Error` of a result by calling a given function\n"
|
||||
" on it.\n"
|
||||
"\n"
|
||||
" If the result is `Ok` rather than `Error` the function is not called and the\n"
|
||||
" result stays the same.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" map_error(over: Error(1), with: fn(x) { x + 1 })\n"
|
||||
" // -> Error(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" map_error(over: Ok(1), with: fn(x) { x + 1 })\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map_error({ok, CPL} | {error, CPM}, fun((CPM) -> CPP)) -> {ok, CPL} |
|
||||
{error, CPP}.
|
||||
map_error(Result, Fun) ->
|
||||
case Result of
|
||||
{ok, X} ->
|
||||
{ok, X};
|
||||
|
||||
{error, Error} ->
|
||||
{error, Fun(Error)}
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 120).
|
||||
?DOC(
|
||||
" Merges a nested `Result` into a single layer.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" flatten(Ok(Ok(1)))\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" flatten(Ok(Error(\"\")))\n"
|
||||
" // -> Error(\"\")\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" flatten(Error(Nil))\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec flatten({ok, {ok, CPS} | {error, CPT}} | {error, CPT}) -> {ok, CPS} |
|
||||
{error, CPT}.
|
||||
flatten(Result) ->
|
||||
case Result of
|
||||
{ok, X} ->
|
||||
X;
|
||||
|
||||
{error, Error} ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 158).
|
||||
?DOC(
|
||||
" \"Updates\" an `Ok` result by passing its value to a function that yields a result,\n"
|
||||
" and returning the yielded result. (This may \"replace\" the `Ok` with an `Error`.)\n"
|
||||
"\n"
|
||||
" If the input is an `Error` rather than an `Ok`, the function is not called and\n"
|
||||
" the original `Error` is returned.\n"
|
||||
"\n"
|
||||
" This function is the equivalent of calling `map` followed by `flatten`, and\n"
|
||||
" it is useful for chaining together multiple functions that may fail.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" try(Ok(1), fn(x) { Ok(x + 1) })\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" try(Ok(1), fn(x) { Ok(#(\"a\", x)) })\n"
|
||||
" // -> Ok(#(\"a\", 1))\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" try(Ok(1), fn(_) { Error(\"Oh no\") })\n"
|
||||
" // -> Error(\"Oh no\")\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" try(Error(Nil), fn(x) { Ok(x + 1) })\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec 'try'({ok, CQA} | {error, CQB}, fun((CQA) -> {ok, CQE} | {error, CQB})) -> {ok,
|
||||
CQE} |
|
||||
{error, CQB}.
|
||||
'try'(Result, Fun) ->
|
||||
case Result of
|
||||
{ok, X} ->
|
||||
Fun(X);
|
||||
|
||||
{error, E} ->
|
||||
{error, E}
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 169).
|
||||
-spec then({ok, CQJ} | {error, CQK}, fun((CQJ) -> {ok, CQN} | {error, CQK})) -> {ok,
|
||||
CQN} |
|
||||
{error, CQK}.
|
||||
then(Result, Fun) ->
|
||||
'try'(Result, Fun).
|
||||
|
||||
-file("src/gleam/result.gleam", 191).
|
||||
?DOC(
|
||||
" Extracts the `Ok` value from a result, returning a default value if the result\n"
|
||||
" is an `Error`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap(Ok(1), 0)\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap(Error(\"\"), 0)\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec unwrap({ok, CQS} | {error, any()}, CQS) -> CQS.
|
||||
unwrap(Result, Default) ->
|
||||
case Result of
|
||||
{ok, V} ->
|
||||
V;
|
||||
|
||||
{error, _} ->
|
||||
Default
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 213).
|
||||
?DOC(
|
||||
" Extracts the `Ok` value from a result, evaluating the default function if the result\n"
|
||||
" is an `Error`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_unwrap(Ok(1), fn() { 0 })\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_unwrap(Error(\"\"), fn() { 0 })\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lazy_unwrap({ok, CQW} | {error, any()}, fun(() -> CQW)) -> CQW.
|
||||
lazy_unwrap(Result, Default) ->
|
||||
case Result of
|
||||
{ok, V} ->
|
||||
V;
|
||||
|
||||
{error, _} ->
|
||||
Default()
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 235).
|
||||
?DOC(
|
||||
" Extracts the `Error` value from a result, returning a default value if the result\n"
|
||||
" is an `Ok`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap_error(Error(1), 0)\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap_error(Ok(\"\"), 0)\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec unwrap_error({ok, any()} | {error, CRB}, CRB) -> CRB.
|
||||
unwrap_error(Result, Default) ->
|
||||
case Result of
|
||||
{ok, _} ->
|
||||
Default;
|
||||
|
||||
{error, E} ->
|
||||
E
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 257).
|
||||
?DOC(
|
||||
" Extracts the inner value from a result. Both the value and error must be of\n"
|
||||
" the same type.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap_both(Error(1))\n"
|
||||
" // -> 1\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" unwrap_both(Ok(2))\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec unwrap_both({ok, CRE} | {error, CRE}) -> CRE.
|
||||
unwrap_both(Result) ->
|
||||
case Result of
|
||||
{ok, A} ->
|
||||
A;
|
||||
|
||||
{error, A@1} ->
|
||||
A@1
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 288).
|
||||
?DOC(
|
||||
" Returns the first value if it is `Ok`, otherwise returns the second value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(Ok(1), Ok(2))\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(Ok(1), Error(\"Error 2\"))\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(Error(\"Error 1\"), Ok(2))\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" or(Error(\"Error 1\"), Error(\"Error 2\"))\n"
|
||||
" // -> Error(\"Error 2\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec 'or'({ok, CRH} | {error, CRI}, {ok, CRH} | {error, CRI}) -> {ok, CRH} |
|
||||
{error, CRI}.
|
||||
'or'(First, Second) ->
|
||||
case First of
|
||||
{ok, _} ->
|
||||
First;
|
||||
|
||||
{error, _} ->
|
||||
Second
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 321).
|
||||
?DOC(
|
||||
" Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value.\n"
|
||||
"\n"
|
||||
" If you need access to the initial error value, use `result.try_recover`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(Ok(1), fn() { Ok(2) })\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(Ok(1), fn() { Error(\"Error 2\") })\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(Error(\"Error 1\"), fn() { Ok(2) })\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lazy_or(Error(\"Error 1\"), fn() { Error(\"Error 2\") })\n"
|
||||
" // -> Error(\"Error 2\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lazy_or({ok, CRP} | {error, CRQ}, fun(() -> {ok, CRP} | {error, CRQ})) -> {ok,
|
||||
CRP} |
|
||||
{error, CRQ}.
|
||||
lazy_or(First, Second) ->
|
||||
case First of
|
||||
{ok, _} ->
|
||||
First;
|
||||
|
||||
{error, _} ->
|
||||
Second()
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 347).
|
||||
?DOC(
|
||||
" Combines a list of results into a single result.\n"
|
||||
" If all elements in the list are `Ok` then returns an `Ok` holding the list of values.\n"
|
||||
" If any element is `Error` then returns the first error.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" all([Ok(1), Ok(2)])\n"
|
||||
" // -> Ok([1, 2])\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" all([Ok(1), Error(\"e\")])\n"
|
||||
" // -> Error(\"e\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec all(list({ok, CRX} | {error, CRY})) -> {ok, list(CRX)} | {error, CRY}.
|
||||
all(Results) ->
|
||||
gleam@list:try_map(Results, fun(Result) -> Result end).
|
||||
|
||||
-file("src/gleam/result.gleam", 367).
|
||||
-spec partition_loop(list({ok, CSM} | {error, CSN}), list(CSM), list(CSN)) -> {list(CSM),
|
||||
list(CSN)}.
|
||||
partition_loop(Results, Oks, Errors) ->
|
||||
case Results of
|
||||
[] ->
|
||||
{Oks, Errors};
|
||||
|
||||
[{ok, A} | Rest] ->
|
||||
partition_loop(Rest, [A | Oks], Errors);
|
||||
|
||||
[{error, E} | Rest@1] ->
|
||||
partition_loop(Rest@1, Oks, [E | Errors])
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 363).
|
||||
?DOC(
|
||||
" Given a list of results, returns a pair where the first element is a list\n"
|
||||
" of all the values inside `Ok` and the second element is a list with all the\n"
|
||||
" values inside `Error`. The values in both lists appear in reverse order with\n"
|
||||
" respect to their position in the original list of results.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" partition([Ok(1), Error(\"a\"), Error(\"b\"), Ok(2)])\n"
|
||||
" // -> #([2, 1], [\"b\", \"a\"])\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec partition(list({ok, CSF} | {error, CSG})) -> {list(CSF), list(CSG)}.
|
||||
partition(Results) ->
|
||||
partition_loop(Results, [], []).
|
||||
|
||||
-file("src/gleam/result.gleam", 389).
|
||||
?DOC(
|
||||
" Replace the value within a result\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" replace(Ok(1), Nil)\n"
|
||||
" // -> Ok(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" replace(Error(1), Nil)\n"
|
||||
" // -> Error(1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec replace({ok, any()} | {error, CSV}, CSY) -> {ok, CSY} | {error, CSV}.
|
||||
replace(Result, Value) ->
|
||||
case Result of
|
||||
{ok, _} ->
|
||||
{ok, Value};
|
||||
|
||||
{error, Error} ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 410).
|
||||
?DOC(
|
||||
" Replace the error within a result\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" replace_error(Error(1), Nil)\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" replace_error(Ok(1), Nil)\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec replace_error({ok, CTB} | {error, any()}, CTF) -> {ok, CTB} | {error, CTF}.
|
||||
replace_error(Result, Error) ->
|
||||
case Result of
|
||||
{ok, X} ->
|
||||
{ok, X};
|
||||
|
||||
{error, _} ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
-file("src/gleam/result.gleam", 426).
|
||||
?DOC(
|
||||
" Given a list of results, returns only the values inside `Ok`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" values([Ok(1), Error(\"a\"), Ok(3)])\n"
|
||||
" // -> [1, 3]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec values(list({ok, CTI} | {error, any()})) -> list(CTI).
|
||||
values(Results) ->
|
||||
gleam@list:filter_map(Results, fun(Result) -> Result end).
|
||||
|
||||
-file("src/gleam/result.gleam", 459).
|
||||
?DOC(
|
||||
" Updates a value held within the `Error` of a result by calling a given function\n"
|
||||
" on it, where the given function also returns a result. The two results are\n"
|
||||
" then merged together into one result.\n"
|
||||
"\n"
|
||||
" If the result is an `Ok` rather than `Error` the function is not called and the\n"
|
||||
" result stays the same.\n"
|
||||
"\n"
|
||||
" This function is useful for chaining together computations that may fail\n"
|
||||
" and trying to recover from possible errors.\n"
|
||||
"\n"
|
||||
" If you do not need access to the initial error value, use `result.lazy_or`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" Ok(1) |> try_recover(with: fn(_) { Error(\"failed to recover\") })\n"
|
||||
" // -> Ok(1)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" Error(1) |> try_recover(with: fn(error) { Ok(error + 1) })\n"
|
||||
" // -> Ok(2)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" Error(1) |> try_recover(with: fn(error) { Error(\"failed to recover\") })\n"
|
||||
" // -> Error(\"failed to recover\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec try_recover(
|
||||
{ok, CTO} | {error, CTP},
|
||||
fun((CTP) -> {ok, CTO} | {error, CTS})
|
||||
) -> {ok, CTO} | {error, CTS}.
|
||||
try_recover(Result, Fun) ->
|
||||
case Result of
|
||||
{ok, Value} ->
|
||||
{ok, Value};
|
||||
|
||||
{error, Error} ->
|
||||
Fun(Error)
|
||||
end.
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache
Normal file
Binary file not shown.
Binary file not shown.
429
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.erl
Normal file
429
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.erl
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
-module(gleam@set).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/set.gleam").
|
||||
-export([new/0, size/1, is_empty/1, contains/2, delete/2, to_list/1, fold/3, filter/2, drop/2, take/2, intersection/2, difference/2, is_subset/2, is_disjoint/2, each/2, insert/2, from_list/1, map/2, union/2, symmetric_difference/2]).
|
||||
-export_type([set/1]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-opaque set(CYN) :: {set, gleam@dict:dict(CYN, list(nil))}.
|
||||
|
||||
-file("src/gleam/set.gleam", 32).
|
||||
?DOC(" Creates a new empty set.\n").
|
||||
-spec new() -> set(any()).
|
||||
new() ->
|
||||
{set, maps:new()}.
|
||||
|
||||
-file("src/gleam/set.gleam", 50).
|
||||
?DOC(
|
||||
" Gets the number of members in a set.\n"
|
||||
"\n"
|
||||
" This function runs in constant time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new()\n"
|
||||
" |> insert(1)\n"
|
||||
" |> insert(2)\n"
|
||||
" |> size\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec size(set(any())) -> integer().
|
||||
size(Set) ->
|
||||
maps:size(erlang:element(2, Set)).
|
||||
|
||||
-file("src/gleam/set.gleam", 68).
|
||||
?DOC(
|
||||
" Determines whether or not the set is empty.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> is_empty\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(1) |> is_empty\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_empty(set(any())) -> boolean().
|
||||
is_empty(Set) ->
|
||||
Set =:= new().
|
||||
|
||||
-file("src/gleam/set.gleam", 110).
|
||||
?DOC(
|
||||
" Checks whether a set contains a given member.\n"
|
||||
"\n"
|
||||
" This function runs in logarithmic time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new()\n"
|
||||
" |> insert(2)\n"
|
||||
" |> contains(2)\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new()\n"
|
||||
" |> insert(2)\n"
|
||||
" |> contains(1)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec contains(set(CYY), CYY) -> boolean().
|
||||
contains(Set, Member) ->
|
||||
_pipe = erlang:element(2, Set),
|
||||
_pipe@1 = gleam_stdlib:map_get(_pipe, Member),
|
||||
gleam@result:is_ok(_pipe@1).
|
||||
|
||||
-file("src/gleam/set.gleam", 131).
|
||||
?DOC(
|
||||
" Removes a member from a set. If the set does not contain the member then\n"
|
||||
" the set is returned unchanged.\n"
|
||||
"\n"
|
||||
" This function runs in logarithmic time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new()\n"
|
||||
" |> insert(2)\n"
|
||||
" |> delete(2)\n"
|
||||
" |> contains(1)\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec delete(set(CZA), CZA) -> set(CZA).
|
||||
delete(Set, Member) ->
|
||||
{set, gleam@dict:delete(erlang:element(2, Set), Member)}.
|
||||
|
||||
-file("src/gleam/set.gleam", 149).
|
||||
?DOC(
|
||||
" Converts the set into a list of the contained members.\n"
|
||||
"\n"
|
||||
" The list has no specific ordering, any unintentional ordering may change in\n"
|
||||
" future versions of Gleam or Erlang.\n"
|
||||
"\n"
|
||||
" This function runs in linear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new() |> insert(2) |> to_list\n"
|
||||
" // -> [2]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_list(set(CZD)) -> list(CZD).
|
||||
to_list(Set) ->
|
||||
maps:keys(erlang:element(2, Set)).
|
||||
|
||||
-file("src/gleam/set.gleam", 190).
|
||||
?DOC(
|
||||
" Combines all entries into a single value by calling a given function on each\n"
|
||||
" one.\n"
|
||||
"\n"
|
||||
" Sets are not ordered so the values are not returned in any specific order.\n"
|
||||
" Do not write code that relies on the order entries are used by this\n"
|
||||
" function as it may change in later versions of Gleam or Erlang.\n"
|
||||
"\n"
|
||||
" # Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([1, 3, 9])\n"
|
||||
" |> fold(0, fn(accumulator, member) { accumulator + member })\n"
|
||||
" // -> 13\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec fold(set(CZJ), CZL, fun((CZL, CZJ) -> CZL)) -> CZL.
|
||||
fold(Set, Initial, Reducer) ->
|
||||
gleam@dict:fold(
|
||||
erlang:element(2, Set),
|
||||
Initial,
|
||||
fun(A, K, _) -> Reducer(A, K) end
|
||||
).
|
||||
|
||||
-file("src/gleam/set.gleam", 214).
|
||||
?DOC(
|
||||
" Creates a new set from an existing set, minus any members that a given\n"
|
||||
" function returns `False` for.\n"
|
||||
"\n"
|
||||
" This function runs in loglinear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
"\n"
|
||||
" from_list([1, 4, 6, 3, 675, 44, 67])\n"
|
||||
" |> filter(keeping: int.is_even)\n"
|
||||
" |> to_list\n"
|
||||
" // -> [4, 6, 44]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec filter(set(CZM), fun((CZM) -> boolean())) -> set(CZM).
|
||||
filter(Set, Predicate) ->
|
||||
{set,
|
||||
gleam@dict:filter(erlang:element(2, Set), fun(M, _) -> Predicate(M) end)}.
|
||||
|
||||
-file("src/gleam/set.gleam", 249).
|
||||
?DOC(
|
||||
" Creates a new set from a given set with all the same entries except any\n"
|
||||
" entry found on the given list.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([1, 2, 3, 4])\n"
|
||||
" |> drop([1, 3])\n"
|
||||
" |> to_list\n"
|
||||
" // -> [2, 4]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec drop(set(CZT), list(CZT)) -> set(CZT).
|
||||
drop(Set, Disallowed) ->
|
||||
gleam@list:fold(Disallowed, Set, fun delete/2).
|
||||
|
||||
-file("src/gleam/set.gleam", 267).
|
||||
?DOC(
|
||||
" Creates a new set from a given set, only including any members which are in\n"
|
||||
" a given list.\n"
|
||||
"\n"
|
||||
" This function runs in loglinear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([1, 2, 3])\n"
|
||||
" |> take([1, 3, 5])\n"
|
||||
" |> to_list\n"
|
||||
" // -> [1, 3]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec take(set(CZX), list(CZX)) -> set(CZX).
|
||||
take(Set, Desired) ->
|
||||
{set, gleam@dict:take(erlang:element(2, Set), Desired)}.
|
||||
|
||||
-file("src/gleam/set.gleam", 287).
|
||||
-spec order(set(DAF), set(DAF)) -> {set(DAF), set(DAF)}.
|
||||
order(First, Second) ->
|
||||
case maps:size(erlang:element(2, First)) > maps:size(
|
||||
erlang:element(2, Second)
|
||||
) of
|
||||
true ->
|
||||
{First, Second};
|
||||
|
||||
false ->
|
||||
{Second, First}
|
||||
end.
|
||||
|
||||
-file("src/gleam/set.gleam", 305).
|
||||
?DOC(
|
||||
" Creates a new set that contains members that are present in both given sets.\n"
|
||||
"\n"
|
||||
" This function runs in loglinear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" intersection(from_list([1, 2]), from_list([2, 3])) |> to_list\n"
|
||||
" // -> [2]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec intersection(set(DAK), set(DAK)) -> set(DAK).
|
||||
intersection(First, Second) ->
|
||||
{Larger, Smaller} = order(First, Second),
|
||||
take(Larger, to_list(Smaller)).
|
||||
|
||||
-file("src/gleam/set.gleam", 323).
|
||||
?DOC(
|
||||
" Creates a new set that contains members that are present in the first set\n"
|
||||
" but not the second.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list\n"
|
||||
" // -> [1]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec difference(set(DAO), set(DAO)) -> set(DAO).
|
||||
difference(First, Second) ->
|
||||
drop(First, to_list(Second)).
|
||||
|
||||
-file("src/gleam/set.gleam", 344).
|
||||
?DOC(
|
||||
" Determines if a set is fully contained by another.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_subset(from_list([1]), from_list([1, 2]))\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_subset(from_list([1, 2, 3]), from_list([3, 4, 5]))\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_subset(set(DAS), set(DAS)) -> boolean().
|
||||
is_subset(First, Second) ->
|
||||
intersection(First, Second) =:= First.
|
||||
|
||||
-file("src/gleam/set.gleam", 362).
|
||||
?DOC(
|
||||
" Determines if two sets contain no common members\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6]))\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5]))\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_disjoint(set(DAV), set(DAV)) -> boolean().
|
||||
is_disjoint(First, Second) ->
|
||||
intersection(First, Second) =:= new().
|
||||
|
||||
-file("src/gleam/set.gleam", 402).
|
||||
?DOC(
|
||||
" Calls a function for each member in a set, discarding the return\n"
|
||||
" value.\n"
|
||||
"\n"
|
||||
" Useful for producing a side effect for every item of a set.\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let set = from_list([\"apple\", \"banana\", \"cherry\"])\n"
|
||||
"\n"
|
||||
" each(set, io.println)\n"
|
||||
" // -> Nil\n"
|
||||
" // apple\n"
|
||||
" // banana\n"
|
||||
" // cherry\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" The order of elements in the iteration is an implementation detail that\n"
|
||||
" should not be relied upon.\n"
|
||||
).
|
||||
-spec each(set(DBC), fun((DBC) -> any())) -> nil.
|
||||
each(Set, Fun) ->
|
||||
fold(
|
||||
Set,
|
||||
nil,
|
||||
fun(Nil, Member) ->
|
||||
Fun(Member),
|
||||
Nil
|
||||
end
|
||||
).
|
||||
|
||||
-file("src/gleam/set.gleam", 86).
|
||||
?DOC(
|
||||
" Inserts an member into the set.\n"
|
||||
"\n"
|
||||
" This function runs in logarithmic time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" new()\n"
|
||||
" |> insert(1)\n"
|
||||
" |> insert(2)\n"
|
||||
" |> size\n"
|
||||
" // -> 2\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec insert(set(CYV), CYV) -> set(CYV).
|
||||
insert(Set, Member) ->
|
||||
{set, gleam@dict:insert(erlang:element(2, Set), Member, [])}.
|
||||
|
||||
-file("src/gleam/set.gleam", 167).
|
||||
?DOC(
|
||||
" Creates a new set of the members in a given list.\n"
|
||||
"\n"
|
||||
" This function runs in loglinear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" import gleam/int\n"
|
||||
" import gleam/list\n"
|
||||
"\n"
|
||||
" [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort(by: int.compare)\n"
|
||||
" // -> [1, 2, 3, 4]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec from_list(list(CZG)) -> set(CZG).
|
||||
from_list(Members) ->
|
||||
Dict = gleam@list:fold(
|
||||
Members,
|
||||
maps:new(),
|
||||
fun(M, K) -> gleam@dict:insert(M, K, []) end
|
||||
),
|
||||
{set, Dict}.
|
||||
|
||||
-file("src/gleam/set.gleam", 232).
|
||||
?DOC(
|
||||
" Creates a new set from a given set with the result of applying the given\n"
|
||||
" function to each member.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_list([1, 2, 3, 4])\n"
|
||||
" |> map(with: fn(x) { x * 2 })\n"
|
||||
" |> to_list\n"
|
||||
" // -> [2, 4, 6, 8]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec map(set(CZP), fun((CZP) -> CZR)) -> set(CZR).
|
||||
map(Set, Fun) ->
|
||||
fold(Set, new(), fun(Acc, Member) -> insert(Acc, Fun(Member)) end).
|
||||
|
||||
-file("src/gleam/set.gleam", 282).
|
||||
?DOC(
|
||||
" Creates a new set that contains all members of both given sets.\n"
|
||||
"\n"
|
||||
" This function runs in loglinear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" union(from_list([1, 2]), from_list([2, 3])) |> to_list\n"
|
||||
" // -> [1, 2, 3]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec union(set(DAB), set(DAB)) -> set(DAB).
|
||||
union(First, Second) ->
|
||||
{Larger, Smaller} = order(First, Second),
|
||||
fold(Smaller, Larger, fun insert/2).
|
||||
|
||||
-file("src/gleam/set.gleam", 374).
|
||||
?DOC(
|
||||
" Creates a new set that contains members that are present in either set, but\n"
|
||||
" not both.\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" symmetric_difference(from_list([1, 2, 3]), from_list([3, 4])) |> to_list\n"
|
||||
" // -> [1, 2, 4]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec symmetric_difference(set(DAY), set(DAY)) -> set(DAY).
|
||||
symmetric_difference(First, Second) ->
|
||||
difference(union(First, Second), intersection(First, Second)).
|
||||
Binary file not shown.
Binary file not shown.
957
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.erl
Normal file
957
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.erl
Normal file
|
|
@ -0,0 +1,957 @@
|
|||
-module(gleam@string).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/string.gleam").
|
||||
-export([is_empty/1, length/1, reverse/1, replace/3, lowercase/1, uppercase/1, compare/2, slice/3, crop/2, drop_end/2, contains/2, starts_with/2, ends_with/2, split_once/2, append/2, concat/1, repeat/2, join/2, pad_start/3, pad_end/3, trim_start/1, trim_end/1, trim/1, pop_grapheme/1, drop_start/2, to_graphemes/1, split/2, to_utf_codepoints/1, from_utf_codepoints/1, utf_codepoint/1, utf_codepoint_to_int/1, to_option/1, first/1, last/1, capitalise/1, inspect/1, byte_size/1]).
|
||||
-export_type([direction/0]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
?MODULEDOC(
|
||||
" Strings in Gleam are UTF-8 binaries. They can be written in your code as\n"
|
||||
" text surrounded by `\"double quotes\"`.\n"
|
||||
).
|
||||
|
||||
-type direction() :: leading | trailing.
|
||||
|
||||
-file("src/gleam/string.gleam", 23).
|
||||
?DOC(
|
||||
" Determines if a `String` is empty.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_empty(\"\")\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_empty(\"the world\")\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_empty(binary()) -> boolean().
|
||||
is_empty(Str) ->
|
||||
Str =:= <<""/utf8>>.
|
||||
|
||||
-file("src/gleam/string.gleam", 51).
|
||||
?DOC(
|
||||
" Gets the number of grapheme clusters in a given `String`.\n"
|
||||
"\n"
|
||||
" This function has to iterate across the whole string to count the number of\n"
|
||||
" graphemes, so it runs in linear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" length(\"Gleam\")\n"
|
||||
" // -> 5\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" length(\"ß↑e̊\")\n"
|
||||
" // -> 3\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" length(\"\")\n"
|
||||
" // -> 0\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec length(binary()) -> integer().
|
||||
length(String) ->
|
||||
string:length(String).
|
||||
|
||||
-file("src/gleam/string.gleam", 65).
|
||||
?DOC(
|
||||
" Reverses a `String`.\n"
|
||||
"\n"
|
||||
" This function has to iterate across the whole `String` so it runs in linear\n"
|
||||
" time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" reverse(\"stressed\")\n"
|
||||
" // -> \"desserts\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec reverse(binary()) -> binary().
|
||||
reverse(String) ->
|
||||
_pipe = String,
|
||||
_pipe@1 = gleam_stdlib:identity(_pipe),
|
||||
_pipe@2 = string:reverse(_pipe@1),
|
||||
unicode:characters_to_binary(_pipe@2).
|
||||
|
||||
-file("src/gleam/string.gleam", 86).
|
||||
?DOC(
|
||||
" Creates a new `String` by replacing all occurrences of a given substring.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" replace(\"www.example.com\", each: \".\", with: \"-\")\n"
|
||||
" // -> \"www-example-com\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" replace(\"a,b,c,d,e\", each: \",\", with: \"/\")\n"
|
||||
" // -> \"a/b/c/d/e\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec replace(binary(), binary(), binary()) -> binary().
|
||||
replace(String, Pattern, Substitute) ->
|
||||
_pipe = String,
|
||||
_pipe@1 = gleam_stdlib:identity(_pipe),
|
||||
_pipe@2 = gleam_stdlib:string_replace(_pipe@1, Pattern, Substitute),
|
||||
unicode:characters_to_binary(_pipe@2).
|
||||
|
||||
-file("src/gleam/string.gleam", 111).
|
||||
?DOC(
|
||||
" Creates a new `String` with all the graphemes in the input `String` converted to\n"
|
||||
" lowercase.\n"
|
||||
"\n"
|
||||
" Useful for case-insensitive comparisons.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" lowercase(\"X-FILES\")\n"
|
||||
" // -> \"x-files\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec lowercase(binary()) -> binary().
|
||||
lowercase(String) ->
|
||||
string:lowercase(String).
|
||||
|
||||
-file("src/gleam/string.gleam", 127).
|
||||
?DOC(
|
||||
" Creates a new `String` with all the graphemes in the input `String` converted to\n"
|
||||
" uppercase.\n"
|
||||
"\n"
|
||||
" Useful for case-insensitive comparisons and VIRTUAL YELLING.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" uppercase(\"skinner\")\n"
|
||||
" // -> \"SKINNER\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec uppercase(binary()) -> binary().
|
||||
uppercase(String) ->
|
||||
string:uppercase(String).
|
||||
|
||||
-file("src/gleam/string.gleam", 145).
|
||||
?DOC(
|
||||
" Compares two `String`s to see which is \"larger\" by comparing their graphemes.\n"
|
||||
"\n"
|
||||
" This does not compare the size or length of the given `String`s.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(\"Anthony\", \"Anthony\")\n"
|
||||
" // -> order.Eq\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" compare(\"A\", \"B\")\n"
|
||||
" // -> order.Lt\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec compare(binary(), binary()) -> gleam@order:order().
|
||||
compare(A, B) ->
|
||||
case A =:= B of
|
||||
true ->
|
||||
eq;
|
||||
|
||||
_ ->
|
||||
case gleam_stdlib:less_than(A, B) of
|
||||
true ->
|
||||
lt;
|
||||
|
||||
false ->
|
||||
gt
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 190).
|
||||
?DOC(
|
||||
" Takes a substring given a start grapheme index and a length. Negative indexes\n"
|
||||
" are taken starting from the *end* of the list.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" slice(from: \"gleam\", at_index: 1, length: 2)\n"
|
||||
" // -> \"le\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" slice(from: \"gleam\", at_index: 1, length: 10)\n"
|
||||
" // -> \"leam\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" slice(from: \"gleam\", at_index: 10, length: 3)\n"
|
||||
" // -> \"\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" slice(from: \"gleam\", at_index: -2, length: 2)\n"
|
||||
" // -> \"am\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" slice(from: \"gleam\", at_index: -12, length: 2)\n"
|
||||
" // -> \"\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec slice(binary(), integer(), integer()) -> binary().
|
||||
slice(String, Idx, Len) ->
|
||||
case Len < 0 of
|
||||
true ->
|
||||
<<""/utf8>>;
|
||||
|
||||
false ->
|
||||
case Idx < 0 of
|
||||
true ->
|
||||
Translated_idx = string:length(String) + Idx,
|
||||
case Translated_idx < 0 of
|
||||
true ->
|
||||
<<""/utf8>>;
|
||||
|
||||
false ->
|
||||
gleam_stdlib:slice(String, Translated_idx, Len)
|
||||
end;
|
||||
|
||||
false ->
|
||||
gleam_stdlib:slice(String, Idx, Len)
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 223).
|
||||
?DOC(
|
||||
" Drops contents of the first `String` that occur before the second `String`.\n"
|
||||
" If the `from` string does not contain the `before` string, `from` is returned unchanged.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" crop(from: \"The Lone Gunmen\", before: \"Lone\")\n"
|
||||
" // -> \"Lone Gunmen\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec crop(binary(), binary()) -> binary().
|
||||
crop(String, Substring) ->
|
||||
gleam_stdlib:crop_string(String, Substring).
|
||||
|
||||
-file("src/gleam/string.gleam", 254).
|
||||
?DOC(
|
||||
" Drops *n* graphemes from the end of a `String`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" drop_end(from: \"Cigarette Smoking Man\", up_to: 2)\n"
|
||||
" // -> \"Cigarette Smoking M\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec drop_end(binary(), integer()) -> binary().
|
||||
drop_end(String, Num_graphemes) ->
|
||||
case Num_graphemes < 0 of
|
||||
true ->
|
||||
String;
|
||||
|
||||
false ->
|
||||
slice(String, 0, string:length(String) - Num_graphemes)
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 282).
|
||||
?DOC(
|
||||
" Checks if the first `String` contains the second.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" contains(does: \"theory\", contain: \"ory\")\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" contains(does: \"theory\", contain: \"the\")\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" contains(does: \"theory\", contain: \"THE\")\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec contains(binary(), binary()) -> boolean().
|
||||
contains(Haystack, Needle) ->
|
||||
gleam_stdlib:contains_string(Haystack, Needle).
|
||||
|
||||
-file("src/gleam/string.gleam", 295).
|
||||
?DOC(
|
||||
" Checks whether the first `String` starts with the second one.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" starts_with(\"theory\", \"ory\")\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec starts_with(binary(), binary()) -> boolean().
|
||||
starts_with(String, Prefix) ->
|
||||
gleam_stdlib:string_starts_with(String, Prefix).
|
||||
|
||||
-file("src/gleam/string.gleam", 308).
|
||||
?DOC(
|
||||
" Checks whether the first `String` ends with the second one.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" ends_with(\"theory\", \"ory\")\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec ends_with(binary(), binary()) -> boolean().
|
||||
ends_with(String, Suffix) ->
|
||||
gleam_stdlib:string_ends_with(String, Suffix).
|
||||
|
||||
-file("src/gleam/string.gleam", 347).
|
||||
?DOC(
|
||||
" Splits a `String` a single time on the given substring.\n"
|
||||
"\n"
|
||||
" Returns an `Error` if substring not present.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" split_once(\"home/gleam/desktop/\", on: \"/\")\n"
|
||||
" // -> Ok(#(\"home\", \"gleam/desktop/\"))\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" split_once(\"home/gleam/desktop/\", on: \"?\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} |
|
||||
{error, nil}.
|
||||
split_once(String, Substring) ->
|
||||
case string:split(String, Substring) of
|
||||
[First, Rest] ->
|
||||
{ok, {First, Rest}};
|
||||
|
||||
_ ->
|
||||
{error, nil}
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 378).
|
||||
?DOC(
|
||||
" Creates a new `String` by joining two `String`s together.\n"
|
||||
"\n"
|
||||
" This function typically copies both `String`s and runs in linear time, but\n"
|
||||
" the exact behaviour will depend on how the runtime you are using optimises\n"
|
||||
" your code. Benchmark and profile your code if you need to understand its\n"
|
||||
" performance better.\n"
|
||||
"\n"
|
||||
" If you are joining together large string and want to avoid copying any data\n"
|
||||
" you may want to investigate using the [`string_tree`](../gleam/string_tree.html)\n"
|
||||
" module.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" append(to: \"butter\", suffix: \"fly\")\n"
|
||||
" // -> \"butterfly\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec append(binary(), binary()) -> binary().
|
||||
append(First, Second) ->
|
||||
<<First/binary, Second/binary>>.
|
||||
|
||||
-file("src/gleam/string.gleam", 400).
|
||||
-spec concat_loop(list(binary()), binary()) -> binary().
|
||||
concat_loop(Strings, Accumulator) ->
|
||||
case Strings of
|
||||
[String | Strings@1] ->
|
||||
concat_loop(Strings@1, <<Accumulator/binary, String/binary>>);
|
||||
|
||||
[] ->
|
||||
Accumulator
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 396).
|
||||
?DOC(
|
||||
" Creates a new `String` by joining many `String`s together.\n"
|
||||
"\n"
|
||||
" This function copies both `String`s and runs in linear time. If you find\n"
|
||||
" yourself joining `String`s frequently consider using the [`string_tree`](../gleam/string_tree.html)\n"
|
||||
" module as it can append `String`s much faster!\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" concat([\"never\", \"the\", \"less\"])\n"
|
||||
" // -> \"nevertheless\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec concat(list(binary())) -> binary().
|
||||
concat(Strings) ->
|
||||
erlang:list_to_binary(Strings).
|
||||
|
||||
-file("src/gleam/string.gleam", 422).
|
||||
-spec repeat_loop(binary(), integer(), binary()) -> binary().
|
||||
repeat_loop(String, Times, Acc) ->
|
||||
case Times =< 0 of
|
||||
true ->
|
||||
Acc;
|
||||
|
||||
false ->
|
||||
repeat_loop(String, Times - 1, <<Acc/binary, String/binary>>)
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 418).
|
||||
?DOC(
|
||||
" Creates a new `String` by repeating a `String` a given number of times.\n"
|
||||
"\n"
|
||||
" This function runs in linear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" repeat(\"ha\", times: 3)\n"
|
||||
" // -> \"hahaha\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec repeat(binary(), integer()) -> binary().
|
||||
repeat(String, Times) ->
|
||||
repeat_loop(String, Times, <<""/utf8>>).
|
||||
|
||||
-file("src/gleam/string.gleam", 447).
|
||||
-spec join_loop(list(binary()), binary(), binary()) -> binary().
|
||||
join_loop(Strings, Separator, Accumulator) ->
|
||||
case Strings of
|
||||
[] ->
|
||||
Accumulator;
|
||||
|
||||
[String | Strings@1] ->
|
||||
join_loop(
|
||||
Strings@1,
|
||||
Separator,
|
||||
<<<<Accumulator/binary, Separator/binary>>/binary,
|
||||
String/binary>>
|
||||
)
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 440).
|
||||
?DOC(
|
||||
" Joins many `String`s together with a given separator.\n"
|
||||
"\n"
|
||||
" This function runs in linear time.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" join([\"home\",\"evan\",\"Desktop\"], with: \"/\")\n"
|
||||
" // -> \"home/evan/Desktop\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec join(list(binary()), binary()) -> binary().
|
||||
join(Strings, Separator) ->
|
||||
case Strings of
|
||||
[] ->
|
||||
<<""/utf8>>;
|
||||
|
||||
[First | Rest] ->
|
||||
join_loop(Rest, Separator, First)
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 525).
|
||||
-spec padding(integer(), binary()) -> binary().
|
||||
padding(Size, Pad_string) ->
|
||||
Pad_string_length = string:length(Pad_string),
|
||||
Num_pads = case Pad_string_length of
|
||||
0 -> 0;
|
||||
Gleam@denominator -> Size div Gleam@denominator
|
||||
end,
|
||||
Extra = case Pad_string_length of
|
||||
0 -> 0;
|
||||
Gleam@denominator@1 -> Size rem Gleam@denominator@1
|
||||
end,
|
||||
<<(repeat(Pad_string, Num_pads))/binary,
|
||||
(slice(Pad_string, 0, Extra))/binary>>.
|
||||
|
||||
-file("src/gleam/string.gleam", 478).
|
||||
?DOC(
|
||||
" Pads the start of a `String` until it has a given length.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pad_start(\"121\", to: 5, with: \".\")\n"
|
||||
" // -> \"..121\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pad_start(\"121\", to: 3, with: \".\")\n"
|
||||
" // -> \"121\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pad_start(\"121\", to: 2, with: \".\")\n"
|
||||
" // -> \"121\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec pad_start(binary(), integer(), binary()) -> binary().
|
||||
pad_start(String, Desired_length, Pad_string) ->
|
||||
Current_length = string:length(String),
|
||||
To_pad_length = Desired_length - Current_length,
|
||||
case To_pad_length =< 0 of
|
||||
true ->
|
||||
String;
|
||||
|
||||
false ->
|
||||
<<(padding(To_pad_length, Pad_string))/binary, String/binary>>
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 511).
|
||||
?DOC(
|
||||
" Pads the end of a `String` until it has a given length.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pad_end(\"123\", to: 5, with: \".\")\n"
|
||||
" // -> \"123..\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pad_end(\"123\", to: 3, with: \".\")\n"
|
||||
" // -> \"123\"\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pad_end(\"123\", to: 2, with: \".\")\n"
|
||||
" // -> \"123\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec pad_end(binary(), integer(), binary()) -> binary().
|
||||
pad_end(String, Desired_length, Pad_string) ->
|
||||
Current_length = string:length(String),
|
||||
To_pad_length = Desired_length - Current_length,
|
||||
case To_pad_length =< 0 of
|
||||
true ->
|
||||
String;
|
||||
|
||||
false ->
|
||||
<<String/binary, (padding(To_pad_length, Pad_string))/binary>>
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 569).
|
||||
?DOC(
|
||||
" Removes whitespace at the start of a `String`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" trim_start(\" hats \\n\")\n"
|
||||
" // -> \"hats \\n\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec trim_start(binary()) -> binary().
|
||||
trim_start(String) ->
|
||||
string:trim(String, leading).
|
||||
|
||||
-file("src/gleam/string.gleam", 583).
|
||||
?DOC(
|
||||
" Removes whitespace at the end of a `String`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" trim_end(\" hats \\n\")\n"
|
||||
" // -> \" hats\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec trim_end(binary()) -> binary().
|
||||
trim_end(String) ->
|
||||
string:trim(String, trailing).
|
||||
|
||||
-file("src/gleam/string.gleam", 547).
|
||||
?DOC(
|
||||
" Removes whitespace on both sides of a `String`.\n"
|
||||
"\n"
|
||||
" Whitespace in this function is the set of nonbreakable whitespace\n"
|
||||
" codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1].\n"
|
||||
"\n"
|
||||
" [1]: https://unicode.org/reports/tr31/\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" trim(\" hats \\n\")\n"
|
||||
" // -> \"hats\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec trim(binary()) -> binary().
|
||||
trim(String) ->
|
||||
_pipe = String,
|
||||
_pipe@1 = trim_start(_pipe),
|
||||
trim_end(_pipe@1).
|
||||
|
||||
-file("src/gleam/string.gleam", 610).
|
||||
?DOC(
|
||||
" Splits a non-empty `String` into its first element (head) and rest (tail).\n"
|
||||
" This lets you pattern match on `String`s exactly as you would with lists.\n"
|
||||
"\n"
|
||||
" ## Performance\n"
|
||||
"\n"
|
||||
" There is a notable overhead to using this function, so you may not want to\n"
|
||||
" use it in a tight loop. If you wish to efficiently parse a string you may\n"
|
||||
" want to use alternatives such as the [splitter package](https://hex.pm/packages/splitter).\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pop_grapheme(\"gleam\")\n"
|
||||
" // -> Ok(#(\"g\", \"leam\"))\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" pop_grapheme(\"\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec pop_grapheme(binary()) -> {ok, {binary(), binary()}} | {error, nil}.
|
||||
pop_grapheme(String) ->
|
||||
gleam_stdlib:string_pop_grapheme(String).
|
||||
|
||||
-file("src/gleam/string.gleam", 234).
|
||||
?DOC(
|
||||
" Drops *n* graphemes from the start of a `String`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" drop_start(from: \"The Lone Gunmen\", up_to: 2)\n"
|
||||
" // -> \"e Lone Gunmen\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec drop_start(binary(), integer()) -> binary().
|
||||
drop_start(String, Num_graphemes) ->
|
||||
case Num_graphemes > 0 of
|
||||
false ->
|
||||
String;
|
||||
|
||||
true ->
|
||||
case gleam_stdlib:string_pop_grapheme(String) of
|
||||
{ok, {_, String@1}} ->
|
||||
drop_start(String@1, Num_graphemes - 1);
|
||||
|
||||
{error, nil} ->
|
||||
String
|
||||
end
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 626).
|
||||
-spec to_graphemes_loop(binary(), list(binary())) -> list(binary()).
|
||||
to_graphemes_loop(String, Acc) ->
|
||||
case gleam_stdlib:string_pop_grapheme(String) of
|
||||
{ok, {Grapheme, Rest}} ->
|
||||
to_graphemes_loop(Rest, [Grapheme | Acc]);
|
||||
|
||||
{error, _} ->
|
||||
Acc
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 621).
|
||||
?DOC(
|
||||
" Converts a `String` to a list of\n"
|
||||
" [graphemes](https://en.wikipedia.org/wiki/Grapheme).\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_graphemes(\"abc\")\n"
|
||||
" // -> [\"a\", \"b\", \"c\"]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_graphemes(binary()) -> list(binary()).
|
||||
to_graphemes(String) ->
|
||||
_pipe = to_graphemes_loop(String, []),
|
||||
lists:reverse(_pipe).
|
||||
|
||||
-file("src/gleam/string.gleam", 319).
|
||||
?DOC(
|
||||
" Creates a list of `String`s by splitting a given string on a given substring.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" split(\"home/gleam/desktop/\", on: \"/\")\n"
|
||||
" // -> [\"home\", \"gleam\", \"desktop\", \"\"]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec split(binary(), binary()) -> list(binary()).
|
||||
split(X, Substring) ->
|
||||
case Substring of
|
||||
<<""/utf8>> ->
|
||||
to_graphemes(X);
|
||||
|
||||
_ ->
|
||||
_pipe = X,
|
||||
_pipe@1 = gleam_stdlib:identity(_pipe),
|
||||
_pipe@2 = gleam@string_tree:split(_pipe@1, Substring),
|
||||
gleam@list:map(_pipe@2, fun unicode:characters_to_binary/1)
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 673).
|
||||
-spec to_utf_codepoints_loop(bitstring(), list(integer())) -> list(integer()).
|
||||
to_utf_codepoints_loop(Bit_array, Acc) ->
|
||||
case Bit_array of
|
||||
<<First/utf8, Rest/binary>> ->
|
||||
to_utf_codepoints_loop(Rest, [First | Acc]);
|
||||
|
||||
_ ->
|
||||
lists:reverse(Acc)
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 668).
|
||||
-spec do_to_utf_codepoints(binary()) -> list(integer()).
|
||||
do_to_utf_codepoints(String) ->
|
||||
to_utf_codepoints_loop(<<String/binary>>, []).
|
||||
|
||||
-file("src/gleam/string.gleam", 663).
|
||||
?DOC(
|
||||
" Converts a `String` to a `List` of `UtfCodepoint`.\n"
|
||||
"\n"
|
||||
" See <https://en.wikipedia.org/wiki/Code_point> and\n"
|
||||
" <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> for an\n"
|
||||
" explanation on code points.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" \"a\" |> to_utf_codepoints\n"
|
||||
" // -> [UtfCodepoint(97)]\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" // Semantically the same as:\n"
|
||||
" // [\"🏳\", \"️\", \"\", \"🌈\"] or:\n"
|
||||
" // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow]\n"
|
||||
" \"🏳️🌈\" |> to_utf_codepoints\n"
|
||||
" // -> [\n"
|
||||
" // UtfCodepoint(127987),\n"
|
||||
" // UtfCodepoint(65039),\n"
|
||||
" // UtfCodepoint(8205),\n"
|
||||
" // UtfCodepoint(127752),\n"
|
||||
" // ]\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_utf_codepoints(binary()) -> list(integer()).
|
||||
to_utf_codepoints(String) ->
|
||||
do_to_utf_codepoints(String).
|
||||
|
||||
-file("src/gleam/string.gleam", 713).
|
||||
?DOC(
|
||||
" Converts a `List` of `UtfCodepoint`s to a `String`.\n"
|
||||
"\n"
|
||||
" See <https://en.wikipedia.org/wiki/Code_point> and\n"
|
||||
" <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> for an\n"
|
||||
" explanation on code points.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let assert Ok(a) = utf_codepoint(97)\n"
|
||||
" let assert Ok(b) = utf_codepoint(98)\n"
|
||||
" let assert Ok(c) = utf_codepoint(99)\n"
|
||||
" from_utf_codepoints([a, b, c])\n"
|
||||
" // -> \"abc\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec from_utf_codepoints(list(integer())) -> binary().
|
||||
from_utf_codepoints(Utf_codepoints) ->
|
||||
gleam_stdlib:utf_codepoint_list_to_string(Utf_codepoints).
|
||||
|
||||
-file("src/gleam/string.gleam", 719).
|
||||
?DOC(
|
||||
" Converts an integer to a `UtfCodepoint`.\n"
|
||||
"\n"
|
||||
" Returns an `Error` if the integer does not represent a valid UTF codepoint.\n"
|
||||
).
|
||||
-spec utf_codepoint(integer()) -> {ok, integer()} | {error, nil}.
|
||||
utf_codepoint(Value) ->
|
||||
case Value of
|
||||
I when I > 1114111 ->
|
||||
{error, nil};
|
||||
|
||||
I@1 when (I@1 >= 55296) andalso (I@1 =< 57343) ->
|
||||
{error, nil};
|
||||
|
||||
I@2 when I@2 < 0 ->
|
||||
{error, nil};
|
||||
|
||||
I@3 ->
|
||||
{ok, gleam_stdlib:identity(I@3)}
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 740).
|
||||
?DOC(
|
||||
" Converts an UtfCodepoint to its ordinal code point value.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" let assert [utf_codepoint, ..] = to_utf_codepoints(\"💜\")\n"
|
||||
" utf_codepoint_to_int(utf_codepoint)\n"
|
||||
" // -> 128156\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec utf_codepoint_to_int(integer()) -> integer().
|
||||
utf_codepoint_to_int(Cp) ->
|
||||
gleam_stdlib:identity(Cp).
|
||||
|
||||
-file("src/gleam/string.gleam", 757).
|
||||
?DOC(
|
||||
" Converts a `String` into `Option(String)` where an empty `String` becomes\n"
|
||||
" `None`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_option(\"\")\n"
|
||||
" // -> None\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" to_option(\"hats\")\n"
|
||||
" // -> Some(\"hats\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec to_option(binary()) -> gleam@option:option(binary()).
|
||||
to_option(String) ->
|
||||
case String of
|
||||
<<""/utf8>> ->
|
||||
none;
|
||||
|
||||
_ ->
|
||||
{some, String}
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 780).
|
||||
?DOC(
|
||||
" Returns the first grapheme cluster in a given `String` and wraps it in a\n"
|
||||
" `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.\n"
|
||||
" Otherwise, it returns `Ok(String)`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" first(\"\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" first(\"icecream\")\n"
|
||||
" // -> Ok(\"i\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec first(binary()) -> {ok, binary()} | {error, nil}.
|
||||
first(String) ->
|
||||
case gleam_stdlib:string_pop_grapheme(String) of
|
||||
{ok, {First, _}} ->
|
||||
{ok, First};
|
||||
|
||||
{error, E} ->
|
||||
{error, E}
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 803).
|
||||
?DOC(
|
||||
" Returns the last grapheme cluster in a given `String` and wraps it in a\n"
|
||||
" `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.\n"
|
||||
" Otherwise, it returns `Ok(String)`.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" last(\"\")\n"
|
||||
" // -> Error(Nil)\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" last(\"icecream\")\n"
|
||||
" // -> Ok(\"m\")\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec last(binary()) -> {ok, binary()} | {error, nil}.
|
||||
last(String) ->
|
||||
case gleam_stdlib:string_pop_grapheme(String) of
|
||||
{ok, {First, <<""/utf8>>}} ->
|
||||
{ok, First};
|
||||
|
||||
{ok, {_, Rest}} ->
|
||||
{ok, slice(Rest, -1, 1)};
|
||||
|
||||
{error, E} ->
|
||||
{error, E}
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 821).
|
||||
?DOC(
|
||||
" Creates a new `String` with the first grapheme in the input `String`\n"
|
||||
" converted to uppercase and the remaining graphemes to lowercase.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" capitalise(\"mamouna\")\n"
|
||||
" // -> \"Mamouna\"\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec capitalise(binary()) -> binary().
|
||||
capitalise(String) ->
|
||||
case gleam_stdlib:string_pop_grapheme(String) of
|
||||
{ok, {First, Rest}} ->
|
||||
append(string:uppercase(First), string:lowercase(Rest));
|
||||
|
||||
{error, _} ->
|
||||
<<""/utf8>>
|
||||
end.
|
||||
|
||||
-file("src/gleam/string.gleam", 830).
|
||||
?DOC(" Returns a `String` representation of a term in Gleam syntax.\n").
|
||||
-spec inspect(any()) -> binary().
|
||||
inspect(Term) ->
|
||||
_pipe = gleam_stdlib:inspect(Term),
|
||||
unicode:characters_to_binary(_pipe).
|
||||
|
||||
-file("src/gleam/string.gleam", 853).
|
||||
?DOC(
|
||||
" Returns the number of bytes in a `String`.\n"
|
||||
"\n"
|
||||
" This function runs in constant time on Erlang and in linear time on\n"
|
||||
" JavaScript.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" byte_size(\"🏳️⚧️🏳️🌈👩🏾❤️👨🏻\")\n"
|
||||
" // -> 58\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec byte_size(binary()) -> integer().
|
||||
byte_size(String) ->
|
||||
erlang:byte_size(String).
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,207 @@
|
|||
-module(gleam@string_tree).
|
||||
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
|
||||
-define(FILEPATH, "src/gleam/string_tree.gleam").
|
||||
-export([append_tree/2, prepend_tree/2, from_strings/1, new/0, concat/1, from_string/1, prepend/2, append/2, to_string/1, byte_size/1, join/2, lowercase/1, uppercase/1, reverse/1, split/2, replace/3, is_equal/2, is_empty/1]).
|
||||
-export_type([string_tree/0, direction/0]).
|
||||
|
||||
-if(?OTP_RELEASE >= 27).
|
||||
-define(MODULEDOC(Str), -moduledoc(Str)).
|
||||
-define(DOC(Str), -doc(Str)).
|
||||
-else.
|
||||
-define(MODULEDOC(Str), -compile([])).
|
||||
-define(DOC(Str), -compile([])).
|
||||
-endif.
|
||||
|
||||
-type string_tree() :: any().
|
||||
|
||||
-type direction() :: all.
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 61).
|
||||
?DOC(
|
||||
" Appends some `StringTree` onto the end of another.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec append_tree(string_tree(), string_tree()) -> string_tree().
|
||||
append_tree(Tree, Suffix) ->
|
||||
gleam_stdlib:iodata_append(Tree, Suffix).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 48).
|
||||
?DOC(
|
||||
" Prepends some `StringTree` onto the start of another.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec prepend_tree(string_tree(), string_tree()) -> string_tree().
|
||||
prepend_tree(Tree, Prefix) ->
|
||||
gleam_stdlib:iodata_append(Prefix, Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 69).
|
||||
?DOC(
|
||||
" Converts a list of strings into a `StringTree`.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec from_strings(list(binary())) -> string_tree().
|
||||
from_strings(Strings) ->
|
||||
gleam_stdlib:identity(Strings).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 24).
|
||||
?DOC(
|
||||
" Create an empty `StringTree`. Useful as the start of a pipe chaining many\n"
|
||||
" trees together.\n"
|
||||
).
|
||||
-spec new() -> string_tree().
|
||||
new() ->
|
||||
gleam_stdlib:identity([]).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 77).
|
||||
?DOC(
|
||||
" Joins a list of trees into a single tree.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec concat(list(string_tree())) -> string_tree().
|
||||
concat(Trees) ->
|
||||
gleam_stdlib:identity(Trees).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 85).
|
||||
?DOC(
|
||||
" Converts a string into a `StringTree`.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec from_string(binary()) -> string_tree().
|
||||
from_string(String) ->
|
||||
gleam_stdlib:identity(String).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 32).
|
||||
?DOC(
|
||||
" Prepends a `String` onto the start of some `StringTree`.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec prepend(string_tree(), binary()) -> string_tree().
|
||||
prepend(Tree, Prefix) ->
|
||||
gleam_stdlib:iodata_append(gleam_stdlib:identity(Prefix), Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 40).
|
||||
?DOC(
|
||||
" Appends a `String` onto the end of some `StringTree`.\n"
|
||||
"\n"
|
||||
" Runs in constant time.\n"
|
||||
).
|
||||
-spec append(string_tree(), binary()) -> string_tree().
|
||||
append(Tree, Second) ->
|
||||
gleam_stdlib:iodata_append(Tree, gleam_stdlib:identity(Second)).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 94).
|
||||
?DOC(
|
||||
" Turns a `StringTree` into a `String`\n"
|
||||
"\n"
|
||||
" This function is implemented natively by the virtual machine and is highly\n"
|
||||
" optimised.\n"
|
||||
).
|
||||
-spec to_string(string_tree()) -> binary().
|
||||
to_string(Tree) ->
|
||||
unicode:characters_to_binary(Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 100).
|
||||
?DOC(" Returns the size of the `StringTree` in bytes.\n").
|
||||
-spec byte_size(string_tree()) -> integer().
|
||||
byte_size(Tree) ->
|
||||
erlang:iolist_size(Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 104).
|
||||
?DOC(" Joins the given trees into a new tree separated with the given string.\n").
|
||||
-spec join(list(string_tree()), binary()) -> string_tree().
|
||||
join(Trees, Sep) ->
|
||||
_pipe = Trees,
|
||||
_pipe@1 = gleam@list:intersperse(_pipe, gleam_stdlib:identity(Sep)),
|
||||
gleam_stdlib:identity(_pipe@1).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 115).
|
||||
?DOC(
|
||||
" Converts a `StringTree` to a new one where the contents have been\n"
|
||||
" lowercased.\n"
|
||||
).
|
||||
-spec lowercase(string_tree()) -> string_tree().
|
||||
lowercase(Tree) ->
|
||||
string:lowercase(Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 122).
|
||||
?DOC(
|
||||
" Converts a `StringTree` to a new one where the contents have been\n"
|
||||
" uppercased.\n"
|
||||
).
|
||||
-spec uppercase(string_tree()) -> string_tree().
|
||||
uppercase(Tree) ->
|
||||
string:uppercase(Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 127).
|
||||
?DOC(" Converts a `StringTree` to a new one with the contents reversed.\n").
|
||||
-spec reverse(string_tree()) -> string_tree().
|
||||
reverse(Tree) ->
|
||||
string:reverse(Tree).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 145).
|
||||
?DOC(" Splits a `StringTree` on a given pattern into a list of trees.\n").
|
||||
-spec split(string_tree(), binary()) -> list(string_tree()).
|
||||
split(Tree, Pattern) ->
|
||||
string:split(Tree, Pattern, all).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 156).
|
||||
?DOC(" Replaces all instances of a pattern with a given string substitute.\n").
|
||||
-spec replace(string_tree(), binary(), binary()) -> string_tree().
|
||||
replace(Tree, Pattern, Substitute) ->
|
||||
gleam_stdlib:string_replace(Tree, Pattern, Substitute).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 182).
|
||||
?DOC(
|
||||
" Compares two string trees to determine if they have the same textual\n"
|
||||
" content.\n"
|
||||
"\n"
|
||||
" Comparing two string trees using the `==` operator may return `False` even\n"
|
||||
" if they have the same content as they may have been build in different ways,\n"
|
||||
" so using this function is often preferred.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_strings([\"a\", \"b\"]) == from_string(\"ab\")\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" is_equal(from_strings([\"a\", \"b\"]), from_string(\"ab\"))\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_equal(string_tree(), string_tree()) -> boolean().
|
||||
is_equal(A, B) ->
|
||||
string:equal(A, B).
|
||||
|
||||
-file("src/gleam/string_tree.gleam", 206).
|
||||
?DOC(
|
||||
" Inspects a `StringTree` to determine if it is equivalent to an empty string.\n"
|
||||
"\n"
|
||||
" ## Examples\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_string(\"ok\") |> is_empty\n"
|
||||
" // -> False\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_string(\"\") |> is_empty\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" from_strings([]) |> is_empty\n"
|
||||
" // -> True\n"
|
||||
" ```\n"
|
||||
).
|
||||
-spec is_empty(string_tree()) -> boolean().
|
||||
is_empty(Tree) ->
|
||||
string:is_empty(Tree).
|
||||
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache
Normal file
BIN
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache
Normal file
Binary file not shown.
Binary file not shown.
1117
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.erl
Normal file
1117
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.erl
Normal file
File diff suppressed because it is too large
Load diff
529
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.erl
Normal file
529
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.erl
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
-module(gleam_stdlib).
|
||||
|
||||
-export([
|
||||
map_get/2, iodata_append/2, identity/1, parse_int/1, parse_float/1,
|
||||
less_than/2, string_pop_grapheme/1, string_pop_codeunit/1,
|
||||
string_starts_with/2, wrap_list/1, string_ends_with/2, string_pad/4,
|
||||
uri_parse/1, bit_array_slice/3, percent_encode/1, percent_decode/1,
|
||||
base_decode64/1, parse_query/1, bit_array_concat/1,
|
||||
bit_array_base64_encode/2, 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, base16_encode/1, base16_decode/1, string_replace/3, slice/3,
|
||||
bit_array_to_int_and_size/1, bit_array_pad_to_bytes/1, index/2, list/5,
|
||||
dict/1, int/1, float/1, bit_array/1, is_null/1
|
||||
]).
|
||||
|
||||
%% 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).
|
||||
|
||||
%% 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).
|
||||
|
||||
-define(is_lowercase_char(X),
|
||||
(X > 96 andalso X < 123)).
|
||||
-define(is_underscore_char(X),
|
||||
(X == 95)).
|
||||
-define(is_digit_char(X),
|
||||
(X > 47 andalso X < 58)).
|
||||
-define(is_ascii_character(X),
|
||||
(erlang:is_integer(X) andalso X >= 32 andalso X =< 126)).
|
||||
|
||||
uppercase(X) -> X - 32.
|
||||
|
||||
map_get(Map, Key) ->
|
||||
case maps:find(Key, Map) of
|
||||
error -> {error, nil};
|
||||
OkFound -> OkFound
|
||||
end.
|
||||
|
||||
iodata_append(Iodata, String) -> [Iodata, String].
|
||||
|
||||
identity(X) -> X.
|
||||
|
||||
classify_dynamic(nil) -> <<"Nil">>;
|
||||
classify_dynamic(null) -> <<"Nil">>;
|
||||
classify_dynamic(undefined) -> <<"Nil">>;
|
||||
classify_dynamic(X) when is_boolean(X) -> <<"Bool">>;
|
||||
classify_dynamic(X) when is_atom(X) -> <<"Atom">>;
|
||||
classify_dynamic(X) when is_binary(X) -> <<"String">>;
|
||||
classify_dynamic(X) when is_bitstring(X) -> <<"BitArray">>;
|
||||
classify_dynamic(X) when is_integer(X) -> <<"Int">>;
|
||||
classify_dynamic(X) when is_float(X) -> <<"Float">>;
|
||||
classify_dynamic(X) when is_list(X) -> <<"List">>;
|
||||
classify_dynamic(X) when is_map(X) -> <<"Dict">>;
|
||||
classify_dynamic(X) when is_tuple(X) -> <<"Array">>;
|
||||
classify_dynamic(X) when is_reference(X) -> <<"Reference">>;
|
||||
classify_dynamic(X) when is_pid(X) -> <<"Pid">>;
|
||||
classify_dynamic(X) when is_port(X) -> <<"Port">>;
|
||||
classify_dynamic(X) when
|
||||
is_function(X, 0) orelse is_function(X, 1) orelse is_function(X, 2) orelse
|
||||
is_function(X, 3) orelse is_function(X, 4) orelse is_function(X, 5) orelse
|
||||
is_function(X, 6) orelse is_function(X, 7) orelse is_function(X, 8) orelse
|
||||
is_function(X, 9) orelse is_function(X, 10) orelse is_function(X, 11) orelse
|
||||
is_function(X, 12) -> <<"Function">>;
|
||||
classify_dynamic(_) -> <<"Unknown">>.
|
||||
|
||||
tuple_get(_tup, Index) when Index < 0 -> {error, nil};
|
||||
tuple_get(Data, Index) when Index >= tuple_size(Data) -> {error, nil};
|
||||
tuple_get(Data, Index) -> {ok, element(Index + 1, Data)}.
|
||||
|
||||
int_from_base_string(String, Base) ->
|
||||
case catch binary_to_integer(String, Base) of
|
||||
Int when is_integer(Int) -> {ok, Int};
|
||||
_ -> {error, nil}
|
||||
end.
|
||||
|
||||
parse_int(String) ->
|
||||
case catch binary_to_integer(String) of
|
||||
Int when is_integer(Int) -> {ok, Int};
|
||||
_ -> {error, nil}
|
||||
end.
|
||||
|
||||
parse_float(String) ->
|
||||
case catch binary_to_float(String) of
|
||||
Float when is_float(Float) -> {ok, Float};
|
||||
_ -> {error, nil}
|
||||
end.
|
||||
|
||||
less_than(Lhs, Rhs) ->
|
||||
Lhs < Rhs.
|
||||
|
||||
string_starts_with(_, <<>>) -> true;
|
||||
string_starts_with(String, Prefix) when byte_size(Prefix) > byte_size(String) -> false;
|
||||
string_starts_with(String, Prefix) ->
|
||||
PrefixSize = byte_size(Prefix),
|
||||
Prefix == binary_part(String, 0, PrefixSize).
|
||||
|
||||
string_ends_with(_, <<>>) -> true;
|
||||
string_ends_with(String, Suffix) when byte_size(Suffix) > byte_size(String) -> false;
|
||||
string_ends_with(String, Suffix) ->
|
||||
SuffixSize = byte_size(Suffix),
|
||||
Suffix == binary_part(String, byte_size(String) - SuffixSize, SuffixSize).
|
||||
|
||||
string_pad(String, Length, Dir, PadString) ->
|
||||
Chars = string:pad(String, Length, Dir, binary_to_list(PadString)),
|
||||
case unicode:characters_to_binary(Chars) of
|
||||
Bin when is_binary(Bin) -> Bin;
|
||||
Error -> erlang:error({gleam_error, {string_invalid_utf8, Error}})
|
||||
end.
|
||||
|
||||
string_pop_grapheme(String) ->
|
||||
case string:next_grapheme(String) of
|
||||
[ Next | Rest ] when is_binary(Rest) ->
|
||||
{ok, {unicode:characters_to_binary([Next]), Rest}};
|
||||
|
||||
[ Next | Rest ] ->
|
||||
{ok, {unicode:characters_to_binary([Next]), unicode:characters_to_binary(Rest)}};
|
||||
|
||||
_ -> {error, nil}
|
||||
end.
|
||||
|
||||
string_pop_codeunit(<<Cp/integer, Rest/binary>>) -> {Cp, Rest};
|
||||
string_pop_codeunit(Binary) -> {0, Binary}.
|
||||
|
||||
bit_array_pad_to_bytes(Bin) ->
|
||||
case erlang:bit_size(Bin) rem 8 of
|
||||
0 -> Bin;
|
||||
TrailingBits ->
|
||||
PaddingBits = 8 - TrailingBits,
|
||||
<<Bin/bits, 0:PaddingBits>>
|
||||
end.
|
||||
|
||||
bit_array_concat(BitArrays) ->
|
||||
list_to_bitstring(BitArrays).
|
||||
|
||||
-if(?OTP_RELEASE >= 26).
|
||||
bit_array_base64_encode(Bin, Padding) ->
|
||||
PaddedBin = bit_array_pad_to_bytes(Bin),
|
||||
base64:encode(PaddedBin, #{padding => Padding}).
|
||||
-else.
|
||||
bit_array_base64_encode(_Bin, _Padding) ->
|
||||
erlang:error(<<"Erlang OTP/26 or higher is required to use base64:encode">>).
|
||||
-endif.
|
||||
|
||||
bit_array_slice(Bin, Pos, Len) ->
|
||||
try {ok, binary:part(Bin, Pos, Len)}
|
||||
catch error:badarg -> {error, nil}
|
||||
end.
|
||||
|
||||
base_decode64(S) ->
|
||||
try {ok, base64:decode(S)}
|
||||
catch error:_ -> {error, nil}
|
||||
end.
|
||||
|
||||
wrap_list(X) when is_list(X) -> X;
|
||||
wrap_list(X) -> [X].
|
||||
|
||||
parse_query(Query) ->
|
||||
case uri_string:dissect_query(Query) of
|
||||
{error, _, _} -> {error, nil};
|
||||
Pairs ->
|
||||
Pairs1 = lists:map(fun
|
||||
({K, true}) -> {K, <<"">>};
|
||||
(Pair) -> Pair
|
||||
end, Pairs),
|
||||
{ok, Pairs1}
|
||||
end.
|
||||
|
||||
percent_encode(B) -> percent_encode(B, <<>>).
|
||||
percent_encode(<<>>, Acc) ->
|
||||
Acc;
|
||||
percent_encode(<<H,T/binary>>, Acc) ->
|
||||
case percent_ok(H) of
|
||||
true ->
|
||||
percent_encode(T, <<Acc/binary,H>>);
|
||||
false ->
|
||||
<<A:4,B:4>> = <<H>>,
|
||||
percent_encode(T, <<Acc/binary,$%,(?DEC2HEX(A)),(?DEC2HEX(B))>>)
|
||||
end.
|
||||
|
||||
percent_decode(Cs) -> percent_decode(Cs, <<>>).
|
||||
percent_decode(<<$%, C0, C1, Cs/binary>>, Acc) ->
|
||||
case is_hex_digit(C0) andalso is_hex_digit(C1) of
|
||||
true ->
|
||||
B = ?HEX2DEC(C0)*16+?HEX2DEC(C1),
|
||||
percent_decode(Cs, <<Acc/binary, B>>);
|
||||
false ->
|
||||
{error, nil}
|
||||
end;
|
||||
percent_decode(<<C,Cs/binary>>, Acc) ->
|
||||
percent_decode(Cs, <<Acc/binary, C>>);
|
||||
percent_decode(<<>>, Acc) ->
|
||||
check_utf8(Acc).
|
||||
|
||||
percent_ok($!) -> true;
|
||||
percent_ok($$) -> true;
|
||||
percent_ok($') -> true;
|
||||
percent_ok($() -> true;
|
||||
percent_ok($)) -> true;
|
||||
percent_ok($*) -> true;
|
||||
percent_ok($+) -> true;
|
||||
percent_ok($-) -> true;
|
||||
percent_ok($.) -> true;
|
||||
percent_ok($_) -> true;
|
||||
percent_ok($~) -> true;
|
||||
percent_ok(C) when $0 =< C, C =< $9 -> true;
|
||||
percent_ok(C) when $A =< C, C =< $Z -> true;
|
||||
percent_ok(C) when $a =< C, C =< $z -> true;
|
||||
percent_ok(_) -> false.
|
||||
|
||||
is_hex_digit(C) ->
|
||||
($0 =< C andalso C =< $9) orelse ($a =< C andalso C =< $f) orelse ($A =< C andalso C =< $F).
|
||||
|
||||
check_utf8(Cs) ->
|
||||
case unicode:characters_to_list(Cs) of
|
||||
{incomplete, _, _} -> {error, nil};
|
||||
{error, _, _} -> {error, nil};
|
||||
_ -> {ok, Cs}
|
||||
end.
|
||||
|
||||
uri_parse(String) ->
|
||||
case uri_string:parse(String) of
|
||||
{error, _, _} -> {error, nil};
|
||||
Uri ->
|
||||
{ok, {uri,
|
||||
maps_get_optional(Uri, scheme),
|
||||
maps_get_optional(Uri, userinfo),
|
||||
maps_get_optional(Uri, host),
|
||||
maps_get_optional(Uri, port),
|
||||
maps_get_or(Uri, path, <<>>),
|
||||
maps_get_optional(Uri, query),
|
||||
maps_get_optional(Uri, fragment)
|
||||
}}
|
||||
end.
|
||||
|
||||
maps_get_optional(Map, Key) ->
|
||||
try {some, maps:get(Key, Map)}
|
||||
catch _:_ -> none
|
||||
end.
|
||||
|
||||
maps_get_or(Map, Key, Default) ->
|
||||
try maps:get(Key, Map)
|
||||
catch _:_ -> Default
|
||||
end.
|
||||
|
||||
print(String) ->
|
||||
io:put_chars(String),
|
||||
nil.
|
||||
|
||||
println(String) ->
|
||||
io:put_chars([String, $\n]),
|
||||
nil.
|
||||
|
||||
print_error(String) ->
|
||||
io:put_chars(standard_error, String),
|
||||
nil.
|
||||
|
||||
println_error(String) ->
|
||||
io:put_chars(standard_error, [String, $\n]),
|
||||
nil.
|
||||
|
||||
inspect(true) ->
|
||||
"True";
|
||||
inspect(false) ->
|
||||
"False";
|
||||
inspect(nil) ->
|
||||
"Nil";
|
||||
inspect(Data) when is_map(Data) ->
|
||||
Fields = [
|
||||
[<<"#(">>, inspect(Key), <<", ">>, inspect(Value), <<")">>]
|
||||
|| {Key, Value} <- maps:to_list(Data)
|
||||
],
|
||||
["dict.from_list([", lists:join(", ", Fields), "])"];
|
||||
inspect(Atom) when is_atom(Atom) ->
|
||||
erlang:element(2, inspect_atom(Atom));
|
||||
inspect(Any) when is_integer(Any) ->
|
||||
erlang:integer_to_list(Any);
|
||||
inspect(Any) when is_float(Any) ->
|
||||
io_lib_format:fwrite_g(Any);
|
||||
inspect(Binary) when is_binary(Binary) ->
|
||||
case inspect_maybe_utf8_string(Binary, <<>>) of
|
||||
{ok, InspectedUtf8String} -> InspectedUtf8String;
|
||||
{error, not_a_utf8_string} ->
|
||||
Segments = [erlang:integer_to_list(X) || <<X>> <= Binary],
|
||||
["<<", lists:join(", ", Segments), ">>"]
|
||||
end;
|
||||
inspect(Bits) when is_bitstring(Bits) ->
|
||||
inspect_bit_array(Bits);
|
||||
inspect(List) when is_list(List) ->
|
||||
case inspect_list(List, true) of
|
||||
{charlist, _} -> ["charlist.from_string(\"", list_to_binary(List), "\")"];
|
||||
{proper, Elements} -> ["[", Elements, "]"];
|
||||
{improper, Elements} -> ["//erl([", Elements, "])"]
|
||||
end;
|
||||
inspect(Any) when is_tuple(Any) % Record constructors
|
||||
andalso is_atom(element(1, Any))
|
||||
andalso element(1, Any) =/= false
|
||||
andalso element(1, Any) =/= true
|
||||
andalso element(1, Any) =/= nil
|
||||
->
|
||||
[Atom | ArgsList] = erlang:tuple_to_list(Any),
|
||||
InspectedArgs = lists:map(fun inspect/1, ArgsList),
|
||||
case inspect_atom(Atom) of
|
||||
{gleam_atom, GleamAtom} ->
|
||||
Args = lists:join(<<", ">>, InspectedArgs),
|
||||
[GleamAtom, "(", Args, ")"];
|
||||
{erlang_atom, ErlangAtom} ->
|
||||
Args = lists:join(<<", ">>, [ErlangAtom | InspectedArgs]),
|
||||
["#(", Args, ")"]
|
||||
end;
|
||||
inspect(Tuple) when is_tuple(Tuple) ->
|
||||
Elements = lists:map(fun inspect/1, erlang:tuple_to_list(Tuple)),
|
||||
["#(", lists:join(", ", Elements), ")"];
|
||||
inspect(Any) when is_function(Any) ->
|
||||
{arity, Arity} = erlang:fun_info(Any, arity),
|
||||
ArgsAsciiCodes = lists:seq($a, $a + Arity - 1),
|
||||
Args = lists:join(<<", ">>,
|
||||
lists:map(fun(Arg) -> <<Arg>> end, ArgsAsciiCodes)
|
||||
),
|
||||
["//fn(", Args, ") { ... }"];
|
||||
inspect(Any) ->
|
||||
["//erl(", io_lib:format("~p", [Any]), ")"].
|
||||
|
||||
inspect_atom(Atom) ->
|
||||
Binary = erlang:atom_to_binary(Atom),
|
||||
case inspect_maybe_gleam_atom(Binary, none, <<>>) of
|
||||
{ok, Inspected} -> {gleam_atom, Inspected};
|
||||
{error, _} -> {erlang_atom, ["atom.create_from_string(\"", Binary, "\")"]}
|
||||
end.
|
||||
|
||||
inspect_maybe_gleam_atom(<<>>, none, _) ->
|
||||
{error, nil};
|
||||
inspect_maybe_gleam_atom(<<First, _Rest/binary>>, none, _) when ?is_digit_char(First) ->
|
||||
{error, nil};
|
||||
inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, none, _) ->
|
||||
{error, nil};
|
||||
inspect_maybe_gleam_atom(<<"_">>, _PrevChar, _Acc) ->
|
||||
{error, nil};
|
||||
inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, $_, _Acc) ->
|
||||
{error, nil};
|
||||
inspect_maybe_gleam_atom(<<First, _Rest/binary>>, _PrevChar, _Acc)
|
||||
when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) ->
|
||||
{error, nil};
|
||||
inspect_maybe_gleam_atom(<<First, Rest/binary>>, none, Acc) ->
|
||||
inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, (uppercase(First))>>);
|
||||
inspect_maybe_gleam_atom(<<"_", Rest/binary>>, _PrevChar, Acc) ->
|
||||
inspect_maybe_gleam_atom(Rest, $_, Acc);
|
||||
inspect_maybe_gleam_atom(<<First, Rest/binary>>, $_, Acc) ->
|
||||
inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, (uppercase(First))>>);
|
||||
inspect_maybe_gleam_atom(<<First, Rest/binary>>, _PrevChar, Acc) ->
|
||||
inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, First>>);
|
||||
inspect_maybe_gleam_atom(<<>>, _PrevChar, Acc) ->
|
||||
{ok, Acc};
|
||||
inspect_maybe_gleam_atom(A, B, C) ->
|
||||
erlang:display({A, B, C}),
|
||||
throw({gleam_error, A, B, C}).
|
||||
|
||||
inspect_list([], _) ->
|
||||
{proper, []};
|
||||
inspect_list([First], true) when ?is_ascii_character(First) ->
|
||||
{charlist, nil};
|
||||
inspect_list([First], _) ->
|
||||
{proper, [inspect(First)]};
|
||||
inspect_list([First | Rest], ValidCharlist) when is_list(Rest) ->
|
||||
StillValidCharlist = ValidCharlist andalso ?is_ascii_character(First),
|
||||
{Kind, Inspected} = inspect_list(Rest, StillValidCharlist),
|
||||
{Kind, [inspect(First), <<", ">> | Inspected]};
|
||||
inspect_list([First | ImproperTail], _) ->
|
||||
{improper, [inspect(First), <<" | ">>, inspect(ImproperTail)]}.
|
||||
|
||||
inspect_bit_array(Bits) ->
|
||||
Text = inspect_bit_array(Bits, <<"<<">>),
|
||||
<<Text/binary, ">>">>.
|
||||
|
||||
inspect_bit_array(<<>>, Acc) ->
|
||||
Acc;
|
||||
inspect_bit_array(<<X, Rest/bitstring>>, Acc) ->
|
||||
inspect_bit_array(Rest, append_segment(Acc, erlang:integer_to_binary(X)));
|
||||
inspect_bit_array(Rest, Acc) ->
|
||||
Size = bit_size(Rest),
|
||||
<<X:Size>> = Rest,
|
||||
X1 = erlang:integer_to_binary(X),
|
||||
Size1 = erlang:integer_to_binary(Size),
|
||||
Segment = <<X1/binary, ":size(", Size1/binary, ")">>,
|
||||
inspect_bit_array(<<>>, append_segment(Acc, Segment)).
|
||||
|
||||
bit_array_to_int_and_size(A) ->
|
||||
Size = bit_size(A),
|
||||
<<A1:Size>> = A,
|
||||
{A1, Size}.
|
||||
|
||||
append_segment(<<"<<">>, Segment) ->
|
||||
<<"<<", Segment/binary>>;
|
||||
append_segment(Acc, Segment) ->
|
||||
<<Acc/binary, ", ", Segment/binary>>.
|
||||
|
||||
|
||||
inspect_maybe_utf8_string(Binary, Acc) ->
|
||||
case Binary of
|
||||
<<>> -> {ok, <<$", Acc/binary, $">>};
|
||||
<<First/utf8, Rest/binary>> ->
|
||||
Escaped = case First of
|
||||
$" -> <<$\\, $">>;
|
||||
$\\ -> <<$\\, $\\>>;
|
||||
$\r -> <<$\\, $r>>;
|
||||
$\n -> <<$\\, $n>>;
|
||||
$\t -> <<$\\, $t>>;
|
||||
$\f -> <<$\\, $f>>;
|
||||
X when X > 126, X < 160 -> convert_to_u(X);
|
||||
X when X < 32 -> convert_to_u(X);
|
||||
Other -> <<Other/utf8>>
|
||||
end,
|
||||
inspect_maybe_utf8_string(Rest, <<Acc/binary, Escaped/binary>>);
|
||||
_ -> {error, not_a_utf8_string}
|
||||
end.
|
||||
|
||||
convert_to_u(Code) ->
|
||||
list_to_binary(io_lib:format("\\u{~4.16.0B}", [Code])).
|
||||
|
||||
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)).
|
||||
|
||||
base16_encode(Bin) ->
|
||||
PaddedBin = bit_array_pad_to_bytes(Bin),
|
||||
binary:encode_hex(PaddedBin).
|
||||
|
||||
base16_decode(String) ->
|
||||
try
|
||||
{ok, binary:decode_hex(String)}
|
||||
catch
|
||||
_:_ -> {error, nil}
|
||||
end.
|
||||
|
||||
string_replace(String, Pattern, Replacement) ->
|
||||
string:replace(String, Pattern, Replacement, all).
|
||||
|
||||
slice(String, Index, Length) ->
|
||||
case string:slice(String, Index, Length) of
|
||||
X when is_binary(X) -> X;
|
||||
X when is_list(X) -> unicode:characters_to_binary(X)
|
||||
end.
|
||||
|
||||
|
||||
index([X | _], 0) ->
|
||||
{ok, {some, X}};
|
||||
index([_, X | _], 1) ->
|
||||
{ok, {some, X}};
|
||||
index([_, _, X | _], 2) ->
|
||||
{ok, {some, X}};
|
||||
index([_, _, _, X | _], 3) ->
|
||||
{ok, {some, X}};
|
||||
index([_, _, _, _, X | _], 4) ->
|
||||
{ok, {some, X}};
|
||||
index([_, _, _, _, _, X | _], 5) ->
|
||||
{ok, {some, X}};
|
||||
index([_, _, _, _, _, _, X | _], 6) ->
|
||||
{ok, {some, X}};
|
||||
index([_, _, _, _, _, _, _, X | _], 7) ->
|
||||
{ok, {some, X}};
|
||||
index(Tuple, Index) when is_tuple(Tuple) andalso is_integer(Index) ->
|
||||
{ok, try
|
||||
{some, element(Index + 1, Tuple)}
|
||||
catch _:_ ->
|
||||
none
|
||||
end};
|
||||
index(Map, Key) when is_map(Map) ->
|
||||
{ok, try
|
||||
{some, maps:get(Key, Map)}
|
||||
catch _:_ ->
|
||||
none
|
||||
end};
|
||||
index(_, Index) when is_integer(Index) ->
|
||||
{error, <<"Indexable">>};
|
||||
index(_, _) ->
|
||||
{error, <<"Dict">>}.
|
||||
|
||||
list(T, A, B, C, D) when is_tuple(T) ->
|
||||
list(tuple_to_list(T), A, B, C, D);
|
||||
list([], _, _, _, Acc) ->
|
||||
{lists:reverse(Acc), []};
|
||||
list([X | Xs], Decode, PushPath, Index, Acc) ->
|
||||
{Out, Errors} = Decode(X),
|
||||
case Errors of
|
||||
[] -> list(Xs, Decode, PushPath, Index + 1, [Out | Acc]);
|
||||
_ -> PushPath({[], Errors}, integer_to_binary(Index))
|
||||
end;
|
||||
list(Unexpected, _, _, _, []) ->
|
||||
Found = gleam@dynamic:classify(Unexpected),
|
||||
Error = {decode_error, <<"List"/utf8>>, Found, []},
|
||||
{[], [Error]};
|
||||
list(_, _, _, _, Acc) ->
|
||||
{lists:reverse(Acc), []}.
|
||||
|
||||
dict(#{} = Data) -> {ok, Data};
|
||||
dict(_) -> {error, nil}.
|
||||
|
||||
int(I) when is_integer(I) -> {ok, I};
|
||||
int(_) -> {error, 0}.
|
||||
|
||||
float(F) when is_float(F) -> {ok, F};
|
||||
float(_) -> {error, 0.0}.
|
||||
|
||||
bit_array(B) when is_bitstring(B) -> {ok, B};
|
||||
bit_array(_) -> {error, <<>>}.
|
||||
|
||||
is_null(X) ->
|
||||
X =:= undefined orelse X =:= null orelse X =:= nil.
|
||||
1044
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.mjs
Normal file
1044
build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.mjs
Normal file
File diff suppressed because it is too large
Load diff
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@bit_array.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@bit_array.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@bool.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@bool.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@bytes_tree.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@bytes_tree.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@dict.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@dict.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic@decode.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic@decode.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@float.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@float.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@function.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@function.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@int.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@int.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@io.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@io.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@list.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@list.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@option.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@option.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@order.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@order.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@pair.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@pair.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@result.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@result.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@set.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@set.beam
Normal file
Binary file not shown.
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@string.beam
Normal file
BIN
build/dev/erlang/gleam_stdlib/ebin/gleam@string.beam
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue