From 00a8f996f43d97264ca8432ebe179d793541286c Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 18 Jul 2025 13:58:21 -0500 Subject: [PATCH] Add Gleam language integration to Elixir project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .github/workflows/elixir.yaml | 29 + GLEAM_INTEGRATION.md | 85 + .../aprsme/_gleam_artefacts/aprsme@@main.erl | 100 + .../_gleam_artefacts/aprsme@encoding.cache | Bin 0 -> 10393 bytes .../aprsme@encoding.cache_meta | Bin 0 -> 1062 bytes .../_gleam_artefacts/aprsme@encoding.erl | 275 ++ .../assets/js/map_helpers_test.ts | 186 ++ .../_gleam_artefacts/gleam@@compile.erl | 182 ++ .../_gleam_artefacts/support/aprs_is_mock.ex | 167 + .../_gleam_artefacts/support/conn_case.ex | 74 + .../_gleam_artefacts/support/data_case.ex | 78 + .../support/fixtures/accounts_fixtures.ex | 37 + .../support/fixtures/packets_fixtures.ex | 54 + .../_gleam_artefacts/support/mock_helpers.ex | 32 + .../_gleam_artefacts/support/test_helpers.ex | 81 + build/dev/erlang/aprsme/ebin/aprsme.app | 8 + .../dev/erlang/aprsme/ebin/aprsme@@main.beam | Bin 0 -> 6600 bytes .../include/aprsme@encoding_EncodingInfo.hrl | 6 + build/dev/erlang/aprsme/priv | 1 + build/dev/erlang/eex | 1 + build/dev/erlang/elixir | 1 + build/dev/erlang/gleam_elixir_paths | 4 + .../gleam_stdlib/_gleam_artefacts/dict.mjs | 993 ++++++ .../_gleam_artefacts/gleam@@compile.erl | 182 ++ .../_gleam_artefacts/gleam@bit_array.cache | Bin 0 -> 14219 bytes .../gleam@bit_array.cache_meta | Bin 0 -> 1249 bytes .../_gleam_artefacts/gleam@bit_array.erl | 346 ++ .../_gleam_artefacts/gleam@bool.cache | Bin 0 -> 8705 bytes .../_gleam_artefacts/gleam@bool.cache_meta | Bin 0 -> 1317 bytes .../_gleam_artefacts/gleam@bool.erl | 352 ++ .../_gleam_artefacts/gleam@bytes_tree.cache | Bin 0 -> 12983 bytes .../gleam@bytes_tree.cache_meta | Bin 0 -> 903 bytes .../_gleam_artefacts/gleam@bytes_tree.erl | 211 ++ .../_gleam_artefacts/gleam@dict.cache | Bin 0 -> 24041 bytes .../_gleam_artefacts/gleam@dict.cache_meta | Bin 0 -> 2273 bytes .../_gleam_artefacts/gleam@dict.erl | 561 ++++ .../_gleam_artefacts/gleam@dynamic.cache | Bin 0 -> 6989 bytes .../_gleam_artefacts/gleam@dynamic.cache_meta | Bin 0 -> 479 bytes .../_gleam_artefacts/gleam@dynamic.erl | 106 + .../gleam@dynamic@decode.cache | Bin 0 -> 57064 bytes .../gleam@dynamic@decode.cache_meta | Bin 0 -> 4466 bytes .../_gleam_artefacts/gleam@dynamic@decode.erl | 1083 +++++++ .../_gleam_artefacts/gleam@float.cache | Bin 0 -> 23125 bytes .../_gleam_artefacts/gleam@float.cache_meta | Bin 0 -> 2724 bytes .../_gleam_artefacts/gleam@float.erl | 744 +++++ .../_gleam_artefacts/gleam@function.cache | Bin 0 -> 1083 bytes .../gleam@function.cache_meta | Bin 0 -> 113 bytes .../_gleam_artefacts/gleam@function.erl | 30 + .../_gleam_artefacts/gleam@int.cache | Bin 0 -> 29069 bytes .../_gleam_artefacts/gleam@int.cache_meta | Bin 0 -> 3411 bytes .../_gleam_artefacts/gleam@int.erl | 984 ++++++ .../_gleam_artefacts/gleam@io.cache | Bin 0 -> 2639 bytes .../_gleam_artefacts/gleam@io.cache_meta | Bin 0 -> 289 bytes .../_gleam_artefacts/gleam@io.erl | 80 + .../_gleam_artefacts/gleam@list.cache | Bin 0 -> 85274 bytes .../_gleam_artefacts/gleam@list.cache_meta | Bin 0 -> 9734 bytes .../_gleam_artefacts/gleam@list.erl | 2860 +++++++++++++++++ .../_gleam_artefacts/gleam@option.cache | Bin 0 -> 13525 bytes .../_gleam_artefacts/gleam@option.cache_meta | Bin 0 -> 1485 bytes .../_gleam_artefacts/gleam@option.erl | 413 +++ .../_gleam_artefacts/gleam@order.cache | Bin 0 -> 5774 bytes .../_gleam_artefacts/gleam@order.cache_meta | Bin 0 -> 677 bytes .../_gleam_artefacts/gleam@order.erl | 200 ++ .../_gleam_artefacts/gleam@pair.cache | Bin 0 -> 2757 bytes .../_gleam_artefacts/gleam@pair.cache_meta | Bin 0 -> 403 bytes .../_gleam_artefacts/gleam@pair.erl | 110 + .../_gleam_artefacts/gleam@result.cache | Bin 0 -> 15479 bytes .../_gleam_artefacts/gleam@result.cache_meta | Bin 0 -> 1947 bytes .../_gleam_artefacts/gleam@result.erl | 566 ++++ .../_gleam_artefacts/gleam@set.cache | Bin 0 -> 16777 bytes .../_gleam_artefacts/gleam@set.cache_meta | Bin 0 -> 1761 bytes .../_gleam_artefacts/gleam@set.erl | 429 +++ .../_gleam_artefacts/gleam@string.cache | Bin 0 -> 35323 bytes .../_gleam_artefacts/gleam@string.cache_meta | Bin 0 -> 3869 bytes .../_gleam_artefacts/gleam@string.erl | 957 ++++++ .../_gleam_artefacts/gleam@string_tree.cache | Bin 0 -> 14138 bytes .../gleam@string_tree.cache_meta | Bin 0 -> 911 bytes .../_gleam_artefacts/gleam@string_tree.erl | 207 ++ .../_gleam_artefacts/gleam@uri.cache | Bin 0 -> 31127 bytes .../_gleam_artefacts/gleam@uri.cache_meta | Bin 0 -> 3253 bytes .../_gleam_artefacts/gleam@uri.erl | 1117 +++++++ .../_gleam_artefacts/gleam_stdlib.erl | 529 +++ .../_gleam_artefacts/gleam_stdlib.mjs | 1044 ++++++ .../gleam_stdlib/ebin/gleam@bit_array.beam | Bin 0 -> 13616 bytes .../erlang/gleam_stdlib/ebin/gleam@bool.beam | Bin 0 -> 8492 bytes .../gleam_stdlib/ebin/gleam@bytes_tree.beam | Bin 0 -> 8852 bytes .../erlang/gleam_stdlib/ebin/gleam@dict.beam | Bin 0 -> 17072 bytes .../gleam_stdlib/ebin/gleam@dynamic.beam | Bin 0 -> 4820 bytes .../ebin/gleam@dynamic@decode.beam | Bin 0 -> 38440 bytes .../erlang/gleam_stdlib/ebin/gleam@float.beam | Bin 0 -> 19520 bytes .../gleam_stdlib/ebin/gleam@function.beam | Bin 0 -> 1796 bytes .../erlang/gleam_stdlib/ebin/gleam@int.beam | Bin 0 -> 23860 bytes .../erlang/gleam_stdlib/ebin/gleam@io.beam | Bin 0 -> 2756 bytes .../erlang/gleam_stdlib/ebin/gleam@list.beam | Bin 0 -> 73044 bytes .../gleam_stdlib/ebin/gleam@option.beam | Bin 0 -> 10064 bytes .../erlang/gleam_stdlib/ebin/gleam@order.beam | Bin 0 -> 4788 bytes .../erlang/gleam_stdlib/ebin/gleam@pair.beam | Bin 0 -> 3648 bytes .../gleam_stdlib/ebin/gleam@result.beam | Bin 0 -> 15204 bytes .../erlang/gleam_stdlib/ebin/gleam@set.beam | Bin 0 -> 13912 bytes .../gleam_stdlib/ebin/gleam@string.beam | Bin 0 -> 27668 bytes .../gleam_stdlib/ebin/gleam@string_tree.beam | Bin 0 -> 8652 bytes .../erlang/gleam_stdlib/ebin/gleam@uri.beam | Bin 0 -> 26276 bytes .../erlang/gleam_stdlib/ebin/gleam_stdlib.app | 7 + .../gleam_stdlib/ebin/gleam_stdlib.beam | Bin 0 -> 27116 bytes .../gleam@dynamic@decode_DecodeError.hrl | 5 + .../include/gleam@dynamic@decode_Decoder.hrl | 4 + .../gleam_stdlib/include/gleam@set_Set.hrl | 1 + .../gleam_stdlib/include/gleam@uri_Uri.hrl | 9 + build/dev/erlang/gleam_version | 1 + .../gleeunit/_gleam_artefacts/gleeunit.cache | Bin 0 -> 7752 bytes .../_gleam_artefacts/gleeunit.cache_meta | Bin 0 -> 455 bytes .../gleeunit/_gleam_artefacts/gleeunit.erl | 87 + .../internal/gleeunit_gleam_panic_ffi.erl | 49 + .../internal/gleeunit_gleam_panic_ffi.mjs | 91 + .../gleeunit@internal@gleam_panic.cache | Bin 0 -> 13578 bytes .../gleeunit@internal@gleam_panic.cache_meta | Bin 0 -> 278 bytes .../gleeunit@internal@gleam_panic.erl | 56 + .../gleeunit@internal@reporting.cache | Bin 0 -> 12966 bytes .../gleeunit@internal@reporting.cache_meta | Bin 0 -> 1225 bytes .../gleeunit@internal@reporting.erl | 331 ++ .../_gleam_artefacts/gleeunit@should.cache | Bin 0 -> 3713 bytes .../gleeunit@should.cache_meta | Bin 0 -> 397 bytes .../_gleam_artefacts/gleeunit@should.erl | 153 + .../_gleam_artefacts/gleeunit_ffi.erl | 14 + .../_gleam_artefacts/gleeunit_ffi.mjs | 100 + .../_gleam_artefacts/gleeunit_progress.erl | 74 + build/dev/erlang/gleeunit/ebin/gleeunit.app | 7 + build/dev/erlang/gleeunit/ebin/gleeunit.beam | Bin 0 -> 4188 bytes .../ebin/gleeunit@internal@gleam_panic.beam | Bin 0 -> 2360 bytes .../ebin/gleeunit@internal@reporting.beam | Bin 0 -> 14556 bytes .../erlang/gleeunit/ebin/gleeunit@should.beam | Bin 0 -> 5588 bytes .../erlang/gleeunit/ebin/gleeunit_ffi.beam | Bin 0 -> 1728 bytes .../ebin/gleeunit_gleam_panic_ffi.beam | Bin 0 -> 3312 bytes .../gleeunit/ebin/gleeunit_progress.beam | Bin 0 -> 3628 bytes .../gleeunit@internal@gleam_panic_Assert.hrl | 6 + ...nternal@gleam_panic_AssertedExpression.hrl | 5 + ...it@internal@gleam_panic_BinaryOperator.hrl | 5 + ...eeunit@internal@gleam_panic_Expression.hrl | 1 + ...unit@internal@gleam_panic_FunctionCall.hrl | 3 + ...eeunit@internal@gleam_panic_GleamPanic.hrl | 8 + ...leeunit@internal@gleam_panic_LetAssert.hrl | 7 + .../gleeunit@internal@gleam_panic_Literal.hrl | 1 + ...t@internal@gleam_panic_OtherExpression.hrl | 3 + .../gleeunit@internal@reporting_State.hrl | 1 + build/dev/erlang/logger | 1 + build/dev/erlang/mix | 1 + build/gleam-dev-erlang.lock | 0 build/gleam-dev-javascript.lock | 0 build/gleam-lsp-erlang.lock | 0 build/gleam-lsp-javascript.lock | 0 build/gleam-prod-erlang.lock | 0 build/gleam-prod-javascript.lock | 0 build/packages/gleam.lock | 0 build/packages/gleam_stdlib/LICENCE | 191 ++ build/packages/gleam_stdlib/README.md | 34 + build/packages/gleam_stdlib/gleam.toml | 14 + .../gleam@dynamic@decode_DecodeError.hrl | 5 + .../include/gleam@dynamic@decode_Decoder.hrl | 4 + .../gleam_stdlib/include/gleam@set_Set.hrl | 1 + .../gleam_stdlib/include/gleam@uri_Uri.hrl | 9 + build/packages/gleam_stdlib/src/dict.mjs | 993 ++++++ .../gleam_stdlib/src/gleam/bit_array.gleam | 279 ++ .../gleam_stdlib/src/gleam/bool.gleam | 316 ++ .../gleam_stdlib/src/gleam/bytes_tree.gleam | 190 ++ .../gleam_stdlib/src/gleam/dict.gleam | 548 ++++ .../gleam_stdlib/src/gleam/dynamic.gleam | 100 + .../src/gleam/dynamic/decode.gleam | 1057 ++++++ .../gleam_stdlib/src/gleam/float.gleam | 661 ++++ .../gleam_stdlib/src/gleam/function.gleam | 15 + .../packages/gleam_stdlib/src/gleam/int.gleam | 826 +++++ .../packages/gleam_stdlib/src/gleam/io.gleam | 59 + .../gleam_stdlib/src/gleam/list.gleam | 2394 ++++++++++++++ .../gleam_stdlib/src/gleam/option.gleam | 358 +++ .../gleam_stdlib/src/gleam/order.gleam | 156 + .../gleam_stdlib/src/gleam/pair.gleam | 85 + .../gleam_stdlib/src/gleam/result.gleam | 467 +++ .../packages/gleam_stdlib/src/gleam/set.gleam | 407 +++ .../gleam_stdlib/src/gleam/string.gleam | 853 +++++ .../gleam_stdlib/src/gleam/string_tree.gleam | 208 ++ .../packages/gleam_stdlib/src/gleam/uri.gleam | 765 +++++ .../gleam_stdlib/src/gleam@bit_array.erl | 346 ++ .../packages/gleam_stdlib/src/gleam@bool.erl | 352 ++ .../gleam_stdlib/src/gleam@bytes_tree.erl | 211 ++ .../packages/gleam_stdlib/src/gleam@dict.erl | 561 ++++ .../gleam_stdlib/src/gleam@dynamic.erl | 106 + .../gleam_stdlib/src/gleam@dynamic@decode.erl | 1084 +++++++ .../packages/gleam_stdlib/src/gleam@float.erl | 744 +++++ .../gleam_stdlib/src/gleam@function.erl | 30 + build/packages/gleam_stdlib/src/gleam@int.erl | 984 ++++++ build/packages/gleam_stdlib/src/gleam@io.erl | 80 + .../packages/gleam_stdlib/src/gleam@list.erl | 2860 +++++++++++++++++ .../gleam_stdlib/src/gleam@option.erl | 413 +++ .../packages/gleam_stdlib/src/gleam@order.erl | 200 ++ .../packages/gleam_stdlib/src/gleam@pair.erl | 110 + .../gleam_stdlib/src/gleam@result.erl | 566 ++++ build/packages/gleam_stdlib/src/gleam@set.erl | 429 +++ .../gleam_stdlib/src/gleam@string.erl | 957 ++++++ .../gleam_stdlib/src/gleam@string_tree.erl | 207 ++ build/packages/gleam_stdlib/src/gleam@uri.erl | 1030 ++++++ .../gleam_stdlib/src/gleam_stdlib.app.src | 31 + .../gleam_stdlib/src/gleam_stdlib.erl | 529 +++ .../gleam_stdlib/src/gleam_stdlib.mjs | 1044 ++++++ build/packages/gleeunit/LICENCE | 191 ++ build/packages/gleeunit/README.md | 44 + build/packages/gleeunit/gleam.toml | 16 + .../gleeunit@internal@gleam_panic_Assert.hrl | 6 + ...nternal@gleam_panic_AssertedExpression.hrl | 5 + ...it@internal@gleam_panic_BinaryOperator.hrl | 5 + ...eeunit@internal@gleam_panic_Expression.hrl | 1 + ...unit@internal@gleam_panic_FunctionCall.hrl | 3 + ...eeunit@internal@gleam_panic_GleamPanic.hrl | 8 + ...leeunit@internal@gleam_panic_LetAssert.hrl | 7 + .../gleeunit@internal@gleam_panic_Literal.hrl | 1 + ...t@internal@gleam_panic_OtherExpression.hrl | 3 + .../gleeunit@internal@reporting_State.hrl | 1 + build/packages/gleeunit/src/gleeunit.app.src | 16 + build/packages/gleeunit/src/gleeunit.erl | 87 + build/packages/gleeunit/src/gleeunit.gleam | 80 + .../src/gleeunit/internal/gleam_panic.gleam | 49 + .../internal/gleeunit_gleam_panic_ffi.erl | 49 + .../internal/gleeunit_gleam_panic_ffi.mjs | 91 + .../src/gleeunit/internal/reporting.gleam | 227 ++ .../gleeunit/src/gleeunit/should.gleam | 72 + .../src/gleeunit@internal@gleam_panic.erl | 56 + .../src/gleeunit@internal@reporting.erl | 328 ++ .../packages/gleeunit/src/gleeunit@should.erl | 153 + build/packages/gleeunit/src/gleeunit_ffi.erl | 14 + build/packages/gleeunit/src/gleeunit_ffi.mjs | 100 + .../gleeunit/src/gleeunit_progress.erl | 74 + build/packages/packages.toml | 3 + gleam.toml | 10 + lib/aprsme/encoding_utils.ex | 154 +- lib/mix/tasks/gleam_compile.ex | 99 + manifest.toml | 11 + mix.exs | 20 +- mix.lock | 2 + priv/gleam/aprs.beam | Bin 0 -> 716 bytes priv/gleam/aprs@@main.beam | Bin 0 -> 6624 bytes priv/gleam/aprs@encoding_simple.beam | Bin 0 -> 3800 bytes priv/gleam/gleam@bit_array.beam | Bin 0 -> 13636 bytes priv/gleam/gleam@bool.beam | Bin 0 -> 8512 bytes priv/gleam/gleam@bytes_tree.beam | Bin 0 -> 8868 bytes priv/gleam/gleam@dict.beam | Bin 0 -> 17092 bytes priv/gleam/gleam@dynamic.beam | Bin 0 -> 4840 bytes priv/gleam/gleam@dynamic@decode.beam | Bin 0 -> 38460 bytes priv/gleam/gleam@float.beam | Bin 0 -> 19540 bytes priv/gleam/gleam@function.beam | Bin 0 -> 1816 bytes priv/gleam/gleam@int.beam | Bin 0 -> 23880 bytes priv/gleam/gleam@io.beam | Bin 0 -> 2772 bytes priv/gleam/gleam@list.beam | Bin 0 -> 73064 bytes priv/gleam/gleam@option.beam | Bin 0 -> 10080 bytes priv/gleam/gleam@order.beam | Bin 0 -> 4808 bytes priv/gleam/gleam@pair.beam | Bin 0 -> 3668 bytes priv/gleam/gleam@result.beam | Bin 0 -> 15220 bytes priv/gleam/gleam@set.beam | Bin 0 -> 13932 bytes priv/gleam/gleam@string.beam | Bin 0 -> 27684 bytes priv/gleam/gleam@string_tree.beam | Bin 0 -> 8668 bytes priv/gleam/gleam@uri.beam | Bin 0 -> 26296 bytes priv/gleam/gleam_stdlib.beam | Bin 0 -> 27152 bytes priv/gleam/gleeunit.beam | Bin 0 -> 4208 bytes priv/gleam/gleeunit@internal@gleam_panic.beam | Bin 0 -> 2380 bytes priv/gleam/gleeunit@internal@reporting.beam | Bin 0 -> 14576 bytes priv/gleam/gleeunit@should.beam | Bin 0 -> 5608 bytes priv/gleam/gleeunit_ffi.beam | Bin 0 -> 1760 bytes priv/gleam/gleeunit_gleam_panic_ffi.beam | Bin 0 -> 3352 bytes priv/gleam/gleeunit_progress.beam | Bin 0 -> 3664 bytes src/aprsme/encoding.gleam | 212 ++ 267 files changed, 42488 insertions(+), 115 deletions(-) create mode 100644 GLEAM_INTEGRATION.md create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/aprsme@@main.erl create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache_meta create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.erl create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/assets/js/map_helpers_test.ts create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/gleam@@compile.erl create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/aprs_is_mock.ex create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/conn_case.ex create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/data_case.ex create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/accounts_fixtures.ex create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/packets_fixtures.ex create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/mock_helpers.ex create mode 100644 build/dev/erlang/aprsme/_gleam_artefacts/support/test_helpers.ex create mode 100644 build/dev/erlang/aprsme/ebin/aprsme.app create mode 100644 build/dev/erlang/aprsme/ebin/aprsme@@main.beam create mode 100644 build/dev/erlang/aprsme/include/aprsme@encoding_EncodingInfo.hrl create mode 120000 build/dev/erlang/aprsme/priv create mode 120000 build/dev/erlang/eex create mode 120000 build/dev/erlang/elixir create mode 100644 build/dev/erlang/gleam_elixir_paths create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/dict.mjs create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@@compile.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bit_array.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@function.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@function.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@function.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.erl create mode 100644 build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.mjs create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@bit_array.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@bool.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@bytes_tree.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@dict.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic@decode.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@float.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@function.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@int.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@io.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@list.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@option.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@order.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@pair.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@result.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@set.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@string.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@string_tree.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam@uri.beam create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.app create mode 100644 build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.beam create mode 100644 build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl create mode 100644 build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl create mode 100644 build/dev/erlang/gleam_stdlib/include/gleam@set_Set.hrl create mode 100644 build/dev/erlang/gleam_stdlib/include/gleam@uri_Uri.hrl create mode 100644 build/dev/erlang/gleam_version create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.cache create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.cache_meta create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.erl create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.erl create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_meta create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.erl create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_meta create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.erl create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.cache create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.cache_meta create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.erl create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.erl create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.mjs create mode 100644 build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_progress.erl create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit.app create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit.beam create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit@internal@gleam_panic.beam create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit@internal@reporting.beam create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit@should.beam create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit_ffi.beam create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit_gleam_panic_ffi.beam create mode 100644 build/dev/erlang/gleeunit/ebin/gleeunit_progress.beam create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl create mode 100644 build/dev/erlang/gleeunit/include/gleeunit@internal@reporting_State.hrl create mode 120000 build/dev/erlang/logger create mode 120000 build/dev/erlang/mix create mode 100644 build/gleam-dev-erlang.lock create mode 100644 build/gleam-dev-javascript.lock create mode 100644 build/gleam-lsp-erlang.lock create mode 100644 build/gleam-lsp-javascript.lock create mode 100644 build/gleam-prod-erlang.lock create mode 100644 build/gleam-prod-javascript.lock create mode 100644 build/packages/gleam.lock create mode 100644 build/packages/gleam_stdlib/LICENCE create mode 100644 build/packages/gleam_stdlib/README.md create mode 100644 build/packages/gleam_stdlib/gleam.toml create mode 100644 build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl create mode 100644 build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl create mode 100644 build/packages/gleam_stdlib/include/gleam@set_Set.hrl create mode 100644 build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl create mode 100644 build/packages/gleam_stdlib/src/dict.mjs create mode 100644 build/packages/gleam_stdlib/src/gleam/bit_array.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/bool.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/dict.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/dynamic.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/float.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/function.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/int.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/io.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/list.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/option.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/order.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/pair.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/result.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/set.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/string.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/string_tree.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam/uri.gleam create mode 100644 build/packages/gleam_stdlib/src/gleam@bit_array.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@bool.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@bytes_tree.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@dict.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@dynamic.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@float.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@function.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@int.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@io.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@list.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@option.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@order.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@pair.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@result.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@set.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@string.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@string_tree.erl create mode 100644 build/packages/gleam_stdlib/src/gleam@uri.erl create mode 100644 build/packages/gleam_stdlib/src/gleam_stdlib.app.src create mode 100644 build/packages/gleam_stdlib/src/gleam_stdlib.erl create mode 100644 build/packages/gleam_stdlib/src/gleam_stdlib.mjs create mode 100644 build/packages/gleeunit/LICENCE create mode 100644 build/packages/gleeunit/README.md create mode 100644 build/packages/gleeunit/gleam.toml create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl create mode 100644 build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl create mode 100644 build/packages/gleeunit/src/gleeunit.app.src create mode 100644 build/packages/gleeunit/src/gleeunit.erl create mode 100644 build/packages/gleeunit/src/gleeunit.gleam create mode 100644 build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam create mode 100644 build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl create mode 100644 build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs create mode 100644 build/packages/gleeunit/src/gleeunit/internal/reporting.gleam create mode 100644 build/packages/gleeunit/src/gleeunit/should.gleam create mode 100644 build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl create mode 100644 build/packages/gleeunit/src/gleeunit@internal@reporting.erl create mode 100644 build/packages/gleeunit/src/gleeunit@should.erl create mode 100644 build/packages/gleeunit/src/gleeunit_ffi.erl create mode 100644 build/packages/gleeunit/src/gleeunit_ffi.mjs create mode 100644 build/packages/gleeunit/src/gleeunit_progress.erl create mode 100644 build/packages/packages.toml create mode 100644 gleam.toml create mode 100644 lib/mix/tasks/gleam_compile.ex create mode 100644 manifest.toml create mode 100644 priv/gleam/aprs.beam create mode 100644 priv/gleam/aprs@@main.beam create mode 100644 priv/gleam/aprs@encoding_simple.beam create mode 100644 priv/gleam/gleam@bit_array.beam create mode 100644 priv/gleam/gleam@bool.beam create mode 100644 priv/gleam/gleam@bytes_tree.beam create mode 100644 priv/gleam/gleam@dict.beam create mode 100644 priv/gleam/gleam@dynamic.beam create mode 100644 priv/gleam/gleam@dynamic@decode.beam create mode 100644 priv/gleam/gleam@float.beam create mode 100644 priv/gleam/gleam@function.beam create mode 100644 priv/gleam/gleam@int.beam create mode 100644 priv/gleam/gleam@io.beam create mode 100644 priv/gleam/gleam@list.beam create mode 100644 priv/gleam/gleam@option.beam create mode 100644 priv/gleam/gleam@order.beam create mode 100644 priv/gleam/gleam@pair.beam create mode 100644 priv/gleam/gleam@result.beam create mode 100644 priv/gleam/gleam@set.beam create mode 100644 priv/gleam/gleam@string.beam create mode 100644 priv/gleam/gleam@string_tree.beam create mode 100644 priv/gleam/gleam@uri.beam create mode 100644 priv/gleam/gleam_stdlib.beam create mode 100644 priv/gleam/gleeunit.beam create mode 100644 priv/gleam/gleeunit@internal@gleam_panic.beam create mode 100644 priv/gleam/gleeunit@internal@reporting.beam create mode 100644 priv/gleam/gleeunit@should.beam create mode 100644 priv/gleam/gleeunit_ffi.beam create mode 100644 priv/gleam/gleeunit_gleam_panic_ffi.beam create mode 100644 priv/gleam/gleeunit_progress.beam create mode 100644 src/aprsme/encoding.gleam diff --git a/.github/workflows/elixir.yaml b/.github/workflows/elixir.yaml index 26f38d8..c7b712e 100644 --- a/.github/workflows/elixir.yaml +++ b/.github/workflows/elixir.yaml @@ -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 diff --git a/GLEAM_INTEGRATION.md b/GLEAM_INTEGRATION.md new file mode 100644 index 0000000..3fd50c2 --- /dev/null +++ b/GLEAM_INTEGRATION.md @@ -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 \ No newline at end of file diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@@main.erl b/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@@main.erl new file mode 100644 index 0000000..ae11abb --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@@main.erl @@ -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]. \ No newline at end of file diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache b/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache new file mode 100644 index 0000000000000000000000000000000000000000..acddc36a6e364514f52ac27fb399d17058d89206 GIT binary patch literal 10393 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 U7C(<8CmU((}?%K!iX literal 0 HcmV?d00001 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache_meta b/build/dev/erlang/aprsme/_gleam_artefacts/aprsme@encoding.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..a9f9645dda30df42644ed2f0ba0303cc1f319564 GIT binary patch literal 1062 zcmY+@Nk~;u7y#g-S!QXY8bVPRMNu@+Mv9<_2GE@bEwWH@cx2CdzN{>C5z#_ujwUiG zn;?>~0;8xvTQqJWshtg*Fe7LYN!oX@7XI*Y@A=PgFX#N{;i-n|AX;|r8lN&IdJ~z$ zk5E-pQMO}oT{01iS4F9*j2qEc6RS&R%gkZqtlFK)SZ#c+d@&hBF}z|do-EPW#`q{J zhC3>2YRi%pntPZS<;8GUc`UiLERiVNw^!;21BX^7mNvDdzKzEGi|ALPPe!Xp%S2<3 za*Q`*ri8GHDw?^=Gy3^WUTO#{Sj}42vw=8Q=%$DFd?0^R2;5&ILU5B;IlysFbB42Y@|gj$vg|(vEN2Cc+@_0J6GB)<5hd*9Dvx;0JN__AolPQ} zT&7XTIr^DBNzG7717~QbgL~ZP9sLZFJvoH=tfQPts)=!$R}3&n{*(|_vXMG2a+e3Z zB*TrHK>?dcaDwx+(#AEe^Mf20U^a^=r;&D^F*C=VpqUHY= 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, <>} -> + 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(<>) 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(<>) 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, <>} -> + 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. diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/assets/js/map_helpers_test.ts b/build/dev/erlang/aprsme/_gleam_artefacts/assets/js/map_helpers_test.ts new file mode 100644 index 0000000..3eae93d --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/assets/js/map_helpers_test.ts @@ -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(); + }); + }); +}); \ No newline at end of file diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/gleam@@compile.erl b/build/dev/erlang/aprsme/_gleam_artefacts/gleam@@compile.erl new file mode 100644 index 0000000..406deee --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/gleam@@compile.erl @@ -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. diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/aprs_is_mock.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/aprs_is_mock.ex new file mode 100644 index 0000000..b43faa8 --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/aprs_is_mock.ex @@ -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 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/conn_case.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/conn_case.ex new file mode 100644 index 0000000..b8a28d4 --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/conn_case.ex @@ -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 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/data_case.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/data_case.ex new file mode 100644 index 0000000..806d7f2 --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/data_case.ex @@ -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 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/accounts_fixtures.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/accounts_fixtures.ex new file mode 100644 index 0000000..4c6921b --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/accounts_fixtures.ex @@ -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 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/packets_fixtures.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/packets_fixtures.ex new file mode 100644 index 0000000..1f88dbc --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/fixtures/packets_fixtures.ex @@ -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 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/mock_helpers.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/mock_helpers.ex new file mode 100644 index 0000000..a70ac6c --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/mock_helpers.ex @@ -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 diff --git a/build/dev/erlang/aprsme/_gleam_artefacts/support/test_helpers.ex b/build/dev/erlang/aprsme/_gleam_artefacts/support/test_helpers.ex new file mode 100644 index 0000000..9448076 --- /dev/null +++ b/build/dev/erlang/aprsme/_gleam_artefacts/support/test_helpers.ex @@ -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 diff --git a/build/dev/erlang/aprsme/ebin/aprsme.app b/build/dev/erlang/aprsme/ebin/aprsme.app new file mode 100644 index 0000000..524ab0d --- /dev/null +++ b/build/dev/erlang/aprsme/ebin/aprsme.app @@ -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, []} +]}. diff --git a/build/dev/erlang/aprsme/ebin/aprsme@@main.beam b/build/dev/erlang/aprsme/ebin/aprsme@@main.beam new file mode 100644 index 0000000000000000000000000000000000000000..d1d4d9f8a7ca5c381515daabb2d0103780923e0d GIT binary patch literal 6600 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 R=EL591i4x8^h0p?{{gW}Lk9o= literal 0 HcmV?d00001 diff --git a/build/dev/erlang/aprsme/include/aprsme@encoding_EncodingInfo.hrl b/build/dev/erlang/aprsme/include/aprsme@encoding_EncodingInfo.hrl new file mode 100644 index 0000000..af2aee3 --- /dev/null +++ b/build/dev/erlang/aprsme/include/aprsme@encoding_EncodingInfo.hrl @@ -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()) +}). diff --git a/build/dev/erlang/aprsme/priv b/build/dev/erlang/aprsme/priv new file mode 120000 index 0000000..4e7b000 --- /dev/null +++ b/build/dev/erlang/aprsme/priv @@ -0,0 +1 @@ +/Users/graham/dev/aprs.me/priv \ No newline at end of file diff --git a/build/dev/erlang/eex b/build/dev/erlang/eex new file mode 120000 index 0000000..22b6ea6 --- /dev/null +++ b/build/dev/erlang/eex @@ -0,0 +1 @@ +/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/eex \ No newline at end of file diff --git a/build/dev/erlang/elixir b/build/dev/erlang/elixir new file mode 120000 index 0000000..c0f1160 --- /dev/null +++ b/build/dev/erlang/elixir @@ -0,0 +1 @@ +/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/elixir \ No newline at end of file diff --git a/build/dev/erlang/gleam_elixir_paths b/build/dev/erlang/gleam_elixir_paths new file mode 100644 index 0000000..8eb6634 --- /dev/null +++ b/build/dev/erlang/gleam_elixir_paths @@ -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 \ No newline at end of file diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/dict.mjs b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/dict.mjs new file mode 100644 index 0000000..f39cd54 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/dict.mjs @@ -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 | IndexNode | CollisionNode} 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 | Node)[] }} ArrayNode + */ +/** + * @template K,V + * @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry | Node)[] }} IndexNode + */ +/** + * @template K,V + * @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry[] }} 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} */ +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} + */ +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} + */ +/** + * Associate a node with a new entry, creating a new node + * @template T,K,V + * @type {AssocFunction,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,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,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,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} 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} + */ +/** + * Return the found entry or undefined if not present in the root + * @template K,V + * @type {FindFunction,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,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,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} root + * @param {K} key + * @returns {undefined | Entry} + */ +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} + */ +/** + * 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,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,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,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} root + * @param {K} key + * @returns {undefined | Node} + */ +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} 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} o + * @returns {Dict} + */ + static fromObject(o) { + const keys = Object.keys(o); + /** @type Dict */ + 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} o + * @returns {Dict} + */ + static fromMap(o) { + /** @type Dict */ + 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} 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} + */ + 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} + */ + 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(); diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@@compile.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@@compile.erl new file mode 100644 index 0000000..406deee --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@@compile.erl @@ -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. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache new file mode 100644 index 0000000000000000000000000000000000000000..f85143594bf2cafb8fff5045fed12b040bf8a839 GIT binary patch literal 14219 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 XI6mbt8Lo1RvEw4%WGd5hA~*gA&qb= 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; + + <> -> + <<<>/binary, + ":size(1)"/utf8>>; + + <> -> + <<<>/binary, + ":size(2)"/utf8>>; + + <> -> + <<<>/binary, + ":size(3)"/utf8>>; + + <> -> + <<<>/binary, + ":size(4)"/utf8>>; + + <> -> + <<<>/binary, + ":size(5)"/utf8>>; + + <> -> + <<<>/binary, + ":size(6)"/utf8>>; + + <> -> + <<<>/binary, + ":size(7)"/utf8>>; + + <> -> + Suffix = case Rest of + <<>> -> + <<""/utf8>>; + + _ -> + <<", "/utf8>> + end, + Accumulator@1 = <<<>/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 + {<>, + <>} -> + 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 + <> when Pref =:= Prefix -> + true; + + _ -> + false + end. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache new file mode 100644 index 0000000000000000000000000000000000000000..c374b2dddd2b61c16b52cb67c1f67831b5f428fe GIT binary patch literal 8705 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..c6b30c1b2683f3872e215b398ff8e1deeb74bf59 GIT binary patch literal 1317 zcmX}rd58{Z90%}c@Va(fO7oI)n1&_CU`+0E&dBcCTuaJrTz}b| zgIPqb#_$IgT^!^vC0yekPpKwaFNB{+qYc9uK_1h{ zr;t4qbCgmlsp2*7s98UR)^s7AUJPUk1^me}j!{A>=cwW(pQ-Uf2#xreU+B*uMp3{@ z*0G75oTHq7so)8bL~kOQRI(VuIL1@Rc8VzG3|F|rW2$&hVgnhXEgi^a5(TVgE$i99 zZC>#ov4-->LbkAj-CX1f8nV&f1R(~^$lFq63~VlkJAHt|;s zB9k0)naxs8Q_e%46Xzq*q!0!(iQieyDz+|8SiO;?!#)%e1G%SGwl^ F`U0Q2u7v;q literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.erl new file mode 100644 index 0000000..a09a3eb --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bool.erl @@ -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. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache new file mode 100644 index 0000000000000000000000000000000000000000..e9a2e2b0b332ed46fafdf482947d40151806ebad GIT binary patch literal 12983 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.erl new file mode 100644 index 0000000..5e78e9c --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.erl @@ -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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dict.cache new file mode 100644 index 0000000000000000000000000000000000000000..aed9b4570758675bd9b598b68ae4ffae69abea6c GIT binary patch literal 24041 zcmeHPd3+nyo!5*c%a#v$JiafDWjmJTLzbRRz)f)MB;?>|6mt|qHkNHAkz-p%lH)j# zhHU9Bg|@rU(xpJVltN3{_5*F91qv-^H)J8@D7$nQC=e)6TCRp&pmej}-@9%i36D|Jir}8%mc_x$8HXsGdSg+V5$^)xJsc}@kp;wgsYeZk& zfGEFvnkd^(7v;wsS#ss+;?eD6q2Rc8By2Jd$JH-eV{wyXWGp;%)O%Je6peYeXGeoO zs8VQ`H#ixMwU39qLsQ|g5$|MhcxP~X2vw*RyhyKkW6@#t0h%3-x8rZ-;CQb^l&qd! zi_NhH4+E{DRr>0*Bn<@01woSR(nEsp;Yx>LI3|lEc~C{FL&Z_4Sm3W3s-%tBWC~=9 zRzWnO2!hFC{KmZEdhw{ztI)8*pNLEZqccimo3b-B6H|f{Bg(Ge*itm7%G)5*!;#RI@ANQ?WR;fJ*dkEI1xg zTc!^6s%pn`)};}x4G!<1p81F(6Js;f=wvh$3r)n8@Psx3B{DG_qUyBBm{c^ROhn>J zBsvm`Vg^(XGn)?1wDJklm#K;HL>!HTu^wY;&G5u_B^={##v^v>C>k0IT9E8_^TbwE9;0TiiS1@yS@X*Bj#RwMU}cy(5uf?|5(mWir;jBR)RX%r|5_ z5)IkWD>i35NRwzc+wHxVigLa%y1G!X$ZO4;SFbl)WS_Nfb%)g=zi#uae$8f)-^&?V z{eF%`ek9kk`arHl-Y5$45Xxm%LB0m%-|d3@F3N`mf^2sP@&mFUKZ!C_Cdg5gE2{ac)J6GiJ?f&|(u8Lyf8B<5P%3?b>_K^ep&rV>azP$NxnYGM|6qk6-6BeNi*hte zlrKZM+b+rnQKAyQqiik_0XzhPo5OM<9;6A}_GJ#uok)&JuR|ulj zBnI;EDM%YU(uM))+-YgUsC1fu2m3wJe!uj&9%-*#x`-ZJ<&mx$kZzimt{RoDUObP2 zOD*71v&rH(EgXwGxd<@{0ShrO{c+LUo@gm+sq!Mxg2gJBrMl6;8Z1lQfV2jmc4?Im zPy`{+fM>-*+DaOv5tb05hc!As>lA8_Zi|eKY{hDu1a-YHnQOh*q_4MM3iL>8?dTpW zk%eW#=16;Q4LnZ!GJCbm_^UK+GON-~u<&)YLi%9`wFboG)5H@r%xAlKzS*WsBGXha z_Wrw9sMr^eY#qZMaGa%#YtMM1gI|QM>8qfMW@F5opf<7O^jE^d-BNLEm@tzo$8xp%!)ho?|t&q+k5?Xd8q)GEOF8P(oU^q&W zlcXWFOXBfN+-vPKWfwL${C|AJq0{ z5S>HjE1~hp_>3}0y$nLELsCORC!SLm)YjnOAm>NBG7*|~H!ByNjH&WHwkuw*(sr_P z-WFa<8z@&W)E$;VTLdTubwbclQ)6-ZBcA{i3%U!_IBBi8%vMH1@nCq&js*zDmDrBR z)Yu4DKStFv$H>AHfGKgeYsl5A`1n}$CqX>vFgzK?6Mx3})Vp13^;QM9YFqqPeFf8X zVpZ&R(1-w7W%WqbJ_jiyom$k#H%R$IN88&~03>LTsNFU`8as;0TWJ+dHmtHqV0YM_ zwh6Tkf*-^=fwzmMLWDOIkIoDPZ8)$36$F*-;a#DL1ZigmC$R{pfBupVTvP&0B9}C(SJnWY5Wty^ zhT{Nhgh)6Eal8WLp;92HP7SsJm?Rn<0?69|dfYZO0YDg;uxErbW5IYRYCtm_!Vs2G zk;`o6OR~?lXk?u8jr+Vz1h$2fB278LSDXq#e;R)YsRZZY1jm=(WM=mlzg`SIqZ0ep zNs|pygo|JZwoICRI`9k^!+^*T!)+e26jn}4ZKDzdA1RR#l*r<>ZZ0RQJRM~V`uC-4 zVZ8;ApeWT1&8L?PlQxhd$1zs6xBl*WFxN;_Lpy^hYoc-2bl}lB*8>X_@<<`SG~Ocx z?b6^e;F^5CE(Mu!O}@s3OE7ALM8kY}Jo4SD8uN&P1l-y!3S>(Kpvg!n(!>qx0#$7G z2^;gF$D$#SbgUD63F*$cQXx7u@ToE#j_*hqDBNs;w2p?M)@jKK}~<<(wROr&1I}NOSY@5r?o#kXZso6 zJHD={L9Sk0b99=Ri^;T!lns4|lF-zfElT+w?5+Cgp!u0#sbhr%p-^D0?hD<8f>0|7 z8;^!#Te+e)nM|uJT)F%*DH1+b<>KJfUYJxaHVu{aMIvKP4b*QEtz4^Y3|tNB1hBqZ z@YU_HN?#TNaggk8Jlr9q4%$GuN0l`ph~V*X@dT)EdPfK_DN5p(B)<-s$YAADo=+Ml zz>K~=I!&D!oq`paPC?1)vk`{2z~hF}_5FFE#D0*NP$UR^R%zQrm=hr26A6XNEp#30LSSev7F9|R1Z{=%i46y%BLoj= zD^=ZWS0OWPC0tP3rp9pei( zfqxyMuj&Z+_hI_3_OH_|84N1Y$pFH!GEo(3&x5}?cCycnzin7iZsG3qf74I29VKg+ zVC^oGll#szGQTv1%u`$o(}4u3bINX;4vc`ZEmGJcg$JaWX(>D^jR~3^Tg<7rgnyPE zi#tGnap^!rZ2_HfO&blIsYJI3{Gu0iCx&Q`_Ab)^r6~I_ zKCic+m~aK&$12nez&!BPyp$~+5dt?up5KRu*9kN=!*U!|P6@?9voRMKR5g4x*g3g*!a2XKfw$w6v#E<7?z z+N-LcY+uZTtiuG8esZU~BLm`CsD+_q3u~j%NYo8x=grts?8;For%zqBgd=_*Q5eRc z(h@ApzRVV;UJtfqL&5q2BCx)FJA$#TSRs|jGT4}!cA1ODDvpK5P#H8eNx3Z zW`P0dn7+VmD)HO~;;FPr-xUI%2l4zp9$qZy!%ib04G2_a00KHyr1->%IOZa)B~XF3 zk_JjxBydQQQlgO*Vo<>YVF&oG2|W07J926Fx_eYRN0Shz&6W_i2JYnOA(OKfTT#U~ zr21I)P=96V(o=5%(i6_q?!XItn`Ia#zM5{kOh(E*nv}Rr&}Nvn&l@=4iZvw!1@x!t z9^m`QZ4=sE)vusQiw$ash1Upd69UDq=)Ju(8Y!w0AzA3I1Is& z=mT7xgd@jDHaa}aWQ!zlK5e{av&U2;>XV6R8oJ0N{wTG~4b9$(OLTf?ch_E@M_e`V>^tGA%){&_zw4p~@ zX_r=HSW8iGV&P7MtI?@hVOnU#nH0}+deHgH9Q<4pfXyN`4oK_qNg)Y}g9O}oRxV_m zRHkKktfZ_|s32{m#i2AZ8k}q9>5dr#717KGq`D!uX9O<1Rh8E zB_2N{^r(wsSj>cbs||9WM7Ih6(%oCF%6NEUib4@Hitg9qo?{(>CVj$skYtdn=|RG& z^TEj361gL3MEXcL6QWc{?j}ny86i?G)HGGyN~I&kCNwsA93HQEyCx_zXQy+!!6@db zDVc7+*5XU-)OUY<`F zl49{opY4%m?9%QGBEf77kv4F`ZpbpZ9OHrPQhWR3S0l7gK%YbQ8J@i=1PJsM>~Lnkn;MwlN@7Dy|n!!{x~ zqkC$@L;~pQ;RcTs70EkwndqzetxdW{x+F!#Cxq79Y3e-*UZLR}#{aPUoUs3bY`eks-=53mQ{Z z#5&Tdl34VsD4GH-i9h{7PNwhIXjCJvh zVQg_JYFlqXrSi=Sgh=#dG0-_y1MIKmQg!pS*DN|%zIRo9$PIS^wGA68lE?vMR+U5S$ zzJBwj6qsA4RkJj2L?;<@(Fj>rk5pg&S3 zxiZ$hu%tLqg~Sy-Pi7aY+Ia5x&T&g2k|(o-h(?`U4z((<=aJ)yL{AJYiuf3fa1xOWy4mJlSLD@(bndE_2M1~cRHOO2Gyy~+wkai}!b8;%4 z05Ajd02pe}WR6mD=8c8FOP%$cIMDQuiVfFPa|kArwlH`bt{KVi5 zW3nT%hAI<#+k9%?`#rM=CWa7LzC*OS>lket}|HQ}8f{uyimtOk(7F?ca zXgsnjv?u{aRZZqyAqcRtWhX8pLh9~OU2?0`JitF!lKBe0dMlHpGf!-3rIuvgotk9+ zZd#JLHf+P{997n3NHbUGm+Gz2p}-n$%IL}D`YE{7R1rh~U=@*3p2!L(uMeUE$CGNV zjfk2~H2Z%g*<2l)?m;-O17{{Ooo&!qQ>_iw>@FWESLG5}`t%rbNe>5Knn^1ra=l={ zrzM*&EgW?+C$S!r9*#JF9?AzLt$QxhnEW6 z&7n^|jWo}i9HF%8YMwN$u3I`ya!Xx1n4>Gh1op*Y1wB;~2NCpK$wh~n7}>>y9R00I zrygd~_bL>d9cqHeRXke2X>Vo|8f~7Ww|OFO6IhgTR1#1$q0%VWqb4TvK#z(_1@@M- zf+xCp926{9We^>}N(WK5_P5S$!(o3{WA8cDXqa{JhFdSEnm$mCdK`{g5{1N5t!>@| z2c4dNvJnY00Ve@770XCg=^w;1n3*^qb|$hVXfA2HznVK>LYp8^aPmcWv+%SP%2u5~ z3|?Dn^42Us12`x4?!zmGK8uU zIg;mzHp!1po1rD%LYTn<3l0xYjZfj&P9)l@CI@nEBy%j~PfE)y+V`>9{!~NSa0~|^ zaEy6@)Zs-A)`c0&J6cK}R(ouxT*ir!Su?}zlbq`c4h_2!pfkatiOe50=O_88`L7(n z7Ezod(9Fo+wFkVa8L0!@q!|g%Wjf#X1g_?e+vL&C`NF1VV;FV~XT`P0A-eSzfVf~H zZVr4`72V$@(QTD(R*x5a9uIN6AZ0$Yc$XjSET&X3{ruWOhdId&kxVluAL}#{)YNmI zJWG|F6S{Midn(3)bW9YskmkAIJxzxpEpW<_YU6L(2}r~fGNdum$#zH}-D9?yd(2X& z1vPyj`;XbQeS4D6d*Z3_^}kH!)+u~v*By)LtG}{zznI>F3cnM9d4uzy0knXu?F21o zi(?=N?xjsnX-IMZ(#uc+D&H_?&PNcm)%B=9o6+;hNjlxA%`q}*awNYda*XlQ8F*K1g?}!69}=Tc^FRAf z1kI8@g%8G8bB#lWS=3*QXWVfqXA44)x^jk1NVp+Zg3XWgiIqTlpsGHd*&eyjU&1G(cBiv)KcP2)z_#)H9IAQ<9PQO z7|Eb|W|ZuR?NfB1S#$nPhsj5Y^CrAze`Gx5R<%%C4my;{B6VN~*LI{P5ygg~hrTFK zGU48>9W)sZqRZXtp%X>nU514uL-UkA_T-5IIzoy-*+MUtN7oh4SO4i4HQu zLSBcbGNr#vZkENooD%m@r-d~z;L3#7q8wE{U$qkVpcR7I;6GJiscA)3E&E%D2{pH9 zuSNa!2!edlejENLPvX)uXSCmw$yz0@!p~)_>n%iBxf^MHqVzo%bdD%J;Xz1GlwR~8 z*;&+1R6y6|ESCh?y7AQBY_n8SDOHrwFWs#4OTA^%Np|xmcbZIa;}YK?Q4mbG(PVY< zg8^yJPc>QTkQN%WIwir}YcWeXE-Bw8S?%icRU(%a)T0eOT7*?*o^nrbUyFY`E-k|&?VKcmrnbtbofsI_r*N0R z{#p1JfmMnvB7RP1gUB|Dmx$~s@!v%Ds`!S;-WTm=R%)&_Gnd(GX6Ko=n_0vhGqbDA zhs^8`<|Ag-Xlb^vlPoJOY@=n+!XlPw3%k&AsfFEUxzEB5SRS>o_bqlS%d_TN*?@JQ zm3_wgBP+YxdeF)aSqrjQQI<1{b!PQuu?<>Jq!ve|!USLd+W9A^&m=bVwlMsqI8VVC7xm&1Oa^G*)? zL(Y*L)?;67XZ`kb>}9dqyrCRyXFd z2Xi0JWk1h-KbL)!Ta$;hrO7;YLEa5{>|1&7=K1q2`K&m-fL&Sel>+vB!O;R{cE}D^=4f!RRgR#8g&pG#w#RX^ zgFWJS!h!7Urb4#1a9tr=Ul=ZguljHyd%2KFtWP>cVrSzglh}6Ya}xWBbXa0nUDc%r+H&x|n^b_}XIj zkHz;Fv)>gLl(51Qse}bewwAEZmi)Yg9V~gYggsVLS<2c)s<2ctPvtq4Y( zv+B;RW83P!T*n@$d$Nv!bzQ8)b)t)1=DOO&ZgSo0Vn1`;=VAr*_4UkOzpI|@slTWm zC)n?;XV2C@U(bGB?`vS^Hf(8N;|&)yuunJquz~%u;n@cELc{MHn5*%OMs{}NKqLEl z;~kCc$BlP3vS%C1ma%oq)-Pk%F8j$c_OoTbSjL`O_QEn&(sV)-JGrT^iG8x^k|uUr z)16K1o~B2dShibnGq=0d%|7k^2RHkc`#Cpz(S6v>UUr|*%(|N|ZDt3X4>hyrnqO>Y zZ#EZuScj*_!#?F1^{}XCw})Ni`I?9Q)boIc9rid{SXoO|3-h$}wy@1D(H3?|%XKa6 znU=g(R@hq9%H-CORyN*xK`VQxwWy7q-WF(MgKZ;i?1HxMwXq{@LOaW8&u?dy?f!Ol zLVL8GeY5?McJ_Gt3+?Q+_TRO$588{otjW8<%g*%f^|F25i@ofN-kZGa4)2p*_MG<( zFZ+|Xr-QBTSlhu)>G)Cy`+CO>9qe$&s~zk}N4AgU`Of#TLEj!9`=;*}AG_0c(8r$h zz3pS~`#$oq_5SUCw$uMDKRe+6S3i5+f7s7n@&CrpI@yVgUCItJc8ERC*h}m!#%elG z?PPm9Z|`LHbl%s=9`Ag)lYP)x+{Ko4ZRuk1t~=utAkTiWm5# zUz_E}?6=ZM3vLK|b$r%)qgj4k@S}K8%H$7(0r^kDkSvHza-BFJH;SWjv$$M77x!Dl zZj>f@FYfo_e!o~IUxE9pP`--$?}&b_l*xDD*}W+DqyCGyz9MdxU&nopc|guL_o0-@ zHMp-cZ7W zp`0Uc!F|x`M=6sp!2OhUqdbHA&*A#-rfLxK) zjq+{zF5KUn6_xML!rXEHN>(3AlWesO$T_xAIp4NiUWxl&n+K&eSQ+@FQ}5bndc z58ImL&*A}zBxdz~D>{aM*)CmZeHK8*Wt z_BrxhxW6~M8>P(2cc1HI3hibifeO)}6RNwbjj&jSyxOmQ&`$ys3aG4p3TAe3{pIy| z@BI4h^~U#%XI1DZP&t1qN&H1%=Tx7cwkWBgve|>1%H5ZX!FA>K znyot$BFAB&R$Fmnvs1ZDgM8ka77;_1~lsZMqL) zuEG5z=aC#V?#k&vtNxsV9OKwvU@m5CEd}ib7{<49ze9WWedp~ow#!?-NJKW$wcSW$ zY6_gbs_4AOwZr+1~5E-;F6T_wqDZrHa;Gw@4?qaNKQ4pJ@46 z$4d?j`SF~8B{F#0`5&~@KdXP31oQV=en>0+TFaYsdA{gn{FDYexq1x_HnGdQuIR$$ z;jVu%?gnK7@Ia3CBMa$MGPC_fU!-<=i_R!Au0GzRM9tZ6{J8d~wRj^|yQkLh2K7a6 zEFfM^Q$D3&rfz2^&F#b5ET^Fr{^KAiTNCx~(nW-}HGEXMo-?y$wI1U*c;4~sVLxsD z6&!QyL(6{~$&7}r$J1xORk^Hw8Q!|S@jH!9Ri$t%o6LCdGc@3=Pt?9M_g>Rm*SH~YWq$EBxhwQqcpkKd|^wTqtFLczzTQ$~p46xIY*0 z?OedOFz&;Eeqn2qx?lW^XYVFax?aFf2mR$gu?oMkJx9Xn*V%{Ruw*?stBJQ?D*g=| znXIX#h4$wYB|UUmS8^&{-Yj{SE|${lQd|m4i|MkZJV-+AVEG}sJYW72U4C2sCS5*N zdp@z`W3^AvWx)AYM0d}*UL^4sa);fxe8qc>Q3`UmPw(TRd_5wQSEKy@_5b8LfR|4c zS0LM&yIhvp$rt)LTjUU0MGXy4+TOJ6&Rp(_}MT(RdYI+Lrl9 zMz2`5iY}|&>xkYja8J>ttK}pTzSAui(k07lCzQ6=zu%9`Go8cj!{lRin!) z9gAwwk94gdN|g#;2)1l*QDuw`2Z$0P4T%fpcg>pcp&u_RYcUv1au{4hgg;g%Ny2gbHF!8pllb^Bv#Q z()&sDU>L($#sz+*f@@R}RV#$%v>|~Wyh0k8%wa7h+@X@h+97n|37%p&lgVU0Z;{Jx zia5m?s)%|hg!(jKB1?FOula^zN@)0S2+_pTmw^mpBpWH>IOm9~V}BUUSQb)11y@O` zD=xCx#8yu6FLCw6PCUIC#SF4p&PHzV7k8*6IVyy~yvPKm@c~=-gwH6XoJ#Hy9toij z&oPow%qE{>oZuu?+@rNZ8OJQL*v3x&CNv14Hcg2ok&&b_opk20nLQlfFxTnOP=1+2 z9v@Q118Ox2A%+%o;2EZnP6mtE#c9s*Go2cTFob7GA)S08l+&k42!j~PcqWp@dmJFb zHExj{?LL!8WiiLNOI(aR5zh!lvz6N!-vq~@a`bS8r= z<}jC&Tq439{-Jiu5V|sf1uSJ5tJp^wQLU^?a}s%ysk})ZYgo&E?$bIhgr1CHIy1>+ z7VG(#4cw%DYx_rAI?#&=%wPqpSw}v_R1ni9gjU3p#Y$F@$6l&Ph&LaJ^k+CznMW?W zILa;RwDk$lgiiEhAvr8zDJ7gIzMbB|5XSK`ud#-soTpxbxoF1YEN4ACIK*L!XxLsa zrZ@9gL^e4b;v!{SqE`oNkxB+xEM^Zsagod1AR$pdU_2AqOac2S6M0|z+F zk6hp~%{tjTo@Nlwvy9yoa*)&1?JR$ErW=b{$4*MQLWFYqcTv0KQcMY@T;V27yQ&?M zd5Ia!W&zo3;#-aqp;3}pXhl~B@&dD2#zualem8YSG%-vggDj2{-CfUP43n8g7N1i| zjmPAb2DGF%{h7^nPIH#aT;)1= 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 + ). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache new file mode 100644 index 0000000000000000000000000000000000000000..66b9dcdc5937dc54540010db8bf932c355454540 GIT binary patch literal 6989 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 J=j30@{{weZO?dzS literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..19152c51c7d712e4fa9dba99d89b742e777acb72 GIT binary patch literal 479 zcmXZYKTCpP6o&EJO09IMD3H*Wh{VdVG6)QcS{vLN`txFo`XVW!PBZXzmaK^#e3po$jS81I!P5yL6U zc!0Z4n#BV0DBvF7@DpzUDIBAS8tVAMgooU)iZx_$h$mD~MFTdPXd&p8ws2$+{eS%d D2v|PD literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.erl new file mode 100644 index 0000000..027b403 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic.erl @@ -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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache new file mode 100644 index 0000000000000000000000000000000000000000..833037b3739674a7a7fd6eb0163bdaed618892bd GIT binary patch literal 57064 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 BPwfBz literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.erl new file mode 100644 index 0000000..fc66d91 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.erl @@ -0,0 +1,1083 @@ +-module(gleam@dynamic@decode). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleam/dynamic/decode.gleam"). +-export([run/2, success/1, decode_dynamic/1, map/2, map_errors/2, then/2, one_of/2, recursive/1, optional/1, decode_error/2, decode_bool/1, decode_int/1, decode_float/1, decode_bit_array/1, collapse_errors/2, failure/2, new_primitive_decoder/2, decode_string/1, dict/2, list/1, subfield/3, at/2, field/3, optional_field/4, optionally_at/3]). +-export_type([decode_error/0, decoder/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( + " The `Dynamic` type is used to represent dynamically typed data. That is, data\n" + " that we don't know the precise type of yet, so we need to introspect the data to\n" + " see if it is of the desired type before we can use it. Typically data like this\n" + " would come from user input or from untyped languages such as Erlang or JavaScript.\n" + "\n" + " This module provides the `Decoder` type and associated functions, which provides\n" + " a type-safe and composable way to convert dynamic data into some desired type,\n" + " or into errors if the data doesn't have the desired structure.\n" + "\n" + " The `Decoder` type is generic and has 1 type parameter, which is the type that\n" + " it attempts to decode. A `Decoder(String)` can be used to decode strings, and a\n" + " `Decoder(Option(Int))` can be used to decode `Option(Int)`s\n" + "\n" + " Decoders work using _runtime reflection_ and the data structures of the target\n" + " platform. Differences between Erlang and JavaScript data structures may impact\n" + " your decoders, so it is important to test your decoders on all supported\n" + " platforms.\n" + "\n" + " The decoding technique used by this module was inspired by Juraj Petráš'\n" + " [Toy](https://github.com/Hackder/toy), Go's `encoding/json`, and Elm's\n" + " `Json.Decode`. Thank you to them!\n" + "\n" + " # Examples\n" + "\n" + " Dynamic data may come from various sources and so many different syntaxes could\n" + " be used to describe or construct them. In these examples a pseudocode\n" + " syntax is used to describe the data.\n" + "\n" + " ## Simple types\n" + "\n" + " This module defines decoders for simple data types such as [`string`](#string),\n" + " [`int`](#int), [`float`](#float), [`bit_array`](#bit_array), and [`bool`](#bool).\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // \"Hello, Joe!\"\n" + "\n" + " let result = decode.run(data, decode.string)\n" + " assert result == Ok(\"Hello, Joe!\")\n" + " ```\n" + "\n" + " ## Lists\n" + "\n" + " The [`list`](#list) decoder decodes `List`s. To use it you must construct it by\n" + " passing in another decoder into the `list` function, which is the decoder that\n" + " is to be used for the elements of the list, type checking both the list and its\n" + " elements.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // [1, 2, 3, 4]\n" + "\n" + " let result = decode.run(data, decode.list(decode.int))\n" + " assert result == Ok([1, 2, 3, 4])\n" + " ```\n" + "\n" + " On Erlang this decoder can decode from lists, and on JavaScript it can\n" + " decode from lists as well as JavaScript arrays.\n" + "\n" + " ## Options\n" + "\n" + " The [`optional`](#optional) decoder is used to decode values that may or may not\n" + " be present. In other environment these might be called \"nullable\" values.\n" + "\n" + " Like the `list` decoder, the `optional` decoder takes another decoder,\n" + " which is used to decode the value if it is present.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // 12.45\n" + "\n" + " let result = decode.run(data, decode.optional(decode.float))\n" + " assert result == Ok(option.Some(12.45))\n" + " ```\n" + " ```gleam\n" + " // Data:\n" + " // null\n" + "\n" + " let result = decode.run(data, decode.optional(decode.int))\n" + " assert result == Ok(option.None)\n" + " ```\n" + "\n" + " This decoder knows how to handle multiple different runtime representations of\n" + " absent values, including `Nil`, `None`, `null`, and `undefined`.\n" + "\n" + " ## Dicts\n" + "\n" + " The [`dict`](#dict) decoder decodes `Dicts` and contains two other decoders, one\n" + " for the keys, one for the values.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // { \"Lucy\" -> 10, \"Nubi\" -> 20 }\n" + "\n" + " let result = decode.run(data, decode.dict(decode.string, decode.int))\n" + " assert result == Ok(dict.from_list([\n" + " #(\"Lucy\", 10),\n" + " #(\"Nubi\", 20),\n" + " ]))\n" + " ```\n" + "\n" + " ## Indexing objects\n" + "\n" + " The [`at`](#at) decoder can be used to decode a value that is nested within\n" + " key-value containers such as Gleam dicts, Erlang maps, or JavaScript objects.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // { \"one\" -> { \"two\" -> 123 } }\n" + "\n" + " let result = decode.run(data, decode.at([\"one\", \"two\"], decode.int))\n" + " assert result == Ok(123)\n" + " ```\n" + "\n" + " ## Indexing arrays\n" + "\n" + " If you use ints as keys then the [`at`](#at) decoder can be used to index into\n" + " array-like containers such as Gleam or Erlang tuples, or JavaScript arrays.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // [\"one\", \"two\", \"three\"]\n" + "\n" + " let result = decode.run(data, decode.at([1], decode.string))\n" + " assert result == Ok(\"two\")\n" + " ```\n" + "\n" + " ## Records\n" + "\n" + " Decoding records from dynamic data is more complex and requires combining a\n" + " decoder for each field and a special constructor that builds your records with\n" + " the decoded field values.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // {\n" + " // \"score\" -> 180,\n" + " // \"name\" -> \"Mel Smith\",\n" + " // \"is-admin\" -> false,\n" + " // \"enrolled\" -> true,\n" + " // \"colour\" -> \"Red\",\n" + " // }\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", decode.string)\n" + " use score <- decode.field(\"score\", decode.int)\n" + " use colour <- decode.field(\"colour\", decode.string)\n" + " use enrolled <- decode.field(\"enrolled\", decode.bool)\n" + " decode.success(Player(name:, score:, colour:, enrolled:))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(Player(\"Mel Smith\", 180, \"Red\", True))\n" + " ```\n" + "\n" + " ## Enum variants\n" + "\n" + " Imagine you have a custom type where all the variants do not contain any values.\n" + "\n" + " ```gleam\n" + " pub type PocketMonsterType {\n" + " Fire\n" + " Water\n" + " Grass\n" + " Electric\n" + " }\n" + " ```\n" + "\n" + " You might choose to encode these variants as strings, `\"fire\"` for `Fire`,\n" + " `\"water\"` for `Water`, and so on. To decode them you'll need to decode the dynamic\n" + " data as a string, but then you'll need to decode it further still as not all\n" + " strings are valid values for the enum. This can be done with the `then`\n" + " function, which enables running a second decoder after the first one\n" + " succeeds.\n" + "\n" + " ```gleam\n" + " let decoder = {\n" + " use decoded_string <- decode.then(decode.string)\n" + " case decoded_string {\n" + " // Return succeeding decoders for valid strings\n" + " \"fire\" -> decode.success(Fire)\n" + " \"water\" -> decode.success(Water)\n" + " \"grass\" -> decode.success(Grass)\n" + " \"electric\" -> decode.success(Electric)\n" + " // Return a failing decoder for any other strings\n" + " _ -> decode.failure(Fire, \"PocketMonsterType\")\n" + " }\n" + " }\n" + "\n" + " let result = decode.run(dynamic.from(\"water\"), decoder)\n" + " assert result == Ok(Water)\n" + "\n" + " let result = decode.run(dynamic.from(\"wobble\"), decoder)\n" + " assert result == Error([DecodeError(\"PocketMonsterType\", \"String\", [])])\n" + " ```\n" + "\n" + " ## Record variants\n" + "\n" + " Decoding type variants that contain other values is done by combining the\n" + " techniques from the \"enum variants\" and \"records\" examples. Imagine you have\n" + " this custom type that you want to decode:\n" + "\n" + " ```gleam\n" + " pub type PocketMonsterPerson {\n" + " Trainer(name: String, badge_count: Int)\n" + " GymLeader(name: String, speciality: PocketMonsterType)\n" + " }\n" + " ```\n" + " And you would like to be able to decode these from dynamic data like this:\n" + " ```erlang\n" + " {\n" + " \"type\" -> \"trainer\",\n" + " \"name\" -> \"Ash\",\n" + " \"badge-count\" -> 1,\n" + " }\n" + " ```\n" + " ```erlang\n" + " {\n" + " \"type\" -> \"gym-leader\",\n" + " \"name\" -> \"Misty\",\n" + " \"speciality\" -> \"water\",\n" + " }\n" + " ```\n" + "\n" + " Notice how both documents have a `\"type\"` field, which is used to indicate which\n" + " variant the data is for.\n" + "\n" + " First, define decoders for each of the variants:\n" + "\n" + " ```gleam\n" + " let trainer_decoder = {\n" + " use name <- decode.field(\"name\", decode.string)\n" + " use badge_count <- decode.field(\"badge-count\", decode.int)\n" + " decode.success(Trainer(name, badge_count))\n" + " }\n" + "\n" + " let gym_leader_decoder = {\n" + " use name <- decode.field(\"name\", decode.string)\n" + " use speciality <- decode.field(\"speciality\", pocket_monster_type_decoder)\n" + " decode.success(GymLeader(name, speciality))\n" + " }\n" + " ```\n" + "\n" + " A third decoder can be used to extract and decode the `\"type\"` field, and the\n" + " expression can evaluate to whichever decoder is suitable for the document.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // {\n" + " // \"type\" -> \"gym-leader\",\n" + " // \"name\" -> \"Misty\",\n" + " // \"speciality\" -> \"water\",\n" + " // }\n" + "\n" + " let decoder = {\n" + " use tag <- decode.field(\"type\", decode.string)\n" + " case tag {\n" + " \"gym-leader\" -> gym_leader_decoder\n" + " _ -> trainer_decoder\n" + " }\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(GymLeader(\"Misty\", Water))\n" + " ```\n" +). + +-type decode_error() :: {decode_error, binary(), binary(), list(binary())}. + +-opaque decoder(BXN) :: {decoder, + fun((gleam@dynamic:dynamic_()) -> {BXN, list(decode_error())})}. + +-file("src/gleam/dynamic/decode.gleam", 356). +?DOC( + " Run a decoder on a `Dynamic` value, decoding the value if it is of the\n" + " desired type, or returning errors.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = {\n" + " use name <- decode.field(\"email\", decode.string)\n" + " use email <- decode.field(\"password\", decode.string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " decode.run(data, decoder)\n" + " ```\n" +). +-spec run(gleam@dynamic:dynamic_(), decoder(BXV)) -> {ok, BXV} | + {error, list(decode_error())}. +run(Data, Decoder) -> + {Maybe_invalid_data, Errors} = (erlang:element(2, Decoder))(Data), + case Errors of + [] -> + {ok, Maybe_invalid_data}; + + [_ | _] -> + {error, Errors} + end. + +-file("src/gleam/dynamic/decode.gleam", 478). +?DOC( + " Finalise a decoder having successfully extracted a value.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"email\", \"lucy@example.com\"),\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", string)\n" + " use email <- decode.field(\"email\", string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" + " ```\n" +). +-spec success(BYW) -> decoder(BYW). +success(Data) -> + {decoder, fun(_) -> {Data, []} end}. + +-file("src/gleam/dynamic/decode.gleam", 717). +-spec decode_dynamic(gleam@dynamic:dynamic_()) -> {gleam@dynamic:dynamic_(), + list(decode_error())}. +decode_dynamic(Data) -> + {Data, []}. + +-file("src/gleam/dynamic/decode.gleam", 871). +?DOC( + " Apply a transformation function to any value decoded by the decoder.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.int |> decode.map(int.to_string)\n" + " let result = decode.run(dynamic.from(1000), decoder)\n" + " assert result == Ok(\"1000\")\n" + " ```\n" +). +-spec map(decoder(CBT), fun((CBT) -> CBV)) -> decoder(CBV). +map(Decoder, Transformer) -> + {decoder, + fun(D) -> + {Data, Errors} = (erlang:element(2, Decoder))(D), + {Transformer(Data), Errors} + end}. + +-file("src/gleam/dynamic/decode.gleam", 880). +?DOC(" Apply a transformation function to any errors returned by the decoder.\n"). +-spec map_errors( + decoder(CBX), + fun((list(decode_error())) -> list(decode_error())) +) -> decoder(CBX). +map_errors(Decoder, Transformer) -> + {decoder, + fun(D) -> + {Data, Errors} = (erlang:element(2, Decoder))(D), + {Data, Transformer(Errors)} + end}. + +-file("src/gleam/dynamic/decode.gleam", 918). +?DOC( + " Create a new decoder based upon the value of a previous decoder.\n" + "\n" + " This may be useful to run one previous decoder to use in further decoding.\n" +). +-spec then(decoder(CCF), fun((CCF) -> decoder(CCH))) -> decoder(CCH). +then(Decoder, Next) -> + {decoder, + fun(Dynamic_data) -> + {Data, Errors} = (erlang:element(2, Decoder))(Dynamic_data), + Decoder@1 = Next(Data), + {Data@1, _} = Layer = (erlang:element(2, Decoder@1))(Dynamic_data), + case Errors of + [] -> + Layer; + + [_ | _] -> + {Data@1, Errors} + end + end}. + +-file("src/gleam/dynamic/decode.gleam", 961). +-spec run_decoders( + gleam@dynamic:dynamic_(), + {CCP, list(decode_error())}, + list(decoder(CCP)) +) -> {CCP, list(decode_error())}. +run_decoders(Data, Failure, Decoders) -> + case Decoders of + [] -> + Failure; + + [Decoder | Decoders@1] -> + {_, Errors} = Layer = (erlang:element(2, Decoder))(Data), + case Errors of + [] -> + Layer; + + [_ | _] -> + run_decoders(Data, Failure, Decoders@1) + end + end. + +-file("src/gleam/dynamic/decode.gleam", 948). +?DOC( + " Create a new decoder from several other decoders. Each of the inner\n" + " decoders is run in turn, and the value from the first to succeed is used.\n" + "\n" + " If no decoder succeeds then the errors from the first decoder is used.\n" + " If you wish for different errors then you may wish to use the\n" + " `collapse_errors` or `map_errors` functions.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.one_of(decode.string, or: [\n" + " decode.int |> decode.map(int.to_string),\n" + " decode.float |> decode.map(float.to_string),\n" + " ])\n" + " decode.run(dynamic.from(1000), decoder)\n" + " // -> Ok(\"1000\")\n" + " ```\n" +). +-spec one_of(decoder(CCK), list(decoder(CCK))) -> decoder(CCK). +one_of(First, Alternatives) -> + {decoder, + fun(Dynamic_data) -> + {_, Errors} = Layer = (erlang:element(2, First))(Dynamic_data), + case Errors of + [] -> + Layer; + + [_ | _] -> + run_decoders(Dynamic_data, Layer, Alternatives) + end + end}. + +-file("src/gleam/dynamic/decode.gleam", 1044). +?DOC( + " Create a decoder that can refer to itself, useful for decoding deeply\n" + " nested data.\n" + "\n" + " Attempting to create a recursive decoder without this function could result\n" + " in an infinite loop. If you are using `field` or other `use`able functions\n" + " then you may not need to use this function.\n" + "\n" + " ```gleam\n" + " type Nested {\n" + " Nested(List(Nested))\n" + " Value(String)\n" + " }\n" + "\n" + " fn nested_decoder() -> decode.Decoder(Nested) {\n" + " use <- decode.recursive\n" + " decode.one_of(decode.string |> decode.map(Value), [\n" + " decode.list(nested_decoder()) |> decode.map(Nested),\n" + " ])\n" + " }\n" + " ```\n" +). +-spec recursive(fun(() -> decoder(CDA))) -> decoder(CDA). +recursive(Inner) -> + {decoder, + fun(Data) -> + Decoder = Inner(), + (erlang:element(2, Decoder))(Data) + end}. + +-file("src/gleam/dynamic/decode.gleam", 849). +?DOC( + " A decoder that decodes nullable values of a type decoded by with a given\n" + " decoder.\n" + "\n" + " This function can handle common representations of null on all runtimes, such as\n" + " `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on\n" + " JavaScript.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let result = decode.run(dynamic.from(100), decode.optional(decode.int))\n" + " assert result == Ok(option.Some(100))\n" + " ```\n" + "\n" + " ```gleam\n" + " let result = decode.run(dynamic.from(Nil), decode.optional(decode.int))\n" + " assert result == Ok(option.None)\n" + " ```\n" +). +-spec optional(decoder(CBP)) -> decoder(gleam@option:option(CBP)). +optional(Inner) -> + {decoder, fun(Data) -> case gleam_stdlib:is_null(Data) of + true -> + {none, []}; + + false -> + {Data@1, Errors} = (erlang:element(2, Inner))(Data), + {{some, Data@1}, Errors} + end end}. + +-file("src/gleam/dynamic/decode.gleam", 484). +?DOC(" Construct a decode error for some unexpected dynamic data.\n"). +-spec decode_error(binary(), gleam@dynamic:dynamic_()) -> list(decode_error()). +decode_error(Expected, Found) -> + [{decode_error, Expected, gleam_stdlib:classify_dynamic(Found), []}]. + +-file("src/gleam/dynamic/decode.gleam", 608). +-spec run_dynamic_function( + gleam@dynamic:dynamic_(), + binary(), + fun((gleam@dynamic:dynamic_()) -> {ok, BZQ} | {error, BZQ}) +) -> {BZQ, list(decode_error())}. +run_dynamic_function(Data, Name, F) -> + case F(Data) of + {ok, Data@1} -> + {Data@1, []}; + + {error, Zero} -> + {Zero, + [{decode_error, Name, gleam_stdlib:classify_dynamic(Data), []}]} + end. + +-file("src/gleam/dynamic/decode.gleam", 657). +-spec decode_bool(gleam@dynamic:dynamic_()) -> {boolean(), list(decode_error())}. +decode_bool(Data) -> + case gleam_stdlib:identity(true) =:= Data of + true -> + {true, []}; + + false -> + case gleam_stdlib:identity(false) =:= Data of + true -> + {false, []}; + + false -> + {false, decode_error(<<"Bool"/utf8>>, Data)} + end + end. + +-file("src/gleam/dynamic/decode.gleam", 679). +-spec decode_int(gleam@dynamic:dynamic_()) -> {integer(), list(decode_error())}. +decode_int(Data) -> + run_dynamic_function(Data, <<"Int"/utf8>>, fun gleam_stdlib:int/1). + +-file("src/gleam/dynamic/decode.gleam", 698). +-spec decode_float(gleam@dynamic:dynamic_()) -> {float(), list(decode_error())}. +decode_float(Data) -> + run_dynamic_function(Data, <<"Float"/utf8>>, fun gleam_stdlib:float/1). + +-file("src/gleam/dynamic/decode.gleam", 732). +-spec decode_bit_array(gleam@dynamic:dynamic_()) -> {bitstring(), + list(decode_error())}. +decode_bit_array(Data) -> + run_dynamic_function( + Data, + <<"BitArray"/utf8>>, + fun gleam_stdlib:bit_array/1 + ). + +-file("src/gleam/dynamic/decode.gleam", 904). +?DOC( + " Replace all errors produced by a decoder with one single error for a named\n" + " expected type.\n" + "\n" + " This function may be useful if you wish to simplify errors before\n" + " presenting them to a user, particularly when using the `one_of` function.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.string |> decode.collapse_errors(\"MyThing\")\n" + " let result = decode.run(dynamic.from(1000), decoder)\n" + " assert result == Error([DecodeError(\"MyThing\", \"Int\", [])])\n" + " ```\n" +). +-spec collapse_errors(decoder(CCC), binary()) -> decoder(CCC). +collapse_errors(Decoder, Name) -> + {decoder, + fun(Dynamic_data) -> + {Data, Errors} = Layer = (erlang:element(2, Decoder))(Dynamic_data), + case Errors of + [] -> + Layer; + + [_ | _] -> + {Data, decode_error(Name, Dynamic_data)} + end + end}. + +-file("src/gleam/dynamic/decode.gleam", 982). +?DOC( + " Define a decoder that always fails. The parameter for this function is the\n" + " name of the type that has failed to decode.\n" +). +-spec failure(CCU, binary()) -> decoder(CCU). +failure(Zero, Expected) -> + {decoder, fun(D) -> {Zero, decode_error(Expected, D)} end}. + +-file("src/gleam/dynamic/decode.gleam", 1011). +?DOC( + " Create a decoder for a new data type from a decoding function.\n" + "\n" + " This function is used for new primitive types. For example, you might\n" + " define a decoder for Erlang's pid type.\n" + "\n" + " A default \"zero\" value is also required to make a decoder. When this\n" + " decoder is used as part of a larger decoder this zero value used as\n" + " a placeholder so that the rest of the decoder can continue to run and\n" + " collect all decoding errors.\n" + "\n" + " If you were to make a decoder for the `String` type (rather than using the\n" + " build-in `string` decoder) you would define it like so:\n" + "\n" + " ```gleam\n" + " pub fn string_decoder() -> decode.Decoder(String) {\n" + " let default = \"\"\n" + " decode.new_primitive_decoder(\"String\", fn(data) {\n" + " case dynamic.string(data) {\n" + " Ok(x) -> Ok(x)\n" + " Error(_) -> Error(default)\n" + " }\n" + " })\n" + " }\n" + " ```\n" +). +-spec new_primitive_decoder( + binary(), + fun((gleam@dynamic:dynamic_()) -> {ok, CCW} | {error, CCW}) +) -> decoder(CCW). +new_primitive_decoder(Name, Decoding_function) -> + {decoder, fun(D) -> case Decoding_function(D) of + {ok, T} -> + {T, []}; + + {error, Zero} -> + {Zero, + [{decode_error, + Name, + gleam_stdlib:classify_dynamic(D), + []}]} + end end}. + +-file("src/gleam/dynamic/decode.gleam", 635). +-spec dynamic_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | + {error, binary()}. +dynamic_string(Data) -> + case gleam_stdlib:bit_array(Data) of + {ok, Data@1} -> + case gleam@bit_array:to_string(Data@1) of + {ok, String} -> + {ok, String}; + + {error, _} -> + {error, <<""/utf8>>} + end; + + {error, _} -> + {error, <<""/utf8>>} + end. + +-file("src/gleam/dynamic/decode.gleam", 630). +-spec decode_string(gleam@dynamic:dynamic_()) -> {binary(), + list(decode_error())}. +decode_string(Data) -> + run_dynamic_function(Data, <<"String"/utf8>>, fun dynamic_string/1). + +-file("src/gleam/dynamic/decode.gleam", 803). +-spec fold_dict( + {gleam@dict:dict(CBB, CBC), list(decode_error())}, + gleam@dynamic:dynamic_(), + gleam@dynamic:dynamic_(), + fun((gleam@dynamic:dynamic_()) -> {CBB, list(decode_error())}), + fun((gleam@dynamic:dynamic_()) -> {CBC, list(decode_error())}) +) -> {gleam@dict:dict(CBB, CBC), list(decode_error())}. +fold_dict(Acc, Key, Value, Key_decoder, Value_decoder) -> + case Key_decoder(Key) of + {Key@1, []} -> + case Value_decoder(Value) of + {Value@1, []} -> + Dict = gleam@dict:insert( + erlang:element(1, Acc), + Key@1, + Value@1 + ), + {Dict, erlang:element(2, Acc)}; + + {_, Errors} -> + push_path({maps:new(), Errors}, [<<"values"/utf8>>]) + end; + + {_, Errors@1} -> + push_path({maps:new(), Errors@1}, [<<"keys"/utf8>>]) + end. + +-file("src/gleam/dynamic/decode.gleam", 783). +?DOC( + " A decoder that decodes dicts where all keys and vales are decoded with\n" + " given decoders.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let values = dict.from_list([\n" + " #(\"one\", 1),\n" + " #(\"two\", 2),\n" + " ])\n" + "\n" + " let result =\n" + " decode.run(dynamic.from(values), decode.dict(decode.string, decode.int))\n" + " assert result == Ok(values)\n" + " ```\n" +). +-spec dict(decoder(CAU), decoder(CAW)) -> decoder(gleam@dict:dict(CAU, CAW)). +dict(Key, Value) -> + {decoder, fun(Data) -> case gleam_stdlib:dict(Data) of + {error, _} -> + {maps:new(), decode_error(<<"Dict"/utf8>>, Data)}; + + {ok, Dict} -> + gleam@dict:fold( + Dict, + {maps:new(), []}, + fun(A, K, V) -> case erlang:element(2, A) of + [] -> + fold_dict( + A, + K, + V, + erlang:element(2, Key), + erlang:element(2, Value) + ); + + [_ | _] -> + A + end end + ) + end end}. + +-file("src/gleam/dynamic/decode.gleam", 751). +?DOC( + " A decoder that decodes lists where all elements are decoded with a given\n" + " decoder.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let result =\n" + " decode.run(dynamic.from([1, 2, 3]), decode.list(of: decode.int))\n" + " assert result == Ok([1, 2, 3])\n" + " ```\n" +). +-spec list(decoder(CAI)) -> decoder(list(CAI)). +list(Inner) -> + {decoder, + fun(Data) -> + gleam_stdlib:list( + Data, + erlang:element(2, Inner), + fun(P, K) -> push_path(P, [K]) end, + 0, + [] + ) + end}. + +-file("src/gleam/dynamic/decode.gleam", 438). +-spec push_path({BYR, list(decode_error())}, list(any())) -> {BYR, + list(decode_error())}. +push_path(Layer, Path) -> + Decoder = one_of( + {decoder, fun decode_string/1}, + [begin + _pipe = {decoder, fun decode_int/1}, + map(_pipe, fun erlang:integer_to_binary/1) + end] + ), + Path@1 = gleam@list:map( + Path, + fun(Key) -> + Key@1 = gleam_stdlib:identity(Key), + case run(Key@1, Decoder) of + {ok, Key@2} -> + Key@2; + + {error, _} -> + <<<<"<"/utf8, + (gleam_stdlib:classify_dynamic(Key@1))/binary>>/binary, + ">"/utf8>> + end + end + ), + Errors = gleam@list:map( + erlang:element(2, Layer), + fun(Error) -> _record = Error, + {decode_error, + erlang:element(2, _record), + erlang:element(3, _record), + lists:append(Path@1, erlang:element(4, Error))} end + ), + {erlang:element(1, Layer), Errors}. + +-file("src/gleam/dynamic/decode.gleam", 403). +-spec index( + list(BYF), + list(BYF), + fun((gleam@dynamic:dynamic_()) -> {BYI, list(decode_error())}), + gleam@dynamic:dynamic_(), + fun((gleam@dynamic:dynamic_(), list(BYF)) -> {BYI, list(decode_error())}) +) -> {BYI, list(decode_error())}. +index(Path, Position, Inner, Data, Handle_miss) -> + case Path of + [] -> + _pipe = Inner(Data), + push_path(_pipe, lists:reverse(Position)); + + [Key | Path@1] -> + case gleam_stdlib:index(Data, Key) of + {ok, {some, Data@1}} -> + index(Path@1, [Key | Position], Inner, Data@1, Handle_miss); + + {ok, none} -> + Handle_miss(Data, [Key | Position]); + + {error, Kind} -> + {Default, _} = Inner(Data), + _pipe@1 = {Default, + [{decode_error, + Kind, + gleam_stdlib:classify_dynamic(Data), + []}]}, + push_path(_pipe@1, lists:reverse(Position)) + end + end. + +-file("src/gleam/dynamic/decode.gleam", 324). +?DOC( + " The same as [`field`](#field), except taking a path to the value rather\n" + " than a field name.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"data\", dict.from_list([\n" + " #(\"email\", \"lucy@example.com\"),\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.subfield([\"data\", \"name\"], decode.string)\n" + " use email <- decode.subfield([\"data\", \"email\"], decode.string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" + " ```\n" +). +-spec subfield(list(any()), decoder(BXQ), fun((BXQ) -> decoder(BXS))) -> decoder(BXS). +subfield(Field_path, Field_decoder, Next) -> + {decoder, + fun(Data) -> + {Out, Errors1} = index( + Field_path, + [], + erlang:element(2, Field_decoder), + Data, + fun(Data@1, Position) -> + {Default, _} = (erlang:element(2, Field_decoder))(Data@1), + _pipe = {Default, + [{decode_error, + <<"Field"/utf8>>, + <<"Nothing"/utf8>>, + []}]}, + push_path(_pipe, lists:reverse(Position)) + end + ), + {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), + {Out@1, lists:append(Errors1, Errors2)} + end}. + +-file("src/gleam/dynamic/decode.gleam", 393). +?DOC( + " A decoder that decodes a value that is nested within other values. For\n" + " example, decoding a value that is within some deeply nested JSON objects.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.at([\"one\", \"two\"], decode.int)\n" + "\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"one\", dict.from_list([\n" + " #(\"two\", 1000),\n" + " ])),\n" + " ]))\n" + "\n" + "\n" + " decode.run(data, decoder)\n" + " // -> Ok(1000)\n" + " ```\n" + "\n" + " ```gleam\n" + " dynamic.from(Nil)\n" + " |> decode.run(decode.optional(decode.int))\n" + " // -> Ok(option.None)\n" + " ```\n" +). +-spec at(list(any()), decoder(BYC)) -> decoder(BYC). +at(Path, Inner) -> + {decoder, + fun(Data) -> + index( + Path, + [], + erlang:element(2, Inner), + Data, + fun(Data@1, Position) -> + {Default, _} = (erlang:element(2, Inner))(Data@1), + _pipe = {Default, + [{decode_error, + <<"Field"/utf8>>, + <<"Nothing"/utf8>>, + []}]}, + push_path(_pipe, lists:reverse(Position)) + end + ) + end}. + +-file("src/gleam/dynamic/decode.gleam", 523). +?DOC( + " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" + " of the desired type, or returning errors. An error is returned if there is\n" + " no field for the specified key.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"email\", \"lucy@example.com\"),\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", string)\n" + " use email <- decode.field(\"email\", string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" + " ```\n" + "\n" + " If you wish to decode a value that is more deeply nested within the dynamic\n" + " data, see [`subfield`](#subfield) and [`at`](#at).\n" + "\n" + " If you wish to return a default in the event that a field is not present,\n" + " see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).\n" +). +-spec field(any(), decoder(BZA), fun((BZA) -> decoder(BZC))) -> decoder(BZC). +field(Field_name, Field_decoder, Next) -> + subfield([Field_name], Field_decoder, Next). + +-file("src/gleam/dynamic/decode.gleam", 556). +?DOC( + " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" + " of the desired type, or returning errors. The given default value is\n" + " returned if there is no field for the specified key.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", string)\n" + " use email <- decode.optional_field(\"email\", \"n/a\", string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"n/a\"))\n" + " ```\n" +). +-spec optional_field(any(), BZG, decoder(BZG), fun((BZG) -> decoder(BZI))) -> decoder(BZI). +optional_field(Key, Default, Field_decoder, Next) -> + {decoder, + fun(Data) -> + {Out, Errors1} = begin + _pipe = case gleam_stdlib:index(Data, Key) of + {ok, {some, Data@1}} -> + (erlang:element(2, Field_decoder))(Data@1); + + {ok, none} -> + {Default, []}; + + {error, Kind} -> + {Default, + [{decode_error, + Kind, + gleam_stdlib:classify_dynamic(Data), + []}]} + end, + push_path(_pipe, [Key]) + end, + {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), + {Out@1, lists:append(Errors1, Errors2)} + end}. + +-file("src/gleam/dynamic/decode.gleam", 598). +?DOC( + " A decoder that decodes a value that is nested within other values. For\n" + " example, decoding a value that is within some deeply nested JSON objects.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.optionally_at([\"one\", \"two\"], 100, decode.int)\n" + "\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"one\", dict.from_list([])),\n" + " ]))\n" + "\n" + "\n" + " decode.run(data, decoder)\n" + " // -> Ok(100)\n" + " ```\n" +). +-spec optionally_at(list(any()), BZN, decoder(BZN)) -> decoder(BZN). +optionally_at(Path, Default, Inner) -> + {decoder, + fun(Data) -> + index( + Path, + [], + erlang:element(2, Inner), + Data, + fun(_, _) -> {Default, []} end + ) + end}. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache new file mode 100644 index 0000000000000000000000000000000000000000..47a58f42eb078b4965dd74567fde1fd0f56e1dad GIT binary patch literal 23125 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..604414bb9ff7d49e8007dc12be5b85abcc9e8382 GIT binary patch literal 2724 zcmXxld617~902f#EQ<|WHbq-3w#|{1pD=1O)3Upc4o7koX&5 zscY=hjO1l@ahXcuZVI6xBiK%jY9S0@0ZTYdXY+WRf9I6L7`~*K63RHmWumK#M*@ko zBb5ORBa?X)6ICOG>U1T80Sw_q-e4AU`G6woM2km+Y;u^)Tg>J&_HclM#Mca=3GKx9wCkX z3}OU}S;rQ(v6ph9V?(G%eOl6ibg~%B61KC0os?5a%q_+dPa7VhD;bPsD)}tuL)NgC zQciN23Zie7OC*s@gr|9lTxO6*KC>y|2&Xtp1u^x-Ab~{EnZ!y~QN}5*aE;n=-Y1D< zBJ^h#8`#Kc&Jk`4p&GF?rWFx7(v`jpWdx(hXES>_N|gq3iW)?d!XO5-l$8{)l|7u` z9OYEfM+_r}@l4?p3i*Zu{6dX})=L73Ji{xz#h0ApFQOWS@Gzqp z&udH|mlYi03Kg`!GlWiL(2IeLV=6PqV=xRd*NfR1!xA`4l{MhYn8 zC(1a>pIqnGyFzGAYub`RZ^kl#H<`&AK4&-kDCQ)URJ+@r@F+9+m@~9(EC%~1p-~fa zWiUf|mf=ie2c?{#QG&Xp4ejVcKe8CjSSB%_^?b^9&Ty6Mgr;(m2&tsgk4(mq%OqB@ ziOm#nkRLft85f9YX5UF5k=~3Xo0nL}E-q5Nc?h+L;bzk5$snF#6z{Qs<$TCboaX`; zX`dKEH>NO$1uSF{rCg+(hwpJdGnstmvXV_4;71NqN#`UrMn4v@j5FMRuNsNKqOLMytEN;lHToT%3B2b$BGwxrOPr|#H~lo0N7 z?@^l=l8G>qb!?)LJsjdBm$*umHfok;B=IDfWRt^0=Chg&Y~~oh^9QH7CE42P#Vqn! z!DG&$Dd(u(R!-81G#;Z5L&;@2vzf;#3Mrz5Bh= 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: \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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@function.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@function.cache new file mode 100644 index 0000000000000000000000000000000000000000..fca1325a3cf3d3212f97bb147441a55be0cb96ca GIT binary patch literal 1083 zcmZ`&T~8B16rDS}+ie>Ny{QChLYOu&Mgo-52O`mQDWoW1E%Cc?t1EjC= zpz=2`;oZOB57D2Yk>K5JDoFKVGLw^Y&)jq7&eAG8gE7W%p^wr;c{hK-O}z6q|AVjW zOzXfa#XiqlI?r$DX1=bc)+}ASY`aPxlv@$2d5zHNdIR815VDD;>+D^YUk1t#%I&l- zJ49@%!?Nu8!Qz1`??sN=Ecaw%U$zxdVkIh!%gTY@7yu+a5UwpI1dG?x9LKlnIUO%b z^(^OvQgvX3Adzu@z3mH2NfRJSzfc#+1p63SRw$2UUELjE-id*(>y!CMxD#f3G zufTo)U|R$(!FAnHm*R!oSAmcz5jY+-CZykv4yX|!y{3@vkvtBBufoXp0^x+Tyj~QF zLs@epwV2IPV+O9jhJqQ&Uefm0k+zTQlceo*+%^^H|8SGQoLtfS#Ajk+v1FfdrSl1ygLhNjok z8cyEE!W3c_A1-5k3h!sNr~8c6^<;!_CQDh9`0R%7cl{f<&Wwpi-L6ZD1}SQZ+#D9n zSZ;E8aF}@EM~X3v&pwuJketkIC#ji@Yjh1WB^)==$PRFeYo~z52^P(qh3gVk8#`Z? zL5J!ZY(h1H_fY)^r;y`08hMLjCKcZ=&E)<*7D}hDF71y(hflE0>p_xoC?GsT^T^U8HgExI$40&8HnA1 SxD<$+fw&WhyP+7Q3= 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. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.cache new file mode 100644 index 0000000000000000000000000000000000000000..19bbdae8dfdda30b9a5b122a6e0f71247d558168 GIT binary patch literal 29069 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�5xswfsF^$_g# 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.erl new file mode 100644 index 0000000..b9f71b2 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@int.erl @@ -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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache new file mode 100644 index 0000000000000000000000000000000000000000..13e0525b078153c9df0bd2168d723e85b8076ad1 GIT binary patch literal 2639 zcmchZ-;Wbj6vyY>xzit$-RvIgS|INBQlbLF)^;EpFuL1raHS6`BW}J6^kZz#v;=@ zV)Am;GL3qsW=oP3_UBzs8md^e@^WU*H61rojXB0)@~N1wW{jrej@QjhxmB|&nWnLD z)To-|;s>FD{;-VeEQAJ%Iv#wHq$!pkW;p8P1y5Xn!t{CIiMU*z9+2ss=cdndzT9+b z4bN)KODWTFY)4oEWXRbl|NHk{O_m?ANq(-RPPBj#{@6bDrtfXV$H#i*vj zpTfS-CEe{3ovm42-xZ3z(b2E?O%bm^cH=FMUx97`=x>p+1ijN*kuY(wiou%AH zQ(g^C)UvAtM&X+{jD;I_-gKnsnyRU+Uk}xEoz#?$;P(L<{URB?wwgMV>I*6PAGG9a zW$z(z+-`|Qqv81-N3=PTqROTScBNSnc0<%WSJ;aU5$Me|O;PIX{Xk5me!{z>Ihre_ zZ*|3$O3{^yEBD}B$zxTh!5lk@BB-CU8w|!$fqCt;mea3>TDwYGyQR}_nh{#p#Z2v-4K1{kBVH^6XYw|+k` z{CKPW5j9I`{TE=9&zf$_@~EQ4ClC@G@-Z1lHsJasqKZ%CFrUO-s{G7RNy_t}+Tkdj z=TaoK$KQ`DtyCG6p@MB&6i%UVau95*Ul%FZNKhbA9eU1bnSLowJ!M#K(DSRIKPKgm z;WEb4I2c7m4ee7*KBHunn}Elo!&%(<2A+Ng&t1aLzQG@EWS0i~RUQJZ3h#sV0sINt zU+_0*z~W4MnC)O%ffboH%T6-dyuUH+cQzqwkIO|_o0VUbHBUY*YiH&2vUXAaR;EMi zQLb&{C%ATszsvjx*cRB2ZS?G2MBi*^ybh*wemJ*Q4(H6mx8Jx@ETpH(QQo;6Z-)8)alK@-?cRvBN v18@+i`H}rhwO)IWr#Uq(<#i>D;e-750A(=!088wqAK($b)emq=c~kiZxXGA5 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..a67a4cf0c1b5f4b7a96f15bc7a7760b67743c940 GIT binary patch literal 289 zcmXxfzY76z7{~GFiyM@`z|KPHiVRG*-3?bZW#|5Y8-*@Ak|;Om{tFq5G8j!V$d4<- zF!gno=?y4)T2KNj>J((X$2osIhClHESNfK7{J2}3k2BWfHSVRA;&cXUG%WT z8gE4SLZw8qD544j7HkZ$!xJym(;^L6u+f1F4^yn*;|MJyQbHMhj4;6*8|-ny1$TtV MYa(roW4!Rs4_JUCZ2$lO literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.erl new file mode 100644 index 0000000..a21232e --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@io.erl @@ -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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@list.cache new file mode 100644 index 0000000000000000000000000000000000000000..d7db915cd16c87b60603bcfab94f4254ec113de7 GIT binary patch literal 85274 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 27). +-define(MODULEDOC(Str), -moduledoc(Str)). +-define(DOC(Str), -doc(Str)). +-else. +-define(MODULEDOC(Str), -compile([])). +-define(DOC(Str), -compile([])). +-endif. + +?MODULEDOC( + " Lists are an ordered sequence of elements and are one of the most common\n" + " data types in Gleam.\n" + "\n" + " New elements can be added and removed from the front of a list in\n" + " constant time, while adding and removing from the end requires traversing\n" + " and copying the whole list, so keep this in mind when designing your\n" + " programs.\n" + "\n" + " There is a dedicated syntax for prefixing to a list:\n" + "\n" + " ```gleam\n" + " let new_list = [1, 2, ..existing_list]\n" + " ```\n" + "\n" + " And a matching syntax for getting the first elements of a list:\n" + "\n" + " ```gleam\n" + " case list {\n" + " [first_element, ..rest] -> first_element\n" + " _ -> \"this pattern matches when the list is empty\"\n" + " }\n" + " ```\n" + "\n" +). + +-type continue_or_stop(YG) :: {continue, YG} | {stop, YG}. + +-type sorting() :: ascending | descending. + +-file("src/gleam/list.gleam", 60). +-spec length_loop(list(any()), integer()) -> integer(). +length_loop(List, Count) -> + case List of + [_ | List@1] -> + length_loop(List@1, Count + 1); + + [] -> + Count + end. + +-file("src/gleam/list.gleam", 56). +?DOC( + " Counts the number of elements in a given list.\n" + "\n" + " This function has to traverse the list to determine the number of elements,\n" + " so it runs in linear time.\n" + "\n" + " This function is natively implemented by the virtual machine and is highly\n" + " optimised.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " length([])\n" + " // -> 0\n" + " ```\n" + "\n" + " ```gleam\n" + " length([1])\n" + " // -> 1\n" + " ```\n" + "\n" + " ```gleam\n" + " length([1, 2])\n" + " // -> 2\n" + " ```\n" +). +-spec length(list(any())) -> integer(). +length(List) -> + erlang:length(List). + +-file("src/gleam/list.gleam", 93). +-spec count_loop(list(YN), fun((YN) -> boolean()), integer()) -> integer(). +count_loop(List, Predicate, Acc) -> + case List of + [] -> + Acc; + + [First | Rest] -> + case Predicate(First) of + true -> + count_loop(Rest, Predicate, Acc + 1); + + false -> + count_loop(Rest, Predicate, Acc) + end + end. + +-file("src/gleam/list.gleam", 89). +?DOC( + " Counts the number of elements in a given list satisfying a given predicate.\n" + "\n" + " This function has to traverse the list to determine the number of elements,\n" + " so it runs in linear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " count([], fn(a) { a > 0 })\n" + " // -> 0\n" + " ```\n" + "\n" + " ```gleam\n" + " count([1], fn(a) { a > 0 })\n" + " // -> 1\n" + " ```\n" + "\n" + " ```gleam\n" + " count([1, 2, 3], int.is_odd)\n" + " // -> 2\n" + " ```\n" +). +-spec count(list(YL), fun((YL) -> boolean())) -> integer(). +count(List, Predicate) -> + count_loop(List, Predicate, 0). + +-file("src/gleam/list.gleam", 139). +?DOC( + " Reverses a list and prepends it to another list.\n" + " This function runs in linear time, proportional to the length of the list\n" + " to prepend.\n" +). +-spec reverse_and_prepend(list(YS), list(YS)) -> list(YS). +reverse_and_prepend(Prefix, Suffix) -> + case Prefix of + [] -> + Suffix; + + [First | Rest] -> + reverse_and_prepend(Rest, [First | Suffix]) + end. + +-file("src/gleam/list.gleam", 131). +?DOC( + " Creates a new list from a given list containing the same elements but in the\n" + " opposite order.\n" + "\n" + " This function has to traverse the list to create the new reversed list, so\n" + " it runs in linear time.\n" + "\n" + " This function is natively implemented by the virtual machine and is highly\n" + " optimised.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " reverse([])\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " reverse([1])\n" + " // -> [1]\n" + " ```\n" + "\n" + " ```gleam\n" + " reverse([1, 2])\n" + " // -> [2, 1]\n" + " ```\n" +). +-spec reverse(list(YP)) -> list(YP). +reverse(List) -> + lists:reverse(List). + +-file("src/gleam/list.gleam", 167). +?DOC( + " Determines whether or not the list is empty.\n" + "\n" + " This function runs in constant time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " is_empty([])\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " is_empty([1])\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " is_empty([1, 1])\n" + " // -> False\n" + " ```\n" +). +-spec is_empty(list(any())) -> boolean(). +is_empty(List) -> + List =:= []. + +-file("src/gleam/list.gleam", 203). +?DOC( + " Determines whether or not a given element exists within a given list.\n" + "\n" + " This function traverses the list to find the element, so it runs in linear\n" + " time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [] |> contains(any: 0)\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " [0] |> contains(any: 0)\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " [1] |> contains(any: 0)\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 1] |> contains(any: 0)\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 0] |> contains(any: 0)\n" + " // -> True\n" + " ```\n" +). +-spec contains(list(YY), YY) -> boolean(). +contains(List, Elem) -> + case List of + [] -> + false; + + [First | _] when First =:= Elem -> + true; + + [_ | Rest] -> + contains(Rest, Elem) + end. + +-file("src/gleam/list.gleam", 230). +?DOC( + " Gets the first element from the start of the list, if there is one.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " first([])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " first([0])\n" + " // -> Ok(0)\n" + " ```\n" + "\n" + " ```gleam\n" + " first([1, 2])\n" + " // -> Ok(1)\n" + " ```\n" +). +-spec first(list(AAA)) -> {ok, AAA} | {error, nil}. +first(List) -> + case List of + [] -> + {error, nil}; + + [First | _] -> + {ok, First} + end. + +-file("src/gleam/list.gleam", 259). +?DOC( + " Returns the list minus the first element. If the list is empty, `Error(Nil)` is\n" + " returned.\n" + "\n" + " This function runs in constant time and does not make a copy of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " rest([])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " rest([0])\n" + " // -> Ok([])\n" + " ```\n" + "\n" + " ```gleam\n" + " rest([1, 2])\n" + " // -> Ok([2])\n" + " ```\n" +). +-spec rest(list(AAE)) -> {ok, list(AAE)} | {error, nil}. +rest(List) -> + case List of + [] -> + {error, nil}; + + [_ | Rest] -> + {ok, Rest} + end. + +-file("src/gleam/list.gleam", 301). +-spec group_loop(list(AAP), fun((AAP) -> AAR), gleam@dict:dict(AAR, list(AAP))) -> gleam@dict:dict(AAR, list(AAP)). +group_loop(List, To_key, Groups) -> + case List of + [] -> + Groups; + + [First | Rest] -> + Key = To_key(First), + Groups@1 = case gleam_stdlib:map_get(Groups, Key) of + {error, _} -> + gleam@dict:insert(Groups, Key, [First]); + + {ok, Existing} -> + gleam@dict:insert(Groups, Key, [First | Existing]) + end, + group_loop(Rest, To_key, Groups@1) + end. + +-file("src/gleam/list.gleam", 297). +?DOC( + " Groups the elements from the given list by the given key function.\n" + "\n" + " Does not preserve the initial value order.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " import gleam/dict\n" + "\n" + " [Ok(3), Error(\"Wrong\"), Ok(200), Ok(73)]\n" + " |> group(by: fn(i) {\n" + " case i {\n" + " Ok(_) -> \"Successful\"\n" + " Error(_) -> \"Failed\"\n" + " }\n" + " })\n" + " |> dict.to_list\n" + " // -> [\n" + " // #(\"Failed\", [Error(\"Wrong\")]),\n" + " // #(\"Successful\", [Ok(73), Ok(200), Ok(3)])\n" + " // ]\n" + " ```\n" + "\n" + " ```gleam\n" + " import gleam/dict\n" + "\n" + " group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 })\n" + " |> dict.to_list\n" + " // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])]\n" + " ```\n" +). +-spec group(list(AAJ), fun((AAJ) -> AAL)) -> gleam@dict:dict(AAL, list(AAJ)). +group(List, Key) -> + group_loop(List, Key, maps:new()). + +-file("src/gleam/list.gleam", 338). +-spec filter_loop(list(ABB), fun((ABB) -> boolean()), list(ABB)) -> list(ABB). +filter_loop(List, Fun, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + New_acc = case Fun(First) of + true -> + [First | Acc]; + + false -> + Acc + end, + filter_loop(Rest, Fun, New_acc) + end. + +-file("src/gleam/list.gleam", 334). +?DOC( + " Returns a new list containing only the elements from the first list for\n" + " which the given functions returns `True`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " filter([2, 4, 6, 1], fn(x) { x > 2 })\n" + " // -> [4, 6]\n" + " ```\n" + "\n" + " ```gleam\n" + " filter([2, 4, 6, 1], fn(x) { x > 6 })\n" + " // -> []\n" + " ```\n" +). +-spec filter(list(AAY), fun((AAY) -> boolean())) -> list(AAY). +filter(List, Predicate) -> + filter_loop(List, Predicate, []). + +-file("src/gleam/list.gleam", 370). +-spec filter_map_loop( + list(ABM), + fun((ABM) -> {ok, ABO} | {error, any()}), + list(ABO) +) -> list(ABO). +filter_map_loop(List, Fun, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + New_acc = case Fun(First) of + {ok, First@1} -> + [First@1 | Acc]; + + {error, _} -> + Acc + end, + filter_map_loop(Rest, Fun, New_acc) + end. + +-file("src/gleam/list.gleam", 366). +?DOC( + " Returns a new list containing only the elements from the first list for\n" + " which the given functions returns `Ok(_)`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " filter_map([2, 4, 6, 1], Error)\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) })\n" + " // -> [3, 5, 7, 2]\n" + " ```\n" +). +-spec filter_map(list(ABF), fun((ABF) -> {ok, ABH} | {error, any()})) -> list(ABH). +filter_map(List, Fun) -> + filter_map_loop(List, Fun, []). + +-file("src/gleam/list.gleam", 401). +-spec map_loop(list(ABY), fun((ABY) -> ACA), list(ACA)) -> list(ACA). +map_loop(List, Fun, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + map_loop(Rest, Fun, [Fun(First) | Acc]) + end. + +-file("src/gleam/list.gleam", 397). +?DOC( + " Returns a new list containing only the elements of the first list after the\n" + " function has been applied to each one.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " map([2, 4, 6], fn(x) { x * 2 })\n" + " // -> [4, 8, 12]\n" + " ```\n" +). +-spec map(list(ABU), fun((ABU) -> ABW)) -> list(ABW). +map(List, Fun) -> + map_loop(List, Fun, []). + +-file("src/gleam/list.gleam", 428). +-spec map2_loop(list(ACJ), list(ACL), fun((ACJ, ACL) -> ACN), list(ACN)) -> list(ACN). +map2_loop(List1, List2, Fun, Acc) -> + case {List1, List2} of + {[], _} -> + lists:reverse(Acc); + + {_, []} -> + lists:reverse(Acc); + + {[A | As_], [B | Bs]} -> + map2_loop(As_, Bs, Fun, [Fun(A, B) | Acc]) + end. + +-file("src/gleam/list.gleam", 424). +?DOC( + " Combines two lists into a single list using the given function.\n" + "\n" + " If a list is longer than the other the extra elements are dropped.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y })\n" + " // -> [5, 7, 9]\n" + " ```\n" + "\n" + " ```gleam\n" + " map2([1, 2], [\"a\", \"b\", \"c\"], fn(i, x) { #(i, x) })\n" + " // -> [#(1, \"a\"), #(2, \"b\")]\n" + " ```\n" +). +-spec map2(list(ACD), list(ACF), fun((ACD, ACF) -> ACH)) -> list(ACH). +map2(List1, List2, Fun) -> + map2_loop(List1, List2, Fun, []). + +-file("src/gleam/list.gleam", 461). +-spec map_fold_loop(list(ACV), fun((ACX, ACV) -> {ACX, ACY}), ACX, list(ACY)) -> {ACX, + list(ACY)}. +map_fold_loop(List, Fun, Acc, List_acc) -> + case List of + [] -> + {Acc, lists:reverse(List_acc)}; + + [First | Rest] -> + {Acc@1, First@1} = Fun(Acc, First), + map_fold_loop(Rest, Fun, Acc@1, [First@1 | List_acc]) + end. + +-file("src/gleam/list.gleam", 453). +?DOC( + " Similar to `map` but also lets you pass around an accumulated value.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " map_fold(\n" + " over: [1, 2, 3],\n" + " from: 100,\n" + " with: fn(memo, i) { #(memo + i, i * 2) }\n" + " )\n" + " // -> #(106, [2, 4, 6])\n" + " ```\n" +). +-spec map_fold(list(ACQ), ACS, fun((ACS, ACQ) -> {ACS, ACT})) -> {ACS, + list(ACT)}. +map_fold(List, Initial, Fun) -> + map_fold_loop(List, Fun, Initial, []). + +-file("src/gleam/list.gleam", 493). +-spec index_map_loop( + list(ADF), + fun((ADF, integer()) -> ADH), + integer(), + list(ADH) +) -> list(ADH). +index_map_loop(List, Fun, Index, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + Acc@1 = [Fun(First, Index) | Acc], + index_map_loop(Rest, Fun, Index + 1, Acc@1) + end. + +-file("src/gleam/list.gleam", 489). +?DOC( + " Returns a new list containing only the elements of the first list after the\n" + " function has been applied to each one and their index.\n" + "\n" + " The index starts at 0, so the first element is 0, the second is 1, and so\n" + " on.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " index_map([\"a\", \"b\"], fn(x, i) { #(i, x) })\n" + " // -> [#(0, \"a\"), #(1, \"b\")]\n" + " ```\n" +). +-spec index_map(list(ADB), fun((ADB, integer()) -> ADD)) -> list(ADD). +index_map(List, Fun) -> + index_map_loop(List, Fun, 0, []). + +-file("src/gleam/list.gleam", 547). +-spec try_map_loop(list(ADT), fun((ADT) -> {ok, ADV} | {error, ADW}), list(ADV)) -> {ok, + list(ADV)} | + {error, ADW}. +try_map_loop(List, Fun, Acc) -> + case List of + [] -> + {ok, lists:reverse(Acc)}; + + [First | Rest] -> + case Fun(First) of + {ok, First@1} -> + try_map_loop(Rest, Fun, [First@1 | Acc]); + + {error, Error} -> + {error, Error} + end + end. + +-file("src/gleam/list.gleam", 540). +?DOC( + " Takes a function that returns a `Result` and applies it to each element in a\n" + " given list in turn.\n" + "\n" + " If the function returns `Ok(new_value)` for all elements in the list then a\n" + " list of the new values is returned.\n" + "\n" + " If the function returns `Error(reason)` for any of the elements then it is\n" + " returned immediately. None of the elements in the list are processed after\n" + " one returns an `Error`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " try_map([1, 2, 3], fn(x) { Ok(x + 2) })\n" + " // -> Ok([3, 4, 5])\n" + " ```\n" + "\n" + " ```gleam\n" + " try_map([1, 2, 3], fn(_) { Error(0) })\n" + " // -> Error(0)\n" + " ```\n" + "\n" + " ```gleam\n" + " try_map([[1], [2, 3]], first)\n" + " // -> Ok([1, 2])\n" + " ```\n" + "\n" + " ```gleam\n" + " try_map([[1], [], [2]], first)\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec try_map(list(ADK), fun((ADK) -> {ok, ADM} | {error, ADN})) -> {ok, + list(ADM)} | + {error, ADN}. +try_map(List, Fun) -> + try_map_loop(List, Fun, []). + +-file("src/gleam/list.gleam", 582). +?DOC( + " Returns a list that is the given list with up to the given number of\n" + " elements removed from the front of the list.\n" + "\n" + " If the element has less than the number of elements an empty list is\n" + " returned.\n" + "\n" + " This function runs in linear time but does not copy the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " drop([1, 2, 3, 4], 2)\n" + " // -> [3, 4]\n" + " ```\n" + "\n" + " ```gleam\n" + " drop([1, 2, 3, 4], 9)\n" + " // -> []\n" + " ```\n" +). +-spec drop(list(AED), integer()) -> list(AED). +drop(List, N) -> + case N =< 0 of + true -> + List; + + false -> + case List of + [] -> + []; + + [_ | Rest] -> + drop(Rest, N - 1) + end + end. + +-file("src/gleam/list.gleam", 617). +-spec take_loop(list(AEJ), integer(), list(AEJ)) -> list(AEJ). +take_loop(List, N, Acc) -> + case N =< 0 of + true -> + lists:reverse(Acc); + + false -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + take_loop(Rest, N - 1, [First | Acc]) + end + end. + +-file("src/gleam/list.gleam", 613). +?DOC( + " Returns a list containing the first given number of elements from the given\n" + " list.\n" + "\n" + " If the element has less than the number of elements then the full list is\n" + " returned.\n" + "\n" + " This function runs in linear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " take([1, 2, 3, 4], 2)\n" + " // -> [1, 2]\n" + " ```\n" + "\n" + " ```gleam\n" + " take([1, 2, 3, 4], 9)\n" + " // -> [1, 2, 3, 4]\n" + " ```\n" +). +-spec take(list(AEG), integer()) -> list(AEG). +take(List, N) -> + take_loop(List, N, []). + +-file("src/gleam/list.gleam", 637). +?DOC( + " Returns a new empty list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " new()\n" + " // -> []\n" + " ```\n" +). +-spec new() -> list(any()). +new() -> + []. + +-file("src/gleam/list.gleam", 657). +?DOC( + " Returns the given item wrapped in a list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " wrap(1)\n" + " // -> [1]\n" + "\n" + " wrap([\"a\", \"b\", \"c\"])\n" + " // -> [[\"a\", \"b\", \"c\"]]\n" + "\n" + " wrap([[]])\n" + " // -> [[[]]]\n" + " ```\n" +). +-spec wrap(AEP) -> list(AEP). +wrap(Item) -> + [Item]. + +-file("src/gleam/list.gleam", 678). +-spec append_loop(list(AEV), list(AEV)) -> list(AEV). +append_loop(First, Second) -> + case First of + [] -> + Second; + + [First@1 | Rest] -> + append_loop(Rest, [First@1 | Second]) + end. + +-file("src/gleam/list.gleam", 674). +?DOC( + " Joins one list onto the end of another.\n" + "\n" + " This function runs in linear time, and it traverses and copies the first\n" + " list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " append([1, 2], [3])\n" + " // -> [1, 2, 3]\n" + " ```\n" +). +-spec append(list(AER), list(AER)) -> list(AER). +append(First, Second) -> + lists:append(First, Second). + +-file("src/gleam/list.gleam", 698). +?DOC( + " Prefixes an item to a list. This can also be done using the dedicated\n" + " syntax instead\n" + "\n" + " ```gleam\n" + " let existing_list = [2, 3, 4]\n" + "\n" + " [1, ..existing_list]\n" + " // -> [1, 2, 3, 4]\n" + "\n" + " prepend(to: existing_list, this: 1)\n" + " // -> [1, 2, 3, 4]\n" + " ```\n" +). +-spec prepend(list(AEZ), AEZ) -> list(AEZ). +prepend(List, Item) -> + [Item | List]. + +-file("src/gleam/list.gleam", 719). +-spec flatten_loop(list(list(AFG)), list(AFG)) -> list(AFG). +flatten_loop(Lists, Acc) -> + case Lists of + [] -> + lists:reverse(Acc); + + [List | Further_lists] -> + flatten_loop(Further_lists, reverse_and_prepend(List, Acc)) + end. + +-file("src/gleam/list.gleam", 715). +?DOC( + " Joins a list of lists into a single list.\n" + "\n" + " This function traverses all elements twice on the JavaScript target.\n" + " This function traverses all elements once on the Erlang target.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " flatten([[1], [2, 3], []])\n" + " // -> [1, 2, 3]\n" + " ```\n" +). +-spec flatten(list(list(AFC))) -> list(AFC). +flatten(Lists) -> + lists:append(Lists). + +-file("src/gleam/list.gleam", 736). +?DOC( + " Maps the list with the given function into a list of lists, and then flattens it.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " flat_map([2, 4, 6], fn(x) { [x, x + 1] })\n" + " // -> [2, 3, 4, 5, 6, 7]\n" + " ```\n" +). +-spec flat_map(list(AFL), fun((AFL) -> list(AFN))) -> list(AFN). +flat_map(List, Fun) -> + lists:append(map(List, Fun)). + +-file("src/gleam/list.gleam", 748). +?DOC( + " Reduces a list of elements into a single value by calling a given function\n" + " on each element, going from left to right.\n" + "\n" + " `fold([1, 2, 3], 0, add)` is the equivalent of\n" + " `add(add(add(0, 1), 2), 3)`.\n" + "\n" + " This function runs in linear time.\n" +). +-spec fold(list(AFQ), AFS, fun((AFS, AFQ) -> AFS)) -> AFS. +fold(List, Initial, Fun) -> + case List of + [] -> + Initial; + + [First | Rest] -> + fold(Rest, Fun(Initial, First), Fun) + end. + +-file("src/gleam/list.gleam", 770). +?DOC( + " Reduces a list of elements into a single value by calling a given function\n" + " on each element, going from right to left.\n" + "\n" + " `fold_right([1, 2, 3], 0, add)` is the equivalent of\n" + " `add(add(add(0, 3), 2), 1)`.\n" + "\n" + " This function runs in linear time.\n" + "\n" + " Unlike `fold` this function is not tail recursive. Where possible use\n" + " `fold` instead as it will use less memory.\n" +). +-spec fold_right(list(AFT), AFV, fun((AFV, AFT) -> AFV)) -> AFV. +fold_right(List, Initial, Fun) -> + case List of + [] -> + Initial; + + [First | Rest] -> + Fun(fold_right(Rest, Initial, Fun), First) + end. + +-file("src/gleam/list.gleam", 798). +-spec index_fold_loop( + list(AFZ), + AGB, + fun((AGB, AFZ, integer()) -> AGB), + integer() +) -> AGB. +index_fold_loop(Over, Acc, With, Index) -> + case Over of + [] -> + Acc; + + [First | Rest] -> + index_fold_loop(Rest, With(Acc, First, Index), With, Index + 1) + end. + +-file("src/gleam/list.gleam", 790). +?DOC( + " Like fold but the folding function also receives the index of the current element.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [\"a\", \"b\", \"c\"]\n" + " |> index_fold([], fn(acc, item, index) { ... })\n" + " ```\n" +). +-spec index_fold(list(AFW), AFY, fun((AFY, AFW, integer()) -> AFY)) -> AFY. +index_fold(List, Initial, Fun) -> + index_fold_loop(List, Initial, Fun, 0). + +-file("src/gleam/list.gleam", 830). +?DOC( + " A variant of fold that might fail.\n" + "\n" + " The folding function should return `Result(accumulator, error)`.\n" + " If the returned value is `Ok(accumulator)` try_fold will try the next value in the list.\n" + " If the returned value is `Error(error)` try_fold will stop and return that error.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4]\n" + " |> try_fold(0, fn(acc, i) {\n" + " case i < 3 {\n" + " True -> Ok(acc + i)\n" + " False -> Error(Nil)\n" + " }\n" + " })\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec try_fold(list(AGC), AGE, fun((AGE, AGC) -> {ok, AGE} | {error, AGF})) -> {ok, + AGE} | + {error, AGF}. +try_fold(List, Initial, Fun) -> + case List of + [] -> + {ok, Initial}; + + [First | Rest] -> + case Fun(Initial, First) of + {ok, Result} -> + try_fold(Rest, Result, Fun); + + {error, _} = Error -> + Error + end + end. + +-file("src/gleam/list.gleam", 869). +?DOC( + " A variant of fold that allows to stop folding earlier.\n" + "\n" + " The folding function should return `ContinueOrStop(accumulator)`.\n" + " If the returned value is `Continue(accumulator)` fold_until will try the next value in the list.\n" + " If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4]\n" + " |> fold_until(0, fn(acc, i) {\n" + " case i < 3 {\n" + " True -> Continue(acc + i)\n" + " False -> Stop(acc)\n" + " }\n" + " })\n" + " // -> 3\n" + " ```\n" +). +-spec fold_until(list(AGK), AGM, fun((AGM, AGK) -> continue_or_stop(AGM))) -> AGM. +fold_until(List, Initial, Fun) -> + case List of + [] -> + Initial; + + [First | Rest] -> + case Fun(Initial, First) of + {continue, Next_accumulator} -> + fold_until(Rest, Next_accumulator, Fun); + + {stop, B} -> + B + end + end. + +-file("src/gleam/list.gleam", 906). +?DOC( + " Finds the first element in a given list for which the given function returns\n" + " `True`.\n" + "\n" + " Returns `Error(Nil)` if no such element is found.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " find([1, 2, 3], fn(x) { x > 2 })\n" + " // -> Ok(3)\n" + " ```\n" + "\n" + " ```gleam\n" + " find([1, 2, 3], fn(x) { x > 4 })\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " find([], fn(_) { True })\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec find(list(AGO), fun((AGO) -> boolean())) -> {ok, AGO} | {error, nil}. +find(List, Is_desired) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + case Is_desired(First) of + true -> + {ok, First}; + + false -> + find(Rest, Is_desired) + end + end. + +-file("src/gleam/list.gleam", 942). +?DOC( + " Finds the first element in a given list for which the given function returns\n" + " `Ok(new_value)`, then returns the wrapped `new_value`.\n" + "\n" + " Returns `Error(Nil)` if no such element is found.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " find_map([[], [2], [3]], first)\n" + " // -> Ok(2)\n" + " ```\n" + "\n" + " ```gleam\n" + " find_map([[], []], first)\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " find_map([], first)\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec find_map(list(AGS), fun((AGS) -> {ok, AGU} | {error, any()})) -> {ok, AGU} | + {error, nil}. +find_map(List, Fun) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + case Fun(First) of + {ok, First@1} -> + {ok, First@1}; + + {error, _} -> + find_map(Rest, Fun) + end + end. + +-file("src/gleam/list.gleam", 977). +?DOC( + " Returns `True` if the given function returns `True` for all the elements in\n" + " the given list. If the function returns `False` for any of the elements it\n" + " immediately returns `False` without checking the rest of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " all([], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " all([4, 5], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " all([4, 3], fn(x) { x > 3 })\n" + " // -> False\n" + " ```\n" +). +-spec all(list(AHA), fun((AHA) -> boolean())) -> boolean(). +all(List, Predicate) -> + case List of + [] -> + true; + + [First | Rest] -> + case Predicate(First) of + true -> + all(Rest, Predicate); + + false -> + false + end + end. + +-file("src/gleam/list.gleam", 1014). +?DOC( + " Returns `True` if the given function returns `True` for any the elements in\n" + " the given list. If the function returns `True` for any of the elements it\n" + " immediately returns `True` without checking the rest of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " any([], fn(x) { x > 3 })\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " any([4, 5], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " any([4, 3], fn(x) { x > 4 })\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " any([3, 4], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" +). +-spec any(list(AHC), fun((AHC) -> boolean())) -> boolean(). +any(List, Predicate) -> + case List of + [] -> + false; + + [First | Rest] -> + case Predicate(First) of + true -> + true; + + false -> + any(Rest, Predicate) + end + end. + +-file("src/gleam/list.gleam", 1056). +-spec zip_loop(list(AHJ), list(AHL), list({AHJ, AHL})) -> list({AHJ, AHL}). +zip_loop(One, Other, Acc) -> + case {One, Other} of + {[First_one | Rest_one], [First_other | Rest_other]} -> + zip_loop(Rest_one, Rest_other, [{First_one, First_other} | Acc]); + + {_, _} -> + lists:reverse(Acc) + end. + +-file("src/gleam/list.gleam", 1052). +?DOC( + " Takes two lists and returns a single list of 2-element tuples.\n" + "\n" + " If one of the lists is longer than the other, the remaining elements from\n" + " the longer list are not used.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " zip([], [])\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " zip([1, 2], [3])\n" + " // -> [#(1, 3)]\n" + " ```\n" + "\n" + " ```gleam\n" + " zip([1], [3, 4])\n" + " // -> [#(1, 3)]\n" + " ```\n" + "\n" + " ```gleam\n" + " zip([1, 2], [3, 4])\n" + " // -> [#(1, 3), #(2, 4)]\n" + " ```\n" +). +-spec zip(list(AHE), list(AHG)) -> list({AHE, AHG}). +zip(List, Other) -> + zip_loop(List, Other, []). + +-file("src/gleam/list.gleam", 1097). +-spec strict_zip_loop(list(AHW), list(AHY), list({AHW, AHY})) -> {ok, + list({AHW, AHY})} | + {error, nil}. +strict_zip_loop(One, Other, Acc) -> + case {One, Other} of + {[], []} -> + {ok, lists:reverse(Acc)}; + + {[], _} -> + {error, nil}; + + {_, []} -> + {error, nil}; + + {[First_one | Rest_one], [First_other | Rest_other]} -> + strict_zip_loop( + Rest_one, + Rest_other, + [{First_one, First_other} | Acc] + ) + end. + +-file("src/gleam/list.gleam", 1090). +?DOC( + " Takes two lists and returns a single list of 2-element tuples.\n" + "\n" + " If one of the lists is longer than the other, an `Error` is returned.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " strict_zip([], [])\n" + " // -> Ok([])\n" + " ```\n" + "\n" + " ```gleam\n" + " strict_zip([1, 2], [3])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " strict_zip([1], [3, 4])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " strict_zip([1, 2], [3, 4])\n" + " // -> Ok([#(1, 3), #(2, 4)])\n" + " ```\n" +). +-spec strict_zip(list(AHP), list(AHR)) -> {ok, list({AHP, AHR})} | {error, nil}. +strict_zip(List, Other) -> + strict_zip_loop(List, Other, []). + +-file("src/gleam/list.gleam", 1128). +-spec unzip_loop(list({AIJ, AIK}), list(AIJ), list(AIK)) -> {list(AIJ), + list(AIK)}. +unzip_loop(Input, One, Other) -> + case Input of + [] -> + {lists:reverse(One), lists:reverse(Other)}; + + [{First_one, First_other} | Rest] -> + unzip_loop(Rest, [First_one | One], [First_other | Other]) + end. + +-file("src/gleam/list.gleam", 1124). +?DOC( + " Takes a single list of 2-element tuples and returns two lists.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " unzip([#(1, 2), #(3, 4)])\n" + " // -> #([1, 3], [2, 4])\n" + " ```\n" + "\n" + " ```gleam\n" + " unzip([])\n" + " // -> #([], [])\n" + " ```\n" +). +-spec unzip(list({AIE, AIF})) -> {list(AIE), list(AIF)}. +unzip(Input) -> + unzip_loop(Input, [], []). + +-file("src/gleam/list.gleam", 1163). +-spec intersperse_loop(list(AIT), AIT, list(AIT)) -> list(AIT). +intersperse_loop(List, Separator, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + intersperse_loop(Rest, Separator, [First, Separator | Acc]) + end. + +-file("src/gleam/list.gleam", 1156). +?DOC( + " Inserts a given value between each existing element in a given list.\n" + "\n" + " This function runs in linear time and copies the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " intersperse([1, 1, 1], 2)\n" + " // -> [1, 2, 1, 2, 1]\n" + " ```\n" + "\n" + " ```gleam\n" + " intersperse([], 2)\n" + " // -> []\n" + " ```\n" +). +-spec intersperse(list(AIQ), AIQ) -> list(AIQ). +intersperse(List, Elem) -> + case List of + [] -> + List; + + [_] -> + List; + + [First | Rest] -> + intersperse_loop(Rest, Elem, [First]) + end. + +-file("src/gleam/list.gleam", 1186). +-spec unique_loop(list(AJA), gleam@dict:dict(AJA, nil), list(AJA)) -> list(AJA). +unique_loop(List, Seen, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + case gleam@dict:has_key(Seen, First) of + true -> + unique_loop(Rest, Seen, Acc); + + false -> + unique_loop( + Rest, + gleam@dict:insert(Seen, First, nil), + [First | Acc] + ) + end + end. + +-file("src/gleam/list.gleam", 1182). +?DOC( + " Removes any duplicate elements from a given list.\n" + "\n" + " This function returns in loglinear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " unique([1, 1, 1, 4, 7, 3, 3, 4])\n" + " // -> [1, 4, 7, 3]\n" + " ```\n" +). +-spec unique(list(AIX)) -> list(AIX). +unique(List) -> + unique_loop(List, maps:new(), []). + +-file("src/gleam/list.gleam", 1272). +?DOC( + " Given a list it returns slices of it that are locally sorted in ascending\n" + " order.\n" + "\n" + " Imagine you have this list:\n" + "\n" + " ```\n" + " [1, 2, 3, 2, 1, 0]\n" + " ^^^^^^^ ^^^^^^^ This is a slice in descending order\n" + " |\n" + " | This is a slice that is sorted in ascending order\n" + " ```\n" + "\n" + " So the produced result will contain these two slices, each one sorted in\n" + " ascending order: `[[1, 2, 3], [0, 1, 2]]`.\n" + "\n" + " - `growing` is an accumulator with the current slice being grown\n" + " - `direction` is the growing direction of the slice being grown, it could\n" + " either be ascending or strictly descending\n" + " - `prev` is the previous element that needs to be added to the growing slice\n" + " it is carried around to check whether we have to keep growing the current\n" + " slice or not\n" + " - `acc` is the accumulator containing the slices sorted in ascending order\n" +). +-spec sequences( + list(AJJ), + fun((AJJ, AJJ) -> gleam@order:order()), + list(AJJ), + sorting(), + AJJ, + list(list(AJJ)) +) -> list(list(AJJ)). +sequences(List, Compare, Growing, Direction, Prev, Acc) -> + Growing@1 = [Prev | Growing], + case List of + [] -> + case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end; + + [New | Rest] -> + case {Compare(Prev, New), Direction} of + {gt, descending} -> + sequences(Rest, Compare, Growing@1, Direction, New, Acc); + + {lt, ascending} -> + sequences(Rest, Compare, Growing@1, Direction, New, Acc); + + {eq, ascending} -> + sequences(Rest, Compare, Growing@1, Direction, New, Acc); + + {gt, ascending} -> + Acc@1 = case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end, + case Rest of + [] -> + [[New] | Acc@1]; + + [Next | Rest@1] -> + Direction@1 = case Compare(New, Next) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + sequences( + Rest@1, + Compare, + [New], + Direction@1, + Next, + Acc@1 + ) + end; + + {lt, descending} -> + Acc@1 = case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end, + case Rest of + [] -> + [[New] | Acc@1]; + + [Next | Rest@1] -> + Direction@1 = case Compare(New, Next) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + sequences( + Rest@1, + Compare, + [New], + Direction@1, + Next, + Acc@1 + ) + end; + + {eq, descending} -> + Acc@1 = case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end, + case Rest of + [] -> + [[New] | Acc@1]; + + [Next | Rest@1] -> + Direction@1 = case Compare(New, Next) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + sequences( + Rest@1, + Compare, + [New], + Direction@1, + Next, + Acc@1 + ) + end + end + end. + +-file("src/gleam/list.gleam", 1420). +?DOC( + " Merges two lists sorted in ascending order into a single list sorted in\n" + " descending order according to the given comparator function.\n" + "\n" + " This reversing of the sort order is not avoidable if we want to implement\n" + " merge as a tail recursive function. We could reverse the accumulator before\n" + " returning it but that would end up being less efficient; so the merging\n" + " algorithm has to play around this.\n" +). +-spec merge_ascendings( + list(AKG), + list(AKG), + fun((AKG, AKG) -> gleam@order:order()), + list(AKG) +) -> list(AKG). +merge_ascendings(List1, List2, Compare, Acc) -> + case {List1, List2} of + {[], List} -> + reverse_and_prepend(List, Acc); + + {List, []} -> + reverse_and_prepend(List, Acc); + + {[First1 | Rest1], [First2 | Rest2]} -> + case Compare(First1, First2) of + lt -> + merge_ascendings(Rest1, List2, Compare, [First1 | Acc]); + + gt -> + merge_ascendings(List1, Rest2, Compare, [First2 | Acc]); + + eq -> + merge_ascendings(List1, Rest2, Compare, [First2 | Acc]) + end + end. + +-file("src/gleam/list.gleam", 1373). +?DOC( + " Given a list of ascending lists, it merges adjacent pairs into a single\n" + " descending list, halving their number.\n" + " It returns a list of the remaining descending lists.\n" +). +-spec merge_ascending_pairs( + list(list(AJU)), + fun((AJU, AJU) -> gleam@order:order()), + list(list(AJU)) +) -> list(list(AJU)). +merge_ascending_pairs(Sequences, Compare, Acc) -> + case Sequences of + [] -> + lists:reverse(Acc); + + [Sequence] -> + lists:reverse([lists:reverse(Sequence) | Acc]); + + [Ascending1, Ascending2 | Rest] -> + Descending = merge_ascendings(Ascending1, Ascending2, Compare, []), + merge_ascending_pairs(Rest, Compare, [Descending | Acc]) + end. + +-file("src/gleam/list.gleam", 1447). +?DOC( + " This is exactly the same as merge_ascendings but mirrored: it merges two\n" + " lists sorted in descending order into a single list sorted in ascending\n" + " order according to the given comparator function.\n" + "\n" + " This reversing of the sort order is not avoidable if we want to implement\n" + " merge as a tail recursive function. We could reverse the accumulator before\n" + " returning it but that would end up being less efficient; so the merging\n" + " algorithm has to play around this.\n" +). +-spec merge_descendings( + list(AKL), + list(AKL), + fun((AKL, AKL) -> gleam@order:order()), + list(AKL) +) -> list(AKL). +merge_descendings(List1, List2, Compare, Acc) -> + case {List1, List2} of + {[], List} -> + reverse_and_prepend(List, Acc); + + {List, []} -> + reverse_and_prepend(List, Acc); + + {[First1 | Rest1], [First2 | Rest2]} -> + case Compare(First1, First2) of + lt -> + merge_descendings(List1, Rest2, Compare, [First2 | Acc]); + + gt -> + merge_descendings(Rest1, List2, Compare, [First1 | Acc]); + + eq -> + merge_descendings(Rest1, List2, Compare, [First1 | Acc]) + end + end. + +-file("src/gleam/list.gleam", 1395). +?DOC(" This is the same as merge_ascending_pairs but flipped for descending lists.\n"). +-spec merge_descending_pairs( + list(list(AKA)), + fun((AKA, AKA) -> gleam@order:order()), + list(list(AKA)) +) -> list(list(AKA)). +merge_descending_pairs(Sequences, Compare, Acc) -> + case Sequences of + [] -> + lists:reverse(Acc); + + [Sequence] -> + lists:reverse([lists:reverse(Sequence) | Acc]); + + [Descending1, Descending2 | Rest] -> + Ascending = merge_descendings(Descending1, Descending2, Compare, []), + merge_descending_pairs(Rest, Compare, [Ascending | Acc]) + end. + +-file("src/gleam/list.gleam", 1339). +?DOC( + " Given some some sorted sequences (assumed to be sorted in `direction`) it\n" + " merges them all together until we're left with just a list sorted in\n" + " ascending order.\n" +). +-spec merge_all( + list(list(AJQ)), + sorting(), + fun((AJQ, AJQ) -> gleam@order:order()) +) -> list(AJQ). +merge_all(Sequences, Direction, Compare) -> + case {Sequences, Direction} of + {[], _} -> + []; + + {[Sequence], ascending} -> + Sequence; + + {[Sequence@1], descending} -> + lists:reverse(Sequence@1); + + {_, ascending} -> + Sequences@1 = merge_ascending_pairs(Sequences, Compare, []), + merge_all(Sequences@1, descending, Compare); + + {_, descending} -> + Sequences@2 = merge_descending_pairs(Sequences, Compare, []), + merge_all(Sequences@2, ascending, Compare) + end. + +-file("src/gleam/list.gleam", 1210). +?DOC( + " Sorts from smallest to largest based upon the ordering specified by a given\n" + " function.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " import gleam/int\n" + "\n" + " sort([4, 3, 6, 5, 4, 1, 2], by: int.compare)\n" + " // -> [1, 2, 3, 4, 4, 5, 6]\n" + " ```\n" +). +-spec sort(list(AJG), fun((AJG, AJG) -> gleam@order:order())) -> list(AJG). +sort(List, Compare) -> + case List of + [] -> + []; + + [X] -> + [X]; + + [X@1, Y | Rest] -> + Direction = case Compare(X@1, Y) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + Sequences = sequences(Rest, Compare, [X@1], Direction, Y, []), + merge_all(Sequences, ascending, Compare) + end. + +-file("src/gleam/list.gleam", 1487). +-spec range_loop(integer(), integer(), list(integer())) -> list(integer()). +range_loop(Start, Stop, Acc) -> + case gleam@int:compare(Start, Stop) of + eq -> + [Stop | Acc]; + + gt -> + range_loop(Start, Stop + 1, [Stop | Acc]); + + lt -> + range_loop(Start, Stop - 1, [Stop | Acc]) + end. + +-file("src/gleam/list.gleam", 1483). +?DOC( + " Creates a list of ints ranging from a given start and finish.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " range(0, 0)\n" + " // -> [0]\n" + " ```\n" + "\n" + " ```gleam\n" + " range(0, 5)\n" + " // -> [0, 1, 2, 3, 4, 5]\n" + " ```\n" + "\n" + " ```gleam\n" + " range(1, -5)\n" + " // -> [1, 0, -1, -2, -3, -4, -5]\n" + " ```\n" +). +-spec range(integer(), integer()) -> list(integer()). +range(Start, Stop) -> + range_loop(Start, Stop, []). + +-file("src/gleam/list.gleam", 1513). +-spec repeat_loop(AKV, integer(), list(AKV)) -> list(AKV). +repeat_loop(Item, Times, Acc) -> + case Times =< 0 of + true -> + Acc; + + false -> + repeat_loop(Item, Times - 1, [Item | Acc]) + end. + +-file("src/gleam/list.gleam", 1509). +?DOC( + " Builds a list of a given value a given number of times.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " repeat(\"a\", times: 0)\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " repeat(\"a\", times: 5)\n" + " // -> [\"a\", \"a\", \"a\", \"a\", \"a\"]\n" + " ```\n" +). +-spec repeat(AKT, integer()) -> list(AKT). +repeat(A, Times) -> + repeat_loop(A, Times, []). + +-file("src/gleam/list.gleam", 1546). +-spec split_loop(list(ALC), integer(), list(ALC)) -> {list(ALC), list(ALC)}. +split_loop(List, N, Taken) -> + case N =< 0 of + true -> + {lists:reverse(Taken), List}; + + false -> + case List of + [] -> + {lists:reverse(Taken), []}; + + [First | Rest] -> + split_loop(Rest, N - 1, [First | Taken]) + end + end. + +-file("src/gleam/list.gleam", 1542). +?DOC( + " Splits a list in two before the given index.\n" + "\n" + " If the list is not long enough to have the given index the before list will\n" + " be the input list, and the after list will be empty.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " split([6, 7, 8, 9], 0)\n" + " // -> #([], [6, 7, 8, 9])\n" + " ```\n" + "\n" + " ```gleam\n" + " split([6, 7, 8, 9], 2)\n" + " // -> #([6, 7], [8, 9])\n" + " ```\n" + "\n" + " ```gleam\n" + " split([6, 7, 8, 9], 4)\n" + " // -> #([6, 7, 8, 9], [])\n" + " ```\n" +). +-spec split(list(AKY), integer()) -> {list(AKY), list(AKY)}. +split(List, Index) -> + split_loop(List, Index, []). + +-file("src/gleam/list.gleam", 1582). +-spec split_while_loop(list(ALL), fun((ALL) -> boolean()), list(ALL)) -> {list(ALL), + list(ALL)}. +split_while_loop(List, F, Acc) -> + case List of + [] -> + {lists:reverse(Acc), []}; + + [First | Rest] -> + case F(First) of + true -> + split_while_loop(Rest, F, [First | Acc]); + + false -> + {lists:reverse(Acc), List} + end + end. + +-file("src/gleam/list.gleam", 1575). +?DOC( + " Splits a list in two before the first element that a given function returns\n" + " `False` for.\n" + "\n" + " If the function returns `True` for all elements the first list will be the\n" + " input list, and the second list will be empty.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 })\n" + " // -> #([1, 2, 3], [4, 5])\n" + " ```\n" + "\n" + " ```gleam\n" + " split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 })\n" + " // -> #([1, 2, 3, 4, 5], [])\n" + " ```\n" +). +-spec split_while(list(ALH), fun((ALH) -> boolean())) -> {list(ALH), list(ALH)}. +split_while(List, Predicate) -> + split_while_loop(List, Predicate, []). + +-file("src/gleam/list.gleam", 1622). +?DOC( + " Given a list of 2-element tuples, finds the first tuple that has a given\n" + " key as the first element and returns the second element.\n" + "\n" + " If no tuple is found with the given key then `Error(Nil)` is returned.\n" + "\n" + " This function may be useful for interacting with Erlang code where lists of\n" + " tuples are common.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_find([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" + " // -> Ok(0)\n" + " ```\n" + "\n" + " ```gleam\n" + " key_find([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" + " // -> Ok(1)\n" + " ```\n" + "\n" + " ```gleam\n" + " key_find([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec key_find(list({ALQ, ALR}), ALQ) -> {ok, ALR} | {error, nil}. +key_find(Keyword_list, Desired_key) -> + find_map( + Keyword_list, + fun(Keyword) -> + {Key, Value} = Keyword, + case Key =:= Desired_key of + true -> + {ok, Value}; + + false -> + {error, nil} + end + end + ). + +-file("src/gleam/list.gleam", 1653). +?DOC( + " Given a list of 2-element tuples, finds all tuples that have a given\n" + " key as the first element and returns the second element.\n" + "\n" + " This function may be useful for interacting with Erlang code where lists of\n" + " tuples are common.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_filter([#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)], \"a\")\n" + " // -> [0, 2]\n" + " ```\n" + "\n" + " ```gleam\n" + " key_filter([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" + " // -> []\n" + " ```\n" +). +-spec key_filter(list({ALV, ALW}), ALV) -> list(ALW). +key_filter(Keyword_list, Desired_key) -> + filter_map( + Keyword_list, + fun(Keyword) -> + {Key, Value} = Keyword, + case Key =:= Desired_key of + true -> + {ok, Value}; + + false -> + {error, nil} + end + end + ). + +-file("src/gleam/list.gleam", 1693). +-spec key_pop_loop(list({AMF, AMG}), AMF, list({AMF, AMG})) -> {ok, + {AMG, list({AMF, AMG})}} | + {error, nil}. +key_pop_loop(List, Key, Checked) -> + case List of + [] -> + {error, nil}; + + [{K, V} | Rest] when K =:= Key -> + {ok, {V, reverse_and_prepend(Checked, Rest)}}; + + [First | Rest@1] -> + key_pop_loop(Rest@1, Key, [First | Checked]) + end. + +-file("src/gleam/list.gleam", 1689). +?DOC( + " Given a list of 2-element tuples, finds the first tuple that has a given\n" + " key as the first element. This function will return the second element\n" + " of the found tuple and list with tuple removed.\n" + "\n" + " If no tuple is found with the given key then `Error(Nil)` is returned.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_pop([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" + " // -> Ok(#(0, [#(\"b\", 1)]))\n" + " ```\n" + "\n" + " ```gleam\n" + " key_pop([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" + " // -> Ok(#(1, [#(\"a\", 0)]))\n" + " ```\n" + "\n" + " ```gleam\n" + " key_pop([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec key_pop(list({ALZ, AMA}), ALZ) -> {ok, {AMA, list({ALZ, AMA})}} | + {error, nil}. +key_pop(List, Key) -> + key_pop_loop(List, Key, []). + +-file("src/gleam/list.gleam", 1727). +-spec key_set_loop(list({AMQ, AMR}), AMQ, AMR, list({AMQ, AMR})) -> list({AMQ, + AMR}). +key_set_loop(List, Key, Value, Inspected) -> + case List of + [{K, _} | Rest] when K =:= Key -> + reverse_and_prepend(Inspected, [{K, Value} | Rest]); + + [First | Rest@1] -> + key_set_loop(Rest@1, Key, Value, [First | Inspected]); + + [] -> + lists:reverse([{Key, Value} | Inspected]) + end. + +-file("src/gleam/list.gleam", 1723). +?DOC( + " Given a list of 2-element tuples, inserts a key and value into the list.\n" + "\n" + " If there was already a tuple with the key then it is replaced, otherwise it\n" + " is added to the end of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_set([#(5, 0), #(4, 1)], 4, 100)\n" + " // -> [#(5, 0), #(4, 100)]\n" + " ```\n" + "\n" + " ```gleam\n" + " key_set([#(5, 0), #(4, 1)], 1, 100)\n" + " // -> [#(5, 0), #(4, 1), #(1, 100)]\n" + " ```\n" +). +-spec key_set(list({AMM, AMN}), AMM, AMN) -> list({AMM, AMN}). +key_set(List, Key, Value) -> + key_set_loop(List, Key, Value, []). + +-file("src/gleam/list.gleam", 1755). +?DOC( + " Calls a function for each element in a list, discarding the return value.\n" + "\n" + " Useful for calling a side effect for every item of a list.\n" + "\n" + " ```gleam\n" + " import gleam/io\n" + "\n" + " each([\"1\", \"2\", \"3\"], io.println)\n" + " // -> Nil\n" + " // 1\n" + " // 2\n" + " // 3\n" + " ```\n" +). +-spec each(list(AMV), fun((AMV) -> any())) -> nil. +each(List, F) -> + case List of + [] -> + nil; + + [First | Rest] -> + F(First), + each(Rest, F) + end. + +-file("src/gleam/list.gleam", 1781). +?DOC( + " Calls a `Result` returning function for each element in a list, discarding\n" + " the return value. If the function returns `Error` then the iteration is\n" + " stopped and the error is returned.\n" + "\n" + " Useful for calling a side effect for every item of a list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " try_each(\n" + " over: [1, 2, 3],\n" + " with: function_that_might_fail,\n" + " )\n" + " // -> Ok(Nil)\n" + " ```\n" +). +-spec try_each(list(AMY), fun((AMY) -> {ok, any()} | {error, ANB})) -> {ok, nil} | + {error, ANB}. +try_each(List, Fun) -> + case List of + [] -> + {ok, nil}; + + [First | Rest] -> + case Fun(First) of + {ok, _} -> + try_each(Rest, Fun); + + {error, E} -> + {error, E} + end + end. + +-file("src/gleam/list.gleam", 1814). +-spec partition_loop(list(BGB), fun((BGB) -> boolean()), list(BGB), list(BGB)) -> {list(BGB), + list(BGB)}. +partition_loop(List, Categorise, Trues, Falses) -> + case List of + [] -> + {lists:reverse(Trues), lists:reverse(Falses)}; + + [First | Rest] -> + case Categorise(First) of + true -> + partition_loop(Rest, Categorise, [First | Trues], Falses); + + false -> + partition_loop(Rest, Categorise, Trues, [First | Falses]) + end + end. + +-file("src/gleam/list.gleam", 1807). +?DOC( + " Partitions a list into a tuple/pair of lists\n" + " by a given categorisation function.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " import gleam/int\n" + "\n" + " [1, 2, 3, 4, 5] |> partition(int.is_odd)\n" + " // -> #([1, 3, 5], [2, 4])\n" + " ```\n" +). +-spec partition(list(ANG), fun((ANG) -> boolean())) -> {list(ANG), list(ANG)}. +partition(List, Categorise) -> + partition_loop(List, Categorise, [], []). + +-file("src/gleam/list.gleam", 1834). +?DOC( + " Returns all the permutations of a list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " permutations([1, 2])\n" + " // -> [[1, 2], [2, 1]]\n" + " ```\n" +). +-spec permutations(list(ANP)) -> list(list(ANP)). +permutations(List) -> + case List of + [] -> + [[]]; + + [_ | _] -> + _pipe@3 = index_map( + List, + fun(I, I_idx) -> + _pipe = index_fold( + List, + [], + fun(Acc, J, J_idx) -> case I_idx =:= J_idx of + true -> + Acc; + + false -> + [J | Acc] + end end + ), + _pipe@1 = lists:reverse(_pipe), + _pipe@2 = permutations(_pipe@1), + map(_pipe@2, fun(Permutation) -> [I | Permutation] end) + end + ), + lists:append(_pipe@3) + end. + +-file("src/gleam/list.gleam", 1874). +-spec window_loop(list(list(ANX)), list(ANX), integer()) -> list(list(ANX)). +window_loop(Acc, List, N) -> + Window = take(List, N), + case erlang:length(Window) =:= N of + true -> + window_loop([Window | Acc], drop(List, 1), N); + + false -> + lists:reverse(Acc) + end. + +-file("src/gleam/list.gleam", 1867). +?DOC( + " Returns a list of sliding windows.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " window([1,2,3,4,5], 3)\n" + " // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]\n" + " ```\n" + "\n" + " ```gleam\n" + " window([1, 2], 4)\n" + " // -> []\n" + " ```\n" +). +-spec window(list(ANT), integer()) -> list(list(ANT)). +window(List, N) -> + case N =< 0 of + true -> + []; + + false -> + window_loop([], List, N) + end. + +-file("src/gleam/list.gleam", 1897). +?DOC( + " Returns a list of tuples containing two contiguous elements.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " window_by_2([1,2,3,4])\n" + " // -> [#(1, 2), #(2, 3), #(3, 4)]\n" + " ```\n" + "\n" + " ```gleam\n" + " window_by_2([1])\n" + " // -> []\n" + " ```\n" +). +-spec window_by_2(list(AOD)) -> list({AOD, AOD}). +window_by_2(List) -> + zip(List, drop(List, 1)). + +-file("src/gleam/list.gleam", 1910). +?DOC( + " Drops the first elements in a given list for which the predicate function returns `True`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " drop_while([1, 2, 3, 4], fn (x) { x < 3 })\n" + " // -> [3, 4]\n" + " ```\n" +). +-spec drop_while(list(AOG), fun((AOG) -> boolean())) -> list(AOG). +drop_while(List, Predicate) -> + case List of + [] -> + []; + + [First | Rest] -> + case Predicate(First) of + true -> + drop_while(Rest, Predicate); + + false -> + [First | Rest] + end + end. + +-file("src/gleam/list.gleam", 1940). +-spec take_while_loop(list(AOM), fun((AOM) -> boolean()), list(AOM)) -> list(AOM). +take_while_loop(List, Predicate, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + case Predicate(First) of + true -> + take_while_loop(Rest, Predicate, [First | Acc]); + + false -> + lists:reverse(Acc) + end + end. + +-file("src/gleam/list.gleam", 1933). +?DOC( + " Takes the first elements in a given list for which the predicate function returns `True`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " take_while([1, 2, 3, 2, 4], fn (x) { x < 3 })\n" + " // -> [1, 2]\n" + " ```\n" +). +-spec take_while(list(AOJ), fun((AOJ) -> boolean())) -> list(AOJ). +take_while(List, Predicate) -> + take_while_loop(List, Predicate, []). + +-file("src/gleam/list.gleam", 1972). +-spec chunk_loop(list(AOV), fun((AOV) -> AOX), AOX, list(AOV), list(list(AOV))) -> list(list(AOV)). +chunk_loop(List, F, Previous_key, Current_chunk, Acc) -> + case List of + [First | Rest] -> + Key = F(First), + case Key =:= Previous_key of + true -> + chunk_loop(Rest, F, Key, [First | Current_chunk], Acc); + + false -> + New_acc = [lists:reverse(Current_chunk) | Acc], + chunk_loop(Rest, F, Key, [First], New_acc) + end; + + [] -> + lists:reverse([lists:reverse(Current_chunk) | Acc]) + end. + +-file("src/gleam/list.gleam", 1965). +?DOC( + " Returns a list of chunks in which\n" + " the return value of calling `f` on each element is the same.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 })\n" + " // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n" + " ```\n" +). +-spec chunk(list(AOQ), fun((AOQ) -> any())) -> list(list(AOQ)). +chunk(List, F) -> + case List of + [] -> + []; + + [First | Rest] -> + chunk_loop(Rest, F, F(First), [First], []) + end. + +-file("src/gleam/list.gleam", 2017). +-spec sized_chunk_loop( + list(APH), + integer(), + integer(), + list(APH), + list(list(APH)) +) -> list(list(APH)). +sized_chunk_loop(List, Count, Left, Current_chunk, Acc) -> + case List of + [] -> + case Current_chunk of + [] -> + lists:reverse(Acc); + + Remaining -> + lists:reverse([lists:reverse(Remaining) | Acc]) + end; + + [First | Rest] -> + Chunk = [First | Current_chunk], + case Left > 1 of + true -> + sized_chunk_loop(Rest, Count, Left - 1, Chunk, Acc); + + false -> + sized_chunk_loop( + Rest, + Count, + Count, + [], + [lists:reverse(Chunk) | Acc] + ) + end + end. + +-file("src/gleam/list.gleam", 2013). +?DOC( + " Returns a list of chunks containing `count` elements each.\n" + "\n" + " If the last chunk does not have `count` elements, it is instead\n" + " a partial chunk, with less than `count` elements.\n" + "\n" + " For any `count` less than 1 this function behaves as if it was set to 1.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2)\n" + " // -> [[1, 2], [3, 4], [5, 6]]\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3)\n" + " // -> [[1, 2, 3], [4, 5, 6], [7, 8]]\n" + " ```\n" +). +-spec sized_chunk(list(APD), integer()) -> list(list(APD)). +sized_chunk(List, Count) -> + sized_chunk_loop(List, Count, Count, [], []). + +-file("src/gleam/list.gleam", 2061). +?DOC( + " This function acts similar to fold, but does not take an initial state.\n" + " Instead, it starts from the first element in the list\n" + " and combines it with each subsequent element in turn using the given\n" + " function. The function is called as `fun(accumulator, current_element)`.\n" + "\n" + " Returns `Ok` to indicate a successful run, and `Error` if called on an\n" + " empty list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [] |> reduce(fn(acc, x) { acc + x })\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x })\n" + " // -> Ok(15)\n" + " ```\n" +). +-spec reduce(list(APO), fun((APO, APO) -> APO)) -> {ok, APO} | {error, nil}. +reduce(List, Fun) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + {ok, fold(Rest, First, Fun)} + end. + +-file("src/gleam/list.gleam", 2085). +-spec scan_loop(list(APW), APY, list(APY), fun((APY, APW) -> APY)) -> list(APY). +scan_loop(List, Accumulator, Accumulated, Fun) -> + case List of + [] -> + lists:reverse(Accumulated); + + [First | Rest] -> + Next = Fun(Accumulator, First), + scan_loop(Rest, Next, [Next | Accumulated], Fun) + end. + +-file("src/gleam/list.gleam", 2077). +?DOC( + " Similar to `fold`, but yields the state of the accumulator at each stage.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i })\n" + " // -> [101, 103, 106]\n" + " ```\n" +). +-spec scan(list(APS), APU, fun((APU, APS) -> APU)) -> list(APU). +scan(List, Initial, Fun) -> + scan_loop(List, Initial, [], Fun). + +-file("src/gleam/list.gleam", 2118). +?DOC( + " Returns the last element in the given list.\n" + "\n" + " Returns `Error(Nil)` if the list is empty.\n" + "\n" + " This function runs in linear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " last([])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " last([1, 2, 3, 4, 5])\n" + " // -> Ok(5)\n" + " ```\n" +). +-spec last(list(AQB)) -> {ok, AQB} | {error, nil}. +last(List) -> + case List of + [] -> + {error, nil}; + + [Last] -> + {ok, Last}; + + [_ | Rest] -> + last(Rest) + end. + +-file("src/gleam/list.gleam", 2140). +?DOC( + " Return unique combinations of elements in the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " combinations([1, 2, 3], 2)\n" + " // -> [[1, 2], [1, 3], [2, 3]]\n" + " ```\n" + "\n" + " ```gleam\n" + " combinations([1, 2, 3, 4], 3)\n" + " // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]\n" + " ```\n" +). +-spec combinations(list(AQF), integer()) -> list(list(AQF)). +combinations(Items, N) -> + case {N, Items} of + {0, _} -> + [[]]; + + {_, []} -> + []; + + {_, [First | Rest]} -> + _pipe = combinations(Rest, N - 1), + _pipe@1 = map(_pipe, fun(Combination) -> [First | Combination] end), + _pipe@2 = lists:reverse(_pipe@1), + fold(_pipe@2, combinations(Rest, N), fun(Acc, C) -> [C | Acc] end) + end. + +-file("src/gleam/list.gleam", 2165). +-spec combination_pairs_loop(list(AQM), list({AQM, AQM})) -> list({AQM, AQM}). +combination_pairs_loop(Items, Acc) -> + case Items of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + First_combinations = map(Rest, fun(Other) -> {First, Other} end), + Acc@1 = reverse_and_prepend(First_combinations, Acc), + combination_pairs_loop(Rest, Acc@1) + end. + +-file("src/gleam/list.gleam", 2161). +?DOC( + " Return unique pair combinations of elements in the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " combination_pairs([1, 2, 3])\n" + " // -> [#(1, 2), #(1, 3), #(2, 3)]\n" + " ```\n" +). +-spec combination_pairs(list(AQJ)) -> list({AQJ, AQJ}). +combination_pairs(Items) -> + combination_pairs_loop(Items, []). + +-file("src/gleam/list.gleam", 2220). +-spec take_firsts(list(list(ARG)), list(ARG), list(list(ARG))) -> {list(ARG), + list(list(ARG))}. +take_firsts(Rows, Column, Remaining_rows) -> + case Rows of + [] -> + {lists:reverse(Column), lists:reverse(Remaining_rows)}; + + [[] | Rest] -> + take_firsts(Rest, Column, Remaining_rows); + + [[First | Remaining_row] | Rest_rows] -> + Remaining_rows@1 = [Remaining_row | Remaining_rows], + take_firsts(Rest_rows, [First | Column], Remaining_rows@1) + end. + +-file("src/gleam/list.gleam", 2207). +-spec transpose_loop(list(list(AQZ)), list(list(AQZ))) -> list(list(AQZ)). +transpose_loop(Rows, Columns) -> + case Rows of + [] -> + lists:reverse(Columns); + + _ -> + {Column, Rest} = take_firsts(Rows, [], []), + case Column of + [_ | _] -> + transpose_loop(Rest, [Column | Columns]); + + [] -> + transpose_loop(Rest, Columns) + end + end. + +-file("src/gleam/list.gleam", 2203). +?DOC( + " Transpose rows and columns of the list of lists.\n" + "\n" + " Notice: This function is not tail recursive,\n" + " and thus may exceed stack size if called,\n" + " with large lists (on the JavaScript target).\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " transpose([[1, 2, 3], [101, 102, 103]])\n" + " // -> [[1, 101], [2, 102], [3, 103]]\n" + " ```\n" +). +-spec transpose(list(list(AQU))) -> list(list(AQU)). +transpose(List_of_lists) -> + transpose_loop(List_of_lists, []). + +-file("src/gleam/list.gleam", 2185). +?DOC( + " Make a list alternating the elements from the given lists\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " interleave([[1, 2], [101, 102], [201, 202]])\n" + " // -> [1, 101, 201, 2, 102, 202]\n" + " ```\n" +). +-spec interleave(list(list(AQQ))) -> list(AQQ). +interleave(List) -> + _pipe = transpose(List), + lists:append(_pipe). + +-file("src/gleam/list.gleam", 2253). +-spec shuffle_pair_unwrap_loop(list({float(), ARS}), list(ARS)) -> list(ARS). +shuffle_pair_unwrap_loop(List, Acc) -> + case List of + [] -> + Acc; + + [Elem_pair | Enumerable] -> + shuffle_pair_unwrap_loop( + Enumerable, + [erlang:element(2, Elem_pair) | Acc] + ) + end. + +-file("src/gleam/list.gleam", 2261). +-spec do_shuffle_by_pair_indexes(list({float(), ARW})) -> list({float(), ARW}). +do_shuffle_by_pair_indexes(List_of_pairs) -> + sort( + List_of_pairs, + fun(A_pair, B_pair) -> + gleam@float:compare( + erlang:element(1, A_pair), + erlang:element(1, B_pair) + ) + end + ). + +-file("src/gleam/list.gleam", 2246). +?DOC( + " Takes a list, randomly sorts all items and returns the shuffled list.\n" + "\n" + " This function uses `float.random` to decide the order of the elements.\n" + "\n" + " ## Example\n" + "\n" + " ```gleam\n" + " range(1, 10) |> shuffle()\n" + " // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5]\n" + " ```\n" +). +-spec shuffle(list(ARP)) -> list(ARP). +shuffle(List) -> + _pipe = List, + _pipe@1 = fold(_pipe, [], fun(Acc, A) -> [{rand:uniform(), A} | Acc] end), + _pipe@2 = do_shuffle_by_pair_indexes(_pipe@1), + shuffle_pair_unwrap_loop(_pipe@2, []). + +-file("src/gleam/list.gleam", 2293). +-spec max_loop(list(ASG), fun((ASG, ASG) -> gleam@order:order()), ASG) -> ASG. +max_loop(List, Compare, Max) -> + case List of + [] -> + Max; + + [First | Rest] -> + case Compare(First, Max) of + gt -> + max_loop(Rest, Compare, First); + + lt -> + max_loop(Rest, Compare, Max); + + eq -> + max_loop(Rest, Compare, Max) + end + end. + +-file("src/gleam/list.gleam", 2283). +?DOC( + " Takes a list and a comparator, and returns the maximum element in the list\n" + "\n" + "\n" + " ## Example\n" + "\n" + " ```gleam\n" + " range(1, 10) |> list.max(int.compare)\n" + " // -> Ok(10)\n" + " ```\n" + "\n" + " ```gleam\n" + " [\"a\", \"c\", \"b\"] |> list.max(string.compare)\n" + " // -> Ok(\"c\")\n" + " ```\n" +). +-spec max(list(ARZ), fun((ARZ, ARZ) -> gleam@order:order())) -> {ok, ARZ} | + {error, nil}. +max(List, Compare) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + {ok, max_loop(Rest, Compare, First)} + end. + +-file("src/gleam/list.gleam", 2374). +-spec build_reservoir_loop( + list(ASV), + integer(), + gleam@dict:dict(integer(), ASV) +) -> {gleam@dict:dict(integer(), ASV), list(ASV)}. +build_reservoir_loop(List, Size, Reservoir) -> + Reservoir_size = maps:size(Reservoir), + case Reservoir_size >= Size of + true -> + {Reservoir, List}; + + false -> + case List of + [] -> + {Reservoir, []}; + + [First | Rest] -> + Reservoir@1 = gleam@dict:insert( + Reservoir, + Reservoir_size, + First + ), + build_reservoir_loop(Rest, Size, Reservoir@1) + end + end. + +-file("src/gleam/list.gleam", 2370). +?DOC( + " Builds the initial reservoir used by Algorithm L.\n" + " This is a dictionary with keys ranging from `0` up to `n - 1` where each\n" + " value is the corresponding element at that position in `list`.\n" + "\n" + " This also returns the remaining elements of `list` that didn't end up in\n" + " the reservoir.\n" +). +-spec build_reservoir(list(ASQ), integer()) -> {gleam@dict:dict(integer(), ASQ), + list(ASQ)}. +build_reservoir(List, N) -> + build_reservoir_loop(List, N, maps:new()). + +-file("src/gleam/list.gleam", 2358). +-spec log_random() -> float(). +log_random() -> + Random@1 = case gleam@float:logarithm( + rand:uniform() + 2.2250738585072014e-308 + ) of + {ok, Random} -> Random; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <>, + module => <<"gleam/list"/utf8>>, + function => <<"log_random"/utf8>>, + line => 2359, + value => _assert_fail, + start => 55490, + 'end' => 55561, + pattern_start => 55501, + pattern_end => 55511}) + end, + Random@1. + +-file("src/gleam/list.gleam", 2335). +-spec sample_loop( + list(ASK), + gleam@dict:dict(integer(), ASK), + integer(), + float() +) -> gleam@dict:dict(integer(), ASK). +sample_loop(List, Reservoir, N, W) -> + Skip = begin + Log@1 = case gleam@float:logarithm(1.0 - W) of + {ok, Log} -> Log; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <>, + module => <<"gleam/list"/utf8>>, + function => <<"sample_loop"/utf8>>, + line => 2342, + value => _assert_fail, + start => 55051, + 'end' => 55097, + pattern_start => 55062, + pattern_end => 55069}) + end, + erlang:round(math:floor(case Log@1 of + +0.0 -> +0.0; + -0.0 -> -0.0; + Gleam@denominator -> log_random() / Gleam@denominator + end)) + end, + case drop(List, Skip) of + [] -> + Reservoir; + + [First | Rest] -> + Reservoir@1 = gleam@dict:insert( + Reservoir, + gleam@int:random(N), + First + ), + W@1 = W * math:exp(case erlang:float(N) of + +0.0 -> +0.0; + -0.0 -> -0.0; + Gleam@denominator@1 -> log_random() / Gleam@denominator@1 + end), + sample_loop(Rest, Reservoir@1, N, W@1) + end. + +-file("src/gleam/list.gleam", 2317). +?DOC( + " Returns a random sample of up to n elements from a list using reservoir\n" + " sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L).\n" + " Returns an empty list if the sample size is less than or equal to 0.\n" + "\n" + " Order is not random, only selection is.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " reservoir_sample([1, 2, 3, 4, 5], 3)\n" + " // -> [2, 4, 5] // A random sample of 3 items\n" + " ```\n" +). +-spec sample(list(ASH), integer()) -> list(ASH). +sample(List, N) -> + {Reservoir, Rest} = build_reservoir(List, N), + case gleam@dict:is_empty(Reservoir) of + true -> + []; + + false -> + W = math:exp(case erlang:float(N) of + +0.0 -> +0.0; + -0.0 -> -0.0; + Gleam@denominator -> log_random() / Gleam@denominator + end), + maps:values(sample_loop(Rest, Reservoir, N, W)) + end. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.cache new file mode 100644 index 0000000000000000000000000000000000000000..0bb7bd5e149eb642eaa6ad8fdab521803f024214 GIT binary patch literal 13525 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..8656c26a6732c744d9a78b34c76394e55653d6eb GIT binary patch literal 1485 zcmX}sYiJf!7zglY>Rj`Z=H_Lat#X;9UkbZvP@09vG8l7i@k$N1u~};@cmstlQYx)2 zn&hR#34VAbL8!z^oY0%t*zi^HR=AjKf+%Y&qoj$(`VrOxKRBH8aL(cI=cJ!n&=7Yj z>%YMteVL;5L)X*w|Ib9Mw)j3#p#AW7>jc6uG3!k!!-E{C1 z3&%y&(!hG&riBzoIZihh80K%XvmaP$aDoh@jLnV6Vh!vDk!CI1h zKr5fnNrqFLCToH_Go1n+qLc(R)RSZfhd4@_o8(T6C}tr~vWUer(#%FSv6U}4!ZEry z#|Sx-BBqc>DG8d{Obe~FF~AjWaFg+qWrl}&l*f6F)vV<;nn>{tUG#E^eg;@}cf@ik zNzlN@e9m4{9OOLxTw{nwrpOCr)bl!T(8O_0bB_5_?N2EQUZs&;9N-X#`H}04l5S1s<{-awgTL= 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, []). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache new file mode 100644 index 0000000000000000000000000000000000000000..76ec374191ac8f82dd2116b4d8f3a7017d24d3e1 GIT binary patch literal 5774 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 a9udtEk#12Wa5aF9to!ky5---5>Hh|W&8O`E literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..4404517ca4be50751de9a68d9658ab34e27040a1 GIT binary patch literal 677 zcmXxiJxCOA6aeu5*~is6+)~yMR%dRJq997t;vm!#=W&h=MrR*~G#MNs7lc7eMd+fK z9T!yUA}Dy3gM-8ken8Jj8?vK|L z#t#beHEwg498Y=1b9Vb)Q(%q~ANfSo)Or%M&_*XoZj#|14;khqW4vOT4}4~gFZ`pn zCWO;8(n1^Ubdco%c^>nENoJU1fn~n(ouB;XFR?=*)KO1@F4FYUPmUq-Jfh4B->9%f z>~ILDI7oLTI9uJhRNROqmUS@rO&tL%2*QU8J}}mUqmv U$Py=GAzYw?8>C3@^L_T>KXdw2X8-^I literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.erl new file mode 100644 index 0000000..5ad2cb2 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@order.erl @@ -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. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache new file mode 100644 index 0000000000000000000000000000000000000000..4d269850150dfb1247c1a270b7964c89c98cf5c5 GIT binary patch literal 2757 zcmb_e?Qc_67{AYXq1|0ac~WLq4B6Qhv#qk#_LvZtjkOLGj39Slj5UT{*1NUPH+oyf z6cZBT2R{(Ln4l321Th+842eVukPxFE^gqC0qQ>yS4}K&%P4JxC?xkBpAo`)V=brPN zm*4OAoZoYwn5Fw6U>G=(M%#z>T*xtf_}Gz|(598#G^Syc}|CMlf5*AHElR(RHeBY|dY`b1Eq79FN(RsykYAVu$PbLRL+i zIcm>2DnzfMChBQ1w>s14P~-XPs2ZboF-cNA1V<97Z7gI%bSeWZbc>{?ZW9*zi%n1c z!&oTd8=LC!v5@8OpW5$dy|ekMTeEryw?2Um%MXBH8U#RL#7QehxIrvNI8fa&Z&1sx zUWlQ7Du(G6S9AIjRzdx3O=AJ#TNerDz}gL9J+C^)p|MFT4Px4<)vG1f6t$cqyi*9L z;1r!wP2@|$79K9s6axcd*9p5=DLAfr%VaVh4`yS^(7;f9n@9`~n<5qyBRfRgoYXO< zsZPgn;XQ~1-Fds>0sQSD04iV#oI=gkAose69`#h9h5MlD+zH;+ z?O_KL!jd!Zp%nA^TF#@PNq{T#nJZ3q^gj4?$U67~Ly2u7uGq)~mq?I{&`Th4uV_~e zxz0@4prx#)^^ri78#QUNguY*-lWN8Mo&~m``q=nj&ra_gm%gK|okLOEsB4=ksMiZM6 zipoOX$%b&5Z!G7U7yaZ4*;JFI)K^ep zFy$xMwFLu!T~YO<hl0d$>v#85uNx3co*=$2;%bu@GlF}c<)#*i0&ew0zE;d zR|~SGogmHgJ&Yc$clm#m!&~@1YN*stXf-k!s_y>-tHJ2A6e5$2Gtn5JQ9N0btjHAQ^N zdOW1xwy}WS%N9UXsng)P)KlBRivO<+czM)soonDdr||yB@m;V^D7+_CX94tP?ZH0M z_CC+$k2|HM>+Ft-gSosbW^7dx3T{~(c0{&Zazx$Lw_Mkbtdq^p*fl3>3U{GYvrnk{ z;no~GJ0>z}>qdbP6BD9&yE6?3_~v}uva&p5siHJzE$5YHae-gt5K-keK(Kqv+N^H; zrKt6h`unBd`WeXNwByzbHAPv+c7zb$7)<#oc5lH*7}3Ou1g66Hlu2JWY8WZz68X&6T)FtrcuBGwo1+-1D-6@L9I-nkoJ^nrX7 z20_L^f_w=IAS+M>>B1$DpTbp;H{b`5x8VE&&U@< zUMF|Rz@LOlMxUed5G_$zp~tAaLBFH&dwPq?pXl#YcC$eyV@xvn8au<}hwMC)7uerS z4)Vvj9Op?c_wrY`Eb_Y6;$tqa@@pI!p>a+LY*HUDNrD|4ke>~8gD=%XaaS7mL~&0T zUrytz(`bkBSQ_hTTnOXaX*}JJr^EO`8ZV6Dg)m-Di>}100>{`+*0P|!IIG4_@i%$Pc+*H$g^WQGT0$CMUMmrJ I>a8UG7XtNNv;Y7A literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..daa77fc4347d01c110f4b8f4d1d7b8b292260479 GIT binary patch literal 403 zcmXxfu}T6^6b9g{DLp|`TZ>49h(k+3VpC8w8RQT_Z5gH**h@Gz6j4w?I7C5|luOW1 zLxWpTOM^p0qlhhih5qny&pFFE_c8gp83u_Ai`{m5WA*fUIX@hDlT0y7mL=9HQl-Wr zSKM&R9iMdQ(r46`aT27+u)-E4%2YVxf+j6qc;}lgeI}wIOp_(YJazUtpur^%bm$RA zLWr@z8rziEp~Vx=yz#*oV=?!VBEueajyUFo9}@8pCYfQ5MG6$DQsbN^_XEE1pS1oj G(a0~68#6!v literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.erl new file mode 100644 index 0000000..228140e --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@pair.erl @@ -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}. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.cache new file mode 100644 index 0000000000000000000000000000000000000000..dc5c1b937d31c4f0dcf63b85a517e78d0b38832d GIT binary patch literal 15479 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 IAhIy>f6olM)&Kwi literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..8283209e77fe4d446d9d99bdcf3ee6e1229affec GIT binary patch literal 1947 zcmXxldrXj37zf}3qKKuC;{7h#BrhaLS+YVaXQiekq;q97NnNPZyv4i?+%hx~Q3KJT zSvo7{D$%@lF*7o>O&4C~U+Iz*Z>3X*tfxk2d-i=hJ7@3t_WsVk&i%(t2@NA6qT!`k z!*g;@cGk3{oT=~3E;92GS^Wk~=#yGM>eT;B%?)Q2|E}4>$DHCcm$<@Rn%UEy?(`y= z;f&)ACQ-y@_E1R`C-{{{ks(CWmX7o$jS-Ax9N8@51J+VXC1myhE`@wZ8Rw~` zj?OW9M*=;`pnoZPD%Y7mq2%!bZ4CMtzF@b!_*upk;ah}`M6Zv2Wu?%7) z8H^{Jg>0sRBb?zTx4FYzhBgo3B_^|+a=v626*O%jOLQfP6w=8ci>XW_mtxA<#%EmQ z7E!VKNH=W((WcMK!;3nQPRM5T`beGnhP9vzh&T!*_g7yNBeFzNC@PNZw{1 zi^*pdpYt`}@&i#VLx?Al!92|nhO(MZ*v?)K@-r8>&K>HAY2`cV%RmM(h55WkDH|zg z6W92QM)9&sJc&HP5T4^@W|2n$D=A|?$2dtf7l>^g!XqT}7zPh8|4ksU&4!Z7AAkNNyan~t*0Rz77Phd4$=C-q3AAG29U38mC< zk5-*Sc!hPWX9F8K%u%X2$0b6S5L(iKF7#m-S;{g>*uZwKQcshf{%N!&led`8EEaQ&>)fG^xL)oqFEWuC6tJBg>}=o!|BZhD Dg)k2D literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.erl new file mode 100644 index 0000000..3a0deb5 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@result.erl @@ -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. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache new file mode 100644 index 0000000000000000000000000000000000000000..1832ba4b54d5d59977a4cacd0ae02d248ac5e679 GIT binary patch literal 16777 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..e5bd75e58b0eb4da8415e982f4799788bdd6d70d GIT binary patch literal 1761 zcmY+^drVhV902eGD3m6c&+w6^q9rr4&}AlR3XN)W=4!b~XoA0ZB`G$QC@ft|GAKYCJo%6ltd;fX#zDVeb zsF<#s9$nW+LC%80@!7cxi#r>J^8cQK+@;00YaP!mbjFP_OLCSjD=5Cl^9&mPJ@jlz z#gOLrqB`HW5uM{Y`)86yIlDPXGsihW8_~waFpyD0PLj|)guaYq3@M~Ci}@6=oHADP15vSZMK>n#0E@_DB`;IXyVTIgA&%0_ z3C?hhgt!ofF@|Iovyw_aW*gP~MgN;ZNF)3?YsQOeBpAo+6)Btl=1~v~h{M9povL@Btt3 zDfKiE)yw%Ho=mD~AXc9^?bvAj`An*eN;CoJjh!1@hc}e#cA&C8^V*! zC6_{0vXLD$a)e_f^$TGh&yYnu`#8XPE)vtLWA&%0_35NP9k7FW}SYPMIvy|7VU_A{S<~Od;eYkoe wi-qK{h&pz$hYqgO^A39=o%uXZ32(58t$f0H;z!6Gvsl8btfhjtyM(Uz4~?nym;e9( literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.erl new file mode 100644 index 0000000..6a15c29 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@set.erl @@ -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)). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.cache new file mode 100644 index 0000000000000000000000000000000000000000..e493e510bed2cfd55dc22e3c45d0a813b649ffd7 GIT binary patch literal 35323 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..bfebc838451b81c79dbbccbe5c484913137ae598 GIT binary patch literal 3869 zcmY+`2XK`|9suw!1tg(J??gZp5$OoXp;AOTQ8-!<0U-uFY6wk`K@i5Hgc&>$X;Ksr z1rtCF@#K&u5a4Ksc))Q)Vx$c9fY2uQ%b0mH?96Z8&hGc^{@?C@_q}2rdJGBjOIT!n zB|85zVOadY;q`_M9h3B~me~|}q-W%)q@g26%+a=$!jJYP4vtSu*K~jqk93VmN*p>O zp?^|heEdNjcQ}=?!SbHZ;VxCff}jSCX+~Rm63=i( zGlhk$C56qLBAW|b96k{c7QjbQoB$mDmB7wPNaE3)0!a9Zk1ST_w z6>Q}=nOvgKV?ofGe)MMm-?EFn+~O`#g@T|c6=_5}V(HFgws4M2nnne|t8`>G^Z1Na zq_B@OWO0F#(ylY(nZSMyQA%Q!qb9X!MjXQ#%S2|fgm3tc@3~Hxge}Vxw4etg8P6o% zV+!lZresm`5zj)F@HHv?z!e@+pqRCwEbZyTK;lW{b5hyL5A5dwg&#LQ<)}d~1~ZIN z?BE!gTqUx&Iq1j;X0V+DoFLrEil!LFDM1S+vWd+^mJ}QDjAbG-N#iglIZe@0LC}F@ z=CPZ7{K6S7Qn_>xG~p#$Gmmv_V?URvTSl(ZonG`Ij%4PulGSYD0#RkfO&JC-iDV9N zn4=scs+<_9LN)5rmv=~H9MehRAN)iHCn-?g_*9`9Jz2mR{zKIY_JhVWqb+YUjwwtd zo!d017z7PTWE?Y@#V2fGHwQVwW0iuS74I^MgB;-;S=^v}5Y0L_aB)>B~-TbC2j6+NnfK`Y@1q zK4KSVIY%b7o(h8Iyw4{rW+}_K$Q8;w9RwAqMID;cgCUF}i4=}-jN_EA>9>LwjAs(> zF@-e#&aY&1hx-(I#`@5Mehg$STiHV{5w+wf1u0D(TGNLFCXmdRT;~>d$f3!zVy7cr z>B}_!#uApZp5vV7GS_%WjoNaa7PO=rgPFpotl=OL&)H9^(um=VW(-NBu$f)#lEP+oae`|Uu4|8YnX!yxK3{N_U&-P(D%X?ijA0Rr`Gr%Q zrg(j^5XX8_In95$#{URwAXaM8famGQRHiYVHJspQe&+@c$t7rLeP~KMI?ILVXc!u&9hOvm_ z6mBjq+R%fW&wN2qQooiJIYa>p2YDEBbY=wncU<) zxzuSZe%7#-+l0R=2Fg;An!G@JUgOUUWIV|%U=jc1ELVtZC%=fMFuhsLA&!#CZ`>rT zy}5{?I`wEvFZwfxPx+3MT;~>d$l;X^a+-9uafqXw9WzGVlexke5Tc($`OVj*Ag4XJG8CU>ab#ht@zbfY^{N#i_OlI~Hm?5qe{7s4Xgg= 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) -> + <>. + +-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 + 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, <>) + 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, + <<<>/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 -> + <> + 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 + <> -> + 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(<>, []). + +-file("src/gleam/string.gleam", 663). +?DOC( + " Converts a `String` to a `List` of `UtfCodepoint`.\n" + "\n" + " See and\n" + " 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 and\n" + " 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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache new file mode 100644 index 0000000000000000000000000000000000000000..ed930dd795069617b8590398a0717d35482d818a GIT binary patch literal 14138 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 U7<7-q2W}?rpfWia0L9V&0=GT8SO5S3 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..abfcf6a5e95e84863043c38a0ea00a48f1cb0d89 GIT binary patch literal 911 zcmXZbNk|ny7y#hWms@*kMnwf3j1)8?5vd@=LZ!%qg<2LKL-oVE{%s#_E`2}S)AzET$qLsPPSW{PBRi9l~ z+t4`Mu!O&{H@{_0|BSqfj+hO}q;QZ2Oj2N}7KZsiMr;Usso)+{6h}h1%6&Q+V33qK zA*>^lLiSO~0b036H@zgqg|LxLg zK@NG;ah-7{NKbSxwo}9jI{3;MX-VdjLmoA>@tQZx5b@NjSxX5Q=;kS(86$U|GgC}6 zkNLtV%jbu%ib9&X!(D#!hiwb=afBw$(99r1yd!pD2wSM<5M2!LjBzp-g|MGW+PTFG zrioh|LMrRo%r16Q!bN)M= 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). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache new file mode 100644 index 0000000000000000000000000000000000000000..638f372cb0a4fe35b4d8722549680dfd1a69eaf0 GIT binary patch literal 31127 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 T#So~F)e-2D^%B@3+ba8ino%9q literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..d4e5f349726790ca8289e8f3370187498efb0069 GIT binary patch literal 3253 zcmZYBX>eB6835oTAfl9gHPt`}VF?fw0TC2I2q2rp5DFx0YM_BYkVKGF772tm zO2;@z3uSOx*#e3NN|G|9AQhQXA(i4_8=?t@t)S38Y3UE9cjlSze)r5d_uTh=&$%~q zO2UuBt>cb6Z=KwI>vwv3>eN{eq|MISaz_YzxaYQp^t8;Zy{;bS2e-9k%*jg2m|g1n zKmV^SGiz?z?CIBPuGb2o$!-1q+cr6CZfa@+jgRoVvCnTPzZf;_rt|+DF-~I1<_L`q z)`H<|re?Y|6RVj(&5dft>dm9P#10B5;Rxm2RXcUgGkpd2LhHKOk*n4P53_Te_63>yrB7R05YdB1kx}J+c3}qZCq_LS@9ON9~t`Isf zkQA1(g&pjph(lZ@u3iW;$!8N)^q2G`-r!Ag*~A`>QpR~|sezVE<1Nl{m45ZbijOIx zn3k$yGTS&ny#^s9u#AQ1h-WZsIY2o#iEnI<6jDqHja1VF zUSm1OXxlV|Ic(%T%4pRrg!_pin)bw#%nX*YjXYG&WE8W=A&;$8@h#P~yx*MY&(oxk#p|5p zJdu$hv|$?g?BoUyw$X1ij`UyzQ^;cth5U(@okDnu*<|q|`Ml2+I(L>Y#*oBXwo*mASl37< zh1L9;3L?9xVTLf2L~{6q6a0l!oF=NPJ&YOT^BH${vlhr?3uQEoGaf@(&km0A35_0* zcSiFnyV%Vc8a-%FCx#C6p&$JjKoT>_W;yxn;0oOzQYUPun(p2GXFJt&f7pLA*});c zBd&+I(~}u2W;-W1#cAsHlp}^Shk4AWn2TIuP%k-V9@)IiLVnLxu5q1)kH`nT8NwLS zS;Br!5Yby3*(~7|c2i2@N7WQln8tJp_==`|tR0@?=e)~t>i6|dp#`mIOl|Z5knclLiSR7kg*v+JoCtA zCAn;%lrQ)@6~x7R|1+9p{E`Cp@&Vs6aIoCfnG_SA5L{s<}wyNOjLh5|~OVb1CFgs=3ZhVn(?yvv`>$KQm}uRxfNh+h?ijVgbQVy=Wo}SA$vP*JwnQspX1+4H7%+D literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.erl new file mode 100644 index 0000000..f64a9db --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam@uri.erl @@ -0,0 +1,1117 @@ +-module(gleam@uri). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleam/uri.gleam"). +-export([parse_query/1, percent_encode/1, query_to_string/1, percent_decode/1, path_segments/1, to_string/1, origin/1, merge/2, parse/1]). +-export_type([uri/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( + " Utilities for working with URIs\n" + "\n" + " This module provides functions for working with URIs (for example, parsing\n" + " URIs or encoding query strings). The functions in this module are implemented\n" + " according to [RFC 3986](https://tools.ietf.org/html/rfc3986).\n" + "\n" + " Query encoding (Form encoding) is defined in the\n" + " [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data).\n" +). + +-type uri() :: {uri, + gleam@option:option(binary()), + gleam@option:option(binary()), + gleam@option:option(binary()), + gleam@option:option(integer()), + binary(), + gleam@option:option(binary()), + gleam@option:option(binary())}. + +-file("src/gleam/uri.gleam", 289). +-spec is_valid_host_within_brackets_char(integer()) -> boolean(). +is_valid_host_within_brackets_char(Char) -> + (((((48 >= Char) andalso (Char =< 57)) orelse ((65 >= Char) andalso (Char =< 90))) + orelse ((97 >= Char) andalso (Char =< 122))) + orelse (Char =:= 58)) + orelse (Char =:= 46). + +-file("src/gleam/uri.gleam", 503). +-spec parse_fragment(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_fragment(Rest, Pieces) -> + {ok, + begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + erlang:element(4, _record), + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + {some, Rest}} + end}. + +-file("src/gleam/uri.gleam", 475). +-spec parse_query_with_question_mark_loop(binary(), binary(), uri(), integer()) -> {ok, + uri()} | + {error, nil}. +parse_query_with_question_mark_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"#"/utf8, Rest/binary>> when Size =:= 0 -> + parse_fragment(Rest, Pieces); + + <<"#"/utf8, Rest@1/binary>> -> + Query = binary:part(Original, 0, Size), + Pieces@1 = begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + erlang:element(4, _record), + erlang:element(5, _record), + erlang:element(6, _record), + {some, Query}, + erlang:element(8, _record)} + end, + parse_fragment(Rest@1, Pieces@1); + + <<""/utf8>> -> + {ok, + begin + _record@1 = Pieces, + {uri, + erlang:element(2, _record@1), + erlang:element(3, _record@1), + erlang:element(4, _record@1), + erlang:element(5, _record@1), + erlang:element(6, _record@1), + {some, Original}, + erlang:element(8, _record@1)} + end}; + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_query_with_question_mark_loop( + Original, + Rest@2, + Pieces, + Size + 1 + ) + end. + +-file("src/gleam/uri.gleam", 468). +-spec parse_query_with_question_mark(binary(), uri()) -> {ok, uri()} | + {error, nil}. +parse_query_with_question_mark(Uri_string, Pieces) -> + parse_query_with_question_mark_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 434). +-spec parse_path_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | + {error, nil}. +parse_path_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"?"/utf8, Rest/binary>> -> + Path = binary:part(Original, 0, Size), + Pieces@1 = begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + erlang:element(4, _record), + erlang:element(5, _record), + Path, + erlang:element(7, _record), + erlang:element(8, _record)} + end, + parse_query_with_question_mark(Rest, Pieces@1); + + <<"#"/utf8, Rest@1/binary>> -> + Path@1 = binary:part(Original, 0, Size), + Pieces@2 = begin + _record@1 = Pieces, + {uri, + erlang:element(2, _record@1), + erlang:element(3, _record@1), + erlang:element(4, _record@1), + erlang:element(5, _record@1), + Path@1, + erlang:element(7, _record@1), + erlang:element(8, _record@1)} + end, + parse_fragment(Rest@1, Pieces@2); + + <<""/utf8>> -> + {ok, + begin + _record@2 = Pieces, + {uri, + erlang:element(2, _record@2), + erlang:element(3, _record@2), + erlang:element(4, _record@2), + erlang:element(5, _record@2), + Original, + erlang:element(7, _record@2), + erlang:element(8, _record@2)} + end}; + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_path_loop(Original, Rest@2, Pieces, Size + 1) + end. + +-file("src/gleam/uri.gleam", 430). +-spec parse_path(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_path(Uri_string, Pieces) -> + parse_path_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 385). +-spec parse_port_loop(binary(), uri(), integer()) -> {ok, uri()} | {error, nil}. +parse_port_loop(Uri_string, Pieces, Port) -> + case Uri_string of + <<"0"/utf8, Rest/binary>> -> + parse_port_loop(Rest, Pieces, Port * 10); + + <<"1"/utf8, Rest@1/binary>> -> + parse_port_loop(Rest@1, Pieces, (Port * 10) + 1); + + <<"2"/utf8, Rest@2/binary>> -> + parse_port_loop(Rest@2, Pieces, (Port * 10) + 2); + + <<"3"/utf8, Rest@3/binary>> -> + parse_port_loop(Rest@3, Pieces, (Port * 10) + 3); + + <<"4"/utf8, Rest@4/binary>> -> + parse_port_loop(Rest@4, Pieces, (Port * 10) + 4); + + <<"5"/utf8, Rest@5/binary>> -> + parse_port_loop(Rest@5, Pieces, (Port * 10) + 5); + + <<"6"/utf8, Rest@6/binary>> -> + parse_port_loop(Rest@6, Pieces, (Port * 10) + 6); + + <<"7"/utf8, Rest@7/binary>> -> + parse_port_loop(Rest@7, Pieces, (Port * 10) + 7); + + <<"8"/utf8, Rest@8/binary>> -> + parse_port_loop(Rest@8, Pieces, (Port * 10) + 8); + + <<"9"/utf8, Rest@9/binary>> -> + parse_port_loop(Rest@9, Pieces, (Port * 10) + 9); + + <<"?"/utf8, Rest@10/binary>> -> + Pieces@1 = begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + erlang:element(4, _record), + {some, Port}, + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end, + parse_query_with_question_mark(Rest@10, Pieces@1); + + <<"#"/utf8, Rest@11/binary>> -> + Pieces@2 = begin + _record@1 = Pieces, + {uri, + erlang:element(2, _record@1), + erlang:element(3, _record@1), + erlang:element(4, _record@1), + {some, Port}, + erlang:element(6, _record@1), + erlang:element(7, _record@1), + erlang:element(8, _record@1)} + end, + parse_fragment(Rest@11, Pieces@2); + + <<"/"/utf8, _/binary>> -> + Pieces@3 = begin + _record@2 = Pieces, + {uri, + erlang:element(2, _record@2), + erlang:element(3, _record@2), + erlang:element(4, _record@2), + {some, Port}, + erlang:element(6, _record@2), + erlang:element(7, _record@2), + erlang:element(8, _record@2)} + end, + parse_path(Uri_string, Pieces@3); + + <<""/utf8>> -> + {ok, + begin + _record@3 = Pieces, + {uri, + erlang:element(2, _record@3), + erlang:element(3, _record@3), + erlang:element(4, _record@3), + {some, Port}, + erlang:element(6, _record@3), + erlang:element(7, _record@3), + erlang:element(8, _record@3)} + end}; + + _ -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 353). +-spec parse_port(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_port(Uri_string, Pieces) -> + case Uri_string of + <<":0"/utf8, Rest/binary>> -> + parse_port_loop(Rest, Pieces, 0); + + <<":1"/utf8, Rest@1/binary>> -> + parse_port_loop(Rest@1, Pieces, 1); + + <<":2"/utf8, Rest@2/binary>> -> + parse_port_loop(Rest@2, Pieces, 2); + + <<":3"/utf8, Rest@3/binary>> -> + parse_port_loop(Rest@3, Pieces, 3); + + <<":4"/utf8, Rest@4/binary>> -> + parse_port_loop(Rest@4, Pieces, 4); + + <<":5"/utf8, Rest@5/binary>> -> + parse_port_loop(Rest@5, Pieces, 5); + + <<":6"/utf8, Rest@6/binary>> -> + parse_port_loop(Rest@6, Pieces, 6); + + <<":7"/utf8, Rest@7/binary>> -> + parse_port_loop(Rest@7, Pieces, 7); + + <<":8"/utf8, Rest@8/binary>> -> + parse_port_loop(Rest@8, Pieces, 8); + + <<":9"/utf8, Rest@9/binary>> -> + parse_port_loop(Rest@9, Pieces, 9); + + <<":"/utf8, _/binary>> -> + {error, nil}; + + <<"?"/utf8, Rest@10/binary>> -> + parse_query_with_question_mark(Rest@10, Pieces); + + <<"#"/utf8, Rest@11/binary>> -> + parse_fragment(Rest@11, Pieces); + + <<"/"/utf8, _/binary>> -> + parse_path(Uri_string, Pieces); + + <<""/utf8>> -> + {ok, Pieces}; + + _ -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 309). +-spec parse_host_outside_of_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, + uri()} | + {error, nil}. +parse_host_outside_of_brackets_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<""/utf8>> -> + {ok, + begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + {some, Original}, + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end}; + + <<":"/utf8, _/binary>> -> + Host = binary:part(Original, 0, Size), + Pieces@1 = begin + _record@1 = Pieces, + {uri, + erlang:element(2, _record@1), + erlang:element(3, _record@1), + {some, Host}, + erlang:element(5, _record@1), + erlang:element(6, _record@1), + erlang:element(7, _record@1), + erlang:element(8, _record@1)} + end, + parse_port(Uri_string, Pieces@1); + + <<"/"/utf8, _/binary>> -> + Host@1 = binary:part(Original, 0, Size), + Pieces@2 = begin + _record@2 = Pieces, + {uri, + erlang:element(2, _record@2), + erlang:element(3, _record@2), + {some, Host@1}, + erlang:element(5, _record@2), + erlang:element(6, _record@2), + erlang:element(7, _record@2), + erlang:element(8, _record@2)} + end, + parse_path(Uri_string, Pieces@2); + + <<"?"/utf8, Rest/binary>> -> + Host@2 = binary:part(Original, 0, Size), + Pieces@3 = begin + _record@3 = Pieces, + {uri, + erlang:element(2, _record@3), + erlang:element(3, _record@3), + {some, Host@2}, + erlang:element(5, _record@3), + erlang:element(6, _record@3), + erlang:element(7, _record@3), + erlang:element(8, _record@3)} + end, + parse_query_with_question_mark(Rest, Pieces@3); + + <<"#"/utf8, Rest@1/binary>> -> + Host@3 = binary:part(Original, 0, Size), + Pieces@4 = begin + _record@4 = Pieces, + {uri, + erlang:element(2, _record@4), + erlang:element(3, _record@4), + {some, Host@3}, + erlang:element(5, _record@4), + erlang:element(6, _record@4), + erlang:element(7, _record@4), + erlang:element(8, _record@4)} + end, + parse_fragment(Rest@1, Pieces@4); + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_host_outside_of_brackets_loop( + Original, + Rest@2, + Pieces, + Size + 1 + ) + end. + +-file("src/gleam/uri.gleam", 229). +-spec parse_host_within_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, + uri()} | + {error, nil}. +parse_host_within_brackets_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<""/utf8>> -> + {ok, + begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + {some, Uri_string}, + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end}; + + <<"]"/utf8, Rest/binary>> when Size =:= 0 -> + parse_port(Rest, Pieces); + + <<"]"/utf8, Rest@1/binary>> -> + Host = binary:part(Original, 0, Size + 1), + Pieces@1 = begin + _record@1 = Pieces, + {uri, + erlang:element(2, _record@1), + erlang:element(3, _record@1), + {some, Host}, + erlang:element(5, _record@1), + erlang:element(6, _record@1), + erlang:element(7, _record@1), + erlang:element(8, _record@1)} + end, + parse_port(Rest@1, Pieces@1); + + <<"/"/utf8, _/binary>> when Size =:= 0 -> + parse_path(Uri_string, Pieces); + + <<"/"/utf8, _/binary>> -> + Host@1 = binary:part(Original, 0, Size), + Pieces@2 = begin + _record@2 = Pieces, + {uri, + erlang:element(2, _record@2), + erlang:element(3, _record@2), + {some, Host@1}, + erlang:element(5, _record@2), + erlang:element(6, _record@2), + erlang:element(7, _record@2), + erlang:element(8, _record@2)} + end, + parse_path(Uri_string, Pieces@2); + + <<"?"/utf8, Rest@2/binary>> when Size =:= 0 -> + parse_query_with_question_mark(Rest@2, Pieces); + + <<"?"/utf8, Rest@3/binary>> -> + Host@2 = binary:part(Original, 0, Size), + Pieces@3 = begin + _record@3 = Pieces, + {uri, + erlang:element(2, _record@3), + erlang:element(3, _record@3), + {some, Host@2}, + erlang:element(5, _record@3), + erlang:element(6, _record@3), + erlang:element(7, _record@3), + erlang:element(8, _record@3)} + end, + parse_query_with_question_mark(Rest@3, Pieces@3); + + <<"#"/utf8, Rest@4/binary>> when Size =:= 0 -> + parse_fragment(Rest@4, Pieces); + + <<"#"/utf8, Rest@5/binary>> -> + Host@3 = binary:part(Original, 0, Size), + Pieces@4 = begin + _record@4 = Pieces, + {uri, + erlang:element(2, _record@4), + erlang:element(3, _record@4), + {some, Host@3}, + erlang:element(5, _record@4), + erlang:element(6, _record@4), + erlang:element(7, _record@4), + erlang:element(8, _record@4)} + end, + parse_fragment(Rest@5, Pieces@4); + + _ -> + {Char, Rest@6} = gleam_stdlib:string_pop_codeunit(Uri_string), + case is_valid_host_within_brackets_char(Char) of + true -> + parse_host_within_brackets_loop( + Original, + Rest@6, + Pieces, + Size + 1 + ); + + false -> + parse_host_outside_of_brackets_loop( + Original, + Original, + Pieces, + 0 + ) + end + end. + +-file("src/gleam/uri.gleam", 222). +-spec parse_host_within_brackets(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_host_within_brackets(Uri_string, Pieces) -> + parse_host_within_brackets_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 302). +-spec parse_host_outside_of_brackets(binary(), uri()) -> {ok, uri()} | + {error, nil}. +parse_host_outside_of_brackets(Uri_string, Pieces) -> + parse_host_outside_of_brackets_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 199). +-spec parse_host(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_host(Uri_string, Pieces) -> + case Uri_string of + <<"["/utf8, _/binary>> -> + parse_host_within_brackets(Uri_string, Pieces); + + <<":"/utf8, _/binary>> -> + Pieces@1 = begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + {some, <<""/utf8>>}, + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end, + parse_port(Uri_string, Pieces@1); + + <<""/utf8>> -> + {ok, + begin + _record@1 = Pieces, + {uri, + erlang:element(2, _record@1), + erlang:element(3, _record@1), + {some, <<""/utf8>>}, + erlang:element(5, _record@1), + erlang:element(6, _record@1), + erlang:element(7, _record@1), + erlang:element(8, _record@1)} + end}; + + _ -> + parse_host_outside_of_brackets(Uri_string, Pieces) + end. + +-file("src/gleam/uri.gleam", 167). +-spec parse_userinfo_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | + {error, nil}. +parse_userinfo_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"@"/utf8, Rest/binary>> when Size =:= 0 -> + parse_host(Rest, Pieces); + + <<"@"/utf8, Rest@1/binary>> -> + Userinfo = binary:part(Original, 0, Size), + Pieces@1 = begin + _record = Pieces, + {uri, + erlang:element(2, _record), + {some, Userinfo}, + erlang:element(4, _record), + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end, + parse_host(Rest@1, Pieces@1); + + <<""/utf8>> -> + parse_host(Original, Pieces); + + <<"/"/utf8, _/binary>> -> + parse_host(Original, Pieces); + + <<"?"/utf8, _/binary>> -> + parse_host(Original, Pieces); + + <<"#"/utf8, _/binary>> -> + parse_host(Original, Pieces); + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_userinfo_loop(Original, Rest@2, Pieces, Size + 1) + end. + +-file("src/gleam/uri.gleam", 163). +-spec parse_authority_pieces(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_authority_pieces(String, Pieces) -> + parse_userinfo_loop(String, String, Pieces, 0). + +-file("src/gleam/uri.gleam", 150). +-spec parse_authority_with_slashes(binary(), uri()) -> {ok, uri()} | + {error, nil}. +parse_authority_with_slashes(Uri_string, Pieces) -> + case Uri_string of + <<"//"/utf8>> -> + {ok, + begin + _record = Pieces, + {uri, + erlang:element(2, _record), + erlang:element(3, _record), + {some, <<""/utf8>>}, + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end}; + + <<"//"/utf8, Rest/binary>> -> + parse_authority_pieces(Rest, Pieces); + + _ -> + parse_path(Uri_string, Pieces) + end. + +-file("src/gleam/uri.gleam", 91). +-spec parse_scheme_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | + {error, nil}. +parse_scheme_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"/"/utf8, _/binary>> when Size =:= 0 -> + parse_authority_with_slashes(Uri_string, Pieces); + + <<"/"/utf8, _/binary>> -> + Scheme = binary:part(Original, 0, Size), + Pieces@1 = begin + _record = Pieces, + {uri, + {some, string:lowercase(Scheme)}, + erlang:element(3, _record), + erlang:element(4, _record), + erlang:element(5, _record), + erlang:element(6, _record), + erlang:element(7, _record), + erlang:element(8, _record)} + end, + parse_authority_with_slashes(Uri_string, Pieces@1); + + <<"?"/utf8, Rest/binary>> when Size =:= 0 -> + parse_query_with_question_mark(Rest, Pieces); + + <<"?"/utf8, Rest@1/binary>> -> + Scheme@1 = binary:part(Original, 0, Size), + Pieces@2 = begin + _record@1 = Pieces, + {uri, + {some, string:lowercase(Scheme@1)}, + erlang:element(3, _record@1), + erlang:element(4, _record@1), + erlang:element(5, _record@1), + erlang:element(6, _record@1), + erlang:element(7, _record@1), + erlang:element(8, _record@1)} + end, + parse_query_with_question_mark(Rest@1, Pieces@2); + + <<"#"/utf8, Rest@2/binary>> when Size =:= 0 -> + parse_fragment(Rest@2, Pieces); + + <<"#"/utf8, Rest@3/binary>> -> + Scheme@2 = binary:part(Original, 0, Size), + Pieces@3 = begin + _record@2 = Pieces, + {uri, + {some, string:lowercase(Scheme@2)}, + erlang:element(3, _record@2), + erlang:element(4, _record@2), + erlang:element(5, _record@2), + erlang:element(6, _record@2), + erlang:element(7, _record@2), + erlang:element(8, _record@2)} + end, + parse_fragment(Rest@3, Pieces@3); + + <<":"/utf8, _/binary>> when Size =:= 0 -> + {error, nil}; + + <<":"/utf8, Rest@4/binary>> -> + Scheme@3 = binary:part(Original, 0, Size), + Pieces@4 = begin + _record@3 = Pieces, + {uri, + {some, string:lowercase(Scheme@3)}, + erlang:element(3, _record@3), + erlang:element(4, _record@3), + erlang:element(5, _record@3), + erlang:element(6, _record@3), + erlang:element(7, _record@3), + erlang:element(8, _record@3)} + end, + parse_authority_with_slashes(Rest@4, Pieces@4); + + <<""/utf8>> -> + {ok, + begin + _record@4 = Pieces, + {uri, + erlang:element(2, _record@4), + erlang:element(3, _record@4), + erlang:element(4, _record@4), + erlang:element(5, _record@4), + Original, + erlang:element(7, _record@4), + erlang:element(8, _record@4)} + end}; + + _ -> + {_, Rest@5} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_scheme_loop(Original, Rest@5, Pieces, Size + 1) + end. + +-file("src/gleam/uri.gleam", 534). +?DOC( + " Parses an urlencoded query string into a list of key value pairs.\n" + " Returns an error for invalid encoding.\n" + "\n" + " The opposite operation is `uri.query_to_string`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " parse_query(\"a=1&b=2\")\n" + " // -> Ok([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" + " ```\n" +). +-spec parse_query(binary()) -> {ok, list({binary(), binary()})} | {error, nil}. +parse_query(Query) -> + gleam_stdlib:parse_query(Query). + +-file("src/gleam/uri.gleam", 570). +?DOC( + " Encodes a string into a percent encoded representation.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " percent_encode(\"100% great\")\n" + " // -> \"100%25%20great\"\n" + " ```\n" +). +-spec percent_encode(binary()) -> binary(). +percent_encode(Value) -> + gleam_stdlib:percent_encode(Value). + +-file("src/gleam/uri.gleam", 555). +-spec query_pair({binary(), binary()}) -> gleam@string_tree:string_tree(). +query_pair(Pair) -> + gleam_stdlib:identity( + [gleam_stdlib:percent_encode(erlang:element(1, Pair)), + <<"="/utf8>>, + gleam_stdlib:percent_encode(erlang:element(2, Pair))] + ). + +-file("src/gleam/uri.gleam", 547). +?DOC( + " Encodes a list of key value pairs as a URI query string.\n" + "\n" + " The opposite operation is `uri.parse_query`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " query_to_string([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" + " // -> \"a=1&b=2\"\n" + " ```\n" +). +-spec query_to_string(list({binary(), binary()})) -> binary(). +query_to_string(Query) -> + _pipe = Query, + _pipe@1 = gleam@list:map(_pipe, fun query_pair/1), + _pipe@2 = gleam@list:intersperse( + _pipe@1, + gleam_stdlib:identity(<<"&"/utf8>>) + ), + _pipe@3 = gleam_stdlib:identity(_pipe@2), + unicode:characters_to_binary(_pipe@3). + +-file("src/gleam/uri.gleam", 583). +?DOC( + " Decodes a percent encoded string.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " percent_decode(\"100%25%20great+fun\")\n" + " // -> Ok(\"100% great+fun\")\n" + " ```\n" +). +-spec percent_decode(binary()) -> {ok, binary()} | {error, nil}. +percent_decode(Value) -> + gleam_stdlib:percent_decode(Value). + +-file("src/gleam/uri.gleam", 605). +-spec remove_dot_segments_loop(list(binary()), list(binary())) -> list(binary()). +remove_dot_segments_loop(Input, Accumulator) -> + case Input of + [] -> + lists:reverse(Accumulator); + + [Segment | Rest] -> + Accumulator@5 = case {Segment, Accumulator} of + {<<""/utf8>>, Accumulator@1} -> + Accumulator@1; + + {<<"."/utf8>>, Accumulator@2} -> + Accumulator@2; + + {<<".."/utf8>>, []} -> + []; + + {<<".."/utf8>>, [_ | Accumulator@3]} -> + Accumulator@3; + + {Segment@1, Accumulator@4} -> + [Segment@1 | Accumulator@4] + end, + remove_dot_segments_loop(Rest, Accumulator@5) + end. + +-file("src/gleam/uri.gleam", 601). +-spec remove_dot_segments(list(binary())) -> list(binary()). +remove_dot_segments(Input) -> + remove_dot_segments_loop(Input, []). + +-file("src/gleam/uri.gleam", 597). +?DOC( + " Splits the path section of a URI into it's constituent segments.\n" + "\n" + " Removes empty segments and resolves dot-segments as specified in\n" + " [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " path_segments(\"/users/1\")\n" + " // -> [\"users\" ,\"1\"]\n" + " ```\n" +). +-spec path_segments(binary()) -> list(binary()). +path_segments(Path) -> + remove_dot_segments(gleam@string:split(Path, <<"/"/utf8>>)). + +-file("src/gleam/uri.gleam", 636). +?DOC( + " Encodes a `Uri` value as a URI string.\n" + "\n" + " The opposite operation is `uri.parse`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " let uri = Uri(..empty, scheme: Some(\"https\"), host: Some(\"example.com\"))\n" + " to_string(uri)\n" + " // -> \"https://example.com\"\n" + " ```\n" +). +-spec to_string(uri()) -> binary(). +to_string(Uri) -> + Parts = case erlang:element(8, Uri) of + {some, Fragment} -> + [<<"#"/utf8>>, Fragment]; + + none -> + [] + end, + Parts@1 = case erlang:element(7, Uri) of + {some, Query} -> + [<<"?"/utf8>>, Query | Parts]; + + none -> + Parts + end, + Parts@2 = [erlang:element(6, Uri) | Parts@1], + Parts@3 = case {erlang:element(4, Uri), + gleam_stdlib:string_starts_with(erlang:element(6, Uri), <<"/"/utf8>>)} of + {{some, Host}, false} when Host =/= <<""/utf8>> -> + [<<"/"/utf8>> | Parts@2]; + + {_, _} -> + Parts@2 + end, + Parts@4 = case {erlang:element(4, Uri), erlang:element(5, Uri)} of + {{some, _}, {some, Port}} -> + [<<":"/utf8>>, erlang:integer_to_binary(Port) | Parts@3]; + + {_, _} -> + Parts@3 + end, + Parts@5 = case {erlang:element(2, Uri), + erlang:element(3, Uri), + erlang:element(4, Uri)} of + {{some, S}, {some, U}, {some, H}} -> + [S, <<"://"/utf8>>, U, <<"@"/utf8>>, H | Parts@4]; + + {{some, S@1}, none, {some, H@1}} -> + [S@1, <<"://"/utf8>>, H@1 | Parts@4]; + + {{some, S@2}, {some, _}, none} -> + [S@2, <<":"/utf8>> | Parts@4]; + + {{some, S@2}, none, none} -> + [S@2, <<":"/utf8>> | Parts@4]; + + {none, none, {some, H@2}} -> + [<<"//"/utf8>>, H@2 | Parts@4]; + + {_, _, _} -> + Parts@4 + end, + erlang:list_to_binary(Parts@5). + +-file("src/gleam/uri.gleam", 680). +?DOC( + " Fetches the origin of a URI.\n" + "\n" + " Returns the origin of a uri as defined in\n" + " [RFC 6454](https://tools.ietf.org/html/rfc6454)\n" + "\n" + " The supported URI schemes are `http` and `https`.\n" + " URLs without a scheme will return `Error`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " let assert Ok(uri) = parse(\"https://example.com/path?foo#bar\")\n" + " origin(uri)\n" + " // -> Ok(\"https://example.com\")\n" + " ```\n" +). +-spec origin(uri()) -> {ok, binary()} | {error, nil}. +origin(Uri) -> + {uri, Scheme, _, Host, Port, _, _, _} = Uri, + case {Host, Scheme} of + {{some, H}, {some, <<"https"/utf8>>}} when Port =:= {some, 443} -> + {ok, erlang:list_to_binary([<<"https://"/utf8>>, H])}; + + {{some, H@1}, {some, <<"http"/utf8>>}} when Port =:= {some, 80} -> + {ok, erlang:list_to_binary([<<"http://"/utf8>>, H@1])}; + + {{some, H@2}, {some, S}} when (S =:= <<"http"/utf8>>) orelse (S =:= <<"https"/utf8>>) -> + case Port of + {some, P} -> + {ok, + erlang:list_to_binary( + [S, + <<"://"/utf8>>, + H@2, + <<":"/utf8>>, + erlang:integer_to_binary(P)] + )}; + + none -> + {ok, erlang:list_to_binary([S, <<"://"/utf8>>, H@2])} + end; + + {_, _} -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 759). +-spec drop_last(list(DGQ)) -> list(DGQ). +drop_last(Elements) -> + gleam@list:take(Elements, erlang:length(Elements) - 1). + +-file("src/gleam/uri.gleam", 763). +-spec join_segments(list(binary())) -> binary(). +join_segments(Segments) -> + gleam@string:join([<<""/utf8>> | Segments], <<"/"/utf8>>). + +-file("src/gleam/uri.gleam", 703). +?DOC( + " Resolves a URI with respect to the given base URI.\n" + "\n" + " The base URI must be an absolute URI or this function will return an error.\n" + " The algorithm for merging uris is described in\n" + " [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2).\n" +). +-spec merge(uri(), uri()) -> {ok, uri()} | {error, nil}. +merge(Base, Relative) -> + case Base of + {uri, {some, _}, _, {some, _}, _, _, _, _} -> + case Relative of + {uri, _, _, {some, _}, _, _, _, _} -> + Path = begin + _pipe = gleam@string:split( + erlang:element(6, Relative), + <<"/"/utf8>> + ), + _pipe@1 = remove_dot_segments(_pipe), + join_segments(_pipe@1) + end, + Resolved = {uri, + gleam@option:'or'( + erlang:element(2, Relative), + erlang:element(2, Base) + ), + none, + erlang:element(4, Relative), + gleam@option:'or'( + erlang:element(5, Relative), + erlang:element(5, Base) + ), + Path, + erlang:element(7, Relative), + erlang:element(8, Relative)}, + {ok, Resolved}; + + _ -> + {New_path, New_query} = case erlang:element(6, Relative) of + <<""/utf8>> -> + {erlang:element(6, Base), + gleam@option:'or'( + erlang:element(7, Relative), + erlang:element(7, Base) + )}; + + _ -> + Path_segments = case gleam_stdlib:string_starts_with( + erlang:element(6, Relative), + <<"/"/utf8>> + ) of + true -> + gleam@string:split( + erlang:element(6, Relative), + <<"/"/utf8>> + ); + + false -> + _pipe@2 = gleam@string:split( + erlang:element(6, Base), + <<"/"/utf8>> + ), + _pipe@3 = drop_last(_pipe@2), + lists:append( + _pipe@3, + gleam@string:split( + erlang:element(6, Relative), + <<"/"/utf8>> + ) + ) + end, + Path@1 = begin + _pipe@4 = Path_segments, + _pipe@5 = remove_dot_segments(_pipe@4), + join_segments(_pipe@5) + end, + {Path@1, erlang:element(7, Relative)} + end, + Resolved@1 = {uri, + erlang:element(2, Base), + none, + erlang:element(4, Base), + erlang:element(5, Base), + New_path, + New_query, + erlang:element(8, Relative)}, + {ok, Resolved@1} + end; + + _ -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 81). +?DOC( + " Parses a compliant URI string into the `Uri` Type.\n" + " If the string is not a valid URI string then an error is returned.\n" + "\n" + " The opposite operation is `uri.to_string`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " parse(\"https://example.com:1234/a/b?query=true#fragment\")\n" + " // -> Ok(\n" + " // Uri(\n" + " // scheme: Some(\"https\"),\n" + " // userinfo: None,\n" + " // host: Some(\"example.com\"),\n" + " // port: Some(1234),\n" + " // path: \"/a/b\",\n" + " // query: Some(\"query=true\"),\n" + " // fragment: Some(\"fragment\")\n" + " // )\n" + " // )\n" + " ```\n" +). +-spec parse(binary()) -> {ok, uri()} | {error, nil}. +parse(Uri_string) -> + gleam_stdlib:uri_parse(Uri_string). diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.erl b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.erl new file mode 100644 index 0000000..0bfcd2f --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.erl @@ -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, 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, + <> + 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(<>, Acc) -> + case percent_ok(H) of + true -> + percent_encode(T, <>); + false -> + <> = <>, + percent_encode(T, <>) + 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, <>); + false -> + {error, nil} + end; +percent_decode(<>, Acc) -> + percent_decode(Cs, <>); +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) || <> <= 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) -> <> 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(<>, 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(<>, _PrevChar, _Acc) + when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) -> + {error, nil}; +inspect_maybe_gleam_atom(<>, none, Acc) -> + inspect_maybe_gleam_atom(Rest, First, <>); +inspect_maybe_gleam_atom(<<"_", Rest/binary>>, _PrevChar, Acc) -> + inspect_maybe_gleam_atom(Rest, $_, Acc); +inspect_maybe_gleam_atom(<>, $_, Acc) -> + inspect_maybe_gleam_atom(Rest, First, <>); +inspect_maybe_gleam_atom(<>, _PrevChar, Acc) -> + inspect_maybe_gleam_atom(Rest, 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, <<"<<">>), + <>">>. + +inspect_bit_array(<<>>, Acc) -> + Acc; +inspect_bit_array(<>, Acc) -> + inspect_bit_array(Rest, append_segment(Acc, erlang:integer_to_binary(X))); +inspect_bit_array(Rest, Acc) -> + Size = bit_size(Rest), + <> = Rest, + X1 = erlang:integer_to_binary(X), + Size1 = erlang:integer_to_binary(Size), + Segment = <>, + inspect_bit_array(<<>>, append_segment(Acc, Segment)). + +bit_array_to_int_and_size(A) -> + Size = bit_size(A), + <> = A, + {A1, Size}. + +append_segment(<<"<<">>, Segment) -> + <<"<<", Segment/binary>>; +append_segment(Acc, Segment) -> + <>. + + +inspect_maybe_utf8_string(Binary, Acc) -> + case Binary of + <<>> -> {ok, <<$", Acc/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 -> <> + end, + inspect_maybe_utf8_string(Rest, <>); + _ -> {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. diff --git a/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.mjs b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.mjs new file mode 100644 index 0000000..2edf3ad --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/_gleam_artefacts/gleam_stdlib.mjs @@ -0,0 +1,1044 @@ +import { + BitArray, + Error, + List, + Ok, + Result, + UtfCodepoint, + stringBits, + toBitArray, + bitArraySlice, + NonEmpty, + Empty, + CustomType, +} from "./gleam.mjs"; +import { Some, None } from "./gleam/option.mjs"; +import Dict from "./dict.mjs"; +import { classify } from "./gleam/dynamic.mjs"; +import { DecodeError } from "./gleam/dynamic/decode.mjs"; + +const Nil = undefined; +const NOT_FOUND = {}; + +export function identity(x) { + return x; +} + +export function parse_int(value) { + if (/^[-+]?(\d+)$/.test(value)) { + return new Ok(parseInt(value)); + } else { + return new Error(Nil); + } +} + +export function parse_float(value) { + if (/^[-+]?(\d+)\.(\d+)([eE][-+]?\d+)?$/.test(value)) { + return new Ok(parseFloat(value)); + } else { + return new Error(Nil); + } +} + +export function to_string(term) { + return term.toString(); +} + +export function int_to_base_string(int, base) { + return int.toString(base).toUpperCase(); +} + +const int_base_patterns = { + 2: /[^0-1]/, + 3: /[^0-2]/, + 4: /[^0-3]/, + 5: /[^0-4]/, + 6: /[^0-5]/, + 7: /[^0-6]/, + 8: /[^0-7]/, + 9: /[^0-8]/, + 10: /[^0-9]/, + 11: /[^0-9a]/, + 12: /[^0-9a-b]/, + 13: /[^0-9a-c]/, + 14: /[^0-9a-d]/, + 15: /[^0-9a-e]/, + 16: /[^0-9a-f]/, + 17: /[^0-9a-g]/, + 18: /[^0-9a-h]/, + 19: /[^0-9a-i]/, + 20: /[^0-9a-j]/, + 21: /[^0-9a-k]/, + 22: /[^0-9a-l]/, + 23: /[^0-9a-m]/, + 24: /[^0-9a-n]/, + 25: /[^0-9a-o]/, + 26: /[^0-9a-p]/, + 27: /[^0-9a-q]/, + 28: /[^0-9a-r]/, + 29: /[^0-9a-s]/, + 30: /[^0-9a-t]/, + 31: /[^0-9a-u]/, + 32: /[^0-9a-v]/, + 33: /[^0-9a-w]/, + 34: /[^0-9a-x]/, + 35: /[^0-9a-y]/, + 36: /[^0-9a-z]/, +}; + +export function int_from_base_string(string, base) { + if (int_base_patterns[base].test(string.replace(/^-/, "").toLowerCase())) { + return new Error(Nil); + } + + const result = parseInt(string, base); + + if (isNaN(result)) { + return new Error(Nil); + } + + return new Ok(result); +} + +export function string_replace(string, target, substitute) { + return string.replaceAll(target, substitute); +} + +export function string_reverse(string) { + return [...string].reverse().join(""); +} + +export function string_length(string) { + if (string === "") { + return 0; + } + const iterator = graphemes_iterator(string); + if (iterator) { + let i = 0; + for (const _ of iterator) { + i++; + } + return i; + } else { + return string.match(/./gsu).length; + } +} + +export function graphemes(string) { + const iterator = graphemes_iterator(string); + if (iterator) { + return List.fromArray(Array.from(iterator).map((item) => item.segment)); + } else { + return List.fromArray(string.match(/./gsu)); + } +} + +let segmenter = undefined; + +function graphemes_iterator(string) { + if (globalThis.Intl && Intl.Segmenter) { + segmenter ||= new Intl.Segmenter(); + return segmenter.segment(string)[Symbol.iterator](); + } +} + +export function pop_grapheme(string) { + let first; + const iterator = graphemes_iterator(string); + if (iterator) { + first = iterator.next().value?.segment; + } else { + first = string.match(/./su)?.[0]; + } + if (first) { + return new Ok([first, string.slice(first.length)]); + } else { + return new Error(Nil); + } +} + +export function pop_codeunit(str) { + return [str.charCodeAt(0) | 0, str.slice(1)]; +} + +export function lowercase(string) { + return string.toLowerCase(); +} + +export function uppercase(string) { + return string.toUpperCase(); +} + +export function less_than(a, b) { + return a < b; +} + +export function add(a, b) { + return a + b; +} + +export function split(xs, pattern) { + return List.fromArray(xs.split(pattern)); +} + +export function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} + +export function length(data) { + return data.length; +} + +export function string_slice(string, idx, len) { + if (len <= 0 || idx >= string.length) { + return ""; + } + + const iterator = graphemes_iterator(string); + if (iterator) { + while (idx-- > 0) { + iterator.next(); + } + + let result = ""; + + while (len-- > 0) { + const v = iterator.next().value; + if (v === undefined) { + break; + } + + result += v.segment; + } + + return result; + } else { + return string + .match(/./gsu) + .slice(idx, idx + len) + .join(""); + } +} + +export function string_codeunit_slice(str, from, length) { + return str.slice(from, from + length); +} +export function crop_string(string, substring) { + return string.substring(string.indexOf(substring)); +} + +export function contains_string(haystack, needle) { + return haystack.indexOf(needle) >= 0; +} + +export function starts_with(haystack, needle) { + return haystack.startsWith(needle); +} + +export function ends_with(haystack, needle) { + return haystack.endsWith(needle); +} + +export function split_once(haystack, needle) { + const index = haystack.indexOf(needle); + if (index >= 0) { + const before = haystack.slice(0, index); + const after = haystack.slice(index + needle.length); + return new Ok([before, after]); + } else { + return new Error(Nil); + } +} + +const unicode_whitespaces = [ + "\u0020", // Space + "\u0009", // Horizontal tab + "\u000A", // Line feed + "\u000B", // Vertical tab + "\u000C", // Form feed + "\u000D", // Carriage return + "\u0085", // Next line + "\u2028", // Line separator + "\u2029", // Paragraph separator +].join(""); + +const trim_start_regex = /* @__PURE__ */ new RegExp( + `^[${unicode_whitespaces}]*`, +); +const trim_end_regex = /* @__PURE__ */ new RegExp(`[${unicode_whitespaces}]*$`); + +export function trim_start(string) { + return string.replace(trim_start_regex, ""); +} + +export function trim_end(string) { + return string.replace(trim_end_regex, ""); +} + +export function bit_array_from_string(string) { + return toBitArray([stringBits(string)]); +} + +export function bit_array_bit_size(bit_array) { + return bit_array.bitSize; +} + +export function bit_array_byte_size(bit_array) { + return bit_array.byteSize; +} + +export function bit_array_pad_to_bytes(bit_array) { + const trailingBitsCount = bit_array.bitSize % 8; + + // If the bit array is a whole number of bytes it can be returned unchanged + if (trailingBitsCount === 0) { + return bit_array; + } + + const finalByte = bit_array.byteAt(bit_array.byteSize - 1); + + // The required final byte has its unused trailing bits set to zero + const unusedBitsCount = 8 - trailingBitsCount; + const correctFinalByte = (finalByte >> unusedBitsCount) << unusedBitsCount; + + // If the unused bits in the final byte are already set to zero then the + // existing buffer can be re-used, avoiding a copy + if (finalByte === correctFinalByte) { + return new BitArray( + bit_array.rawBuffer, + bit_array.byteSize * 8, + bit_array.bitOffset, + ); + } + + // Copy the bit array into a new aligned buffer and set the correct final byte + const buffer = new Uint8Array(bit_array.byteSize); + for (let i = 0; i < buffer.length - 1; i++) { + buffer[i] = bit_array.byteAt(i); + } + buffer[buffer.length - 1] = correctFinalByte; + + return new BitArray(buffer); +} + +export function bit_array_concat(bit_arrays) { + return toBitArray(bit_arrays.toArray()); +} + +export function console_log(term) { + console.log(term); +} + +export function console_error(term) { + console.error(term); +} + +export function crash(message) { + throw new globalThis.Error(message); +} + +export function bit_array_to_string(bit_array) { + // If the bit array isn't a whole number of bytes then return an error + if (bit_array.bitSize % 8 !== 0) { + return new Error(Nil); + } + + try { + const decoder = new TextDecoder("utf-8", { fatal: true }); + + if (bit_array.bitOffset === 0) { + return new Ok(decoder.decode(bit_array.rawBuffer)); + } else { + // The input data isn't aligned, so copy it into a new aligned buffer so + // that TextDecoder can be used + const buffer = new Uint8Array(bit_array.byteSize); + for (let i = 0; i < buffer.length; i++) { + buffer[i] = bit_array.byteAt(i); + } + return new Ok(decoder.decode(buffer)); + } + } catch { + return new Error(Nil); + } +} + +export function print(string) { + if (typeof process === "object" && process.stdout?.write) { + process.stdout.write(string); // We can write without a trailing newline + } else if (typeof Deno === "object") { + Deno.stdout.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline + } else { + console.log(string); // We're in a browser. Newlines are mandated + } +} + +export function print_error(string) { + if (typeof process === "object" && process.stderr?.write) { + process.stderr.write(string); // We can write without a trailing newline + } else if (typeof Deno === "object") { + Deno.stderr.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline + } else { + console.error(string); // We're in a browser. Newlines are mandated + } +} + +export function print_debug(string) { + if (typeof process === "object" && process.stderr?.write) { + process.stderr.write(string + "\n"); // If we're in Node.js, use `stderr` + } else if (typeof Deno === "object") { + Deno.stderr.writeSync(new TextEncoder().encode(string + "\n")); // If we're in Deno, use `stderr` + } else { + console.log(string); // Otherwise, use `console.log` (so that it doesn't look like an error) + } +} + +export function ceiling(float) { + return Math.ceil(float); +} + +export function floor(float) { + return Math.floor(float); +} + +export function round(float) { + return Math.round(float); +} + +export function truncate(float) { + return Math.trunc(float); +} + +export function power(base, exponent) { + // It is checked in Gleam that: + // - The base is non-negative and that the exponent is not fractional. + // - The base is non-zero and the exponent is non-negative (otherwise + // the result will essentially be division by zero). + // It can thus be assumed that valid input is passed to the Math.pow + // function and a NaN or Infinity value will not be produced. + return Math.pow(base, exponent); +} + +export function random_uniform() { + const random_uniform_result = Math.random(); + // With round-to-nearest-even behavior, the ranges claimed for the functions below + // (excluding the one for Math.random() itself) aren't exact. + // If extremely large bounds are chosen (2^53 or higher), + // it's possible in extremely rare cases to calculate the usually-excluded upper bound. + // Note that as numbers in JavaScript are IEEE 754 floating point numbers + // See: + // Because of this, we just loop 'until' we get a valid result where 0.0 <= x < 1.0: + if (random_uniform_result === 1.0) { + return random_uniform(); + } + return random_uniform_result; +} + +export function bit_array_slice(bits, position, length) { + const start = Math.min(position, position + length); + const end = Math.max(position, position + length); + + if (start < 0 || end * 8 > bits.bitSize) { + return new Error(Nil); + } + + return new Ok(bitArraySlice(bits, start * 8, end * 8)); +} + +export function codepoint(int) { + return new UtfCodepoint(int); +} + +export function string_to_codepoint_integer_list(string) { + return List.fromArray(Array.from(string).map((item) => item.codePointAt(0))); +} + +export function utf_codepoint_list_to_string(utf_codepoint_integer_list) { + return utf_codepoint_integer_list + .toArray() + .map((x) => String.fromCodePoint(x.value)) + .join(""); +} + +export function utf_codepoint_to_int(utf_codepoint) { + return utf_codepoint.value; +} + +export function new_map() { + return Dict.new(); +} + +export function map_size(map) { + return map.size; +} + +export function map_to_list(map) { + return List.fromArray(map.entries()); +} + +export function map_remove(key, map) { + return map.delete(key); +} + +export function map_get(map, key) { + const value = map.get(key, NOT_FOUND); + if (value === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value); +} + +export function map_insert(key, value, map) { + return map.set(key, value); +} + +function unsafe_percent_decode(string) { + return decodeURIComponent(string || ""); +} + +function unsafe_percent_decode_query(string) { + return decodeURIComponent((string || "").replace("+", " ")); +} + +export function percent_decode(string) { + try { + return new Ok(unsafe_percent_decode(string)); + } catch { + return new Error(Nil); + } +} + +export function percent_encode(string) { + return encodeURIComponent(string).replace("%2B", "+"); +} + +export function parse_query(query) { + try { + const pairs = []; + for (const section of query.split("&")) { + const [key, value] = section.split("="); + if (!key) continue; + + const decodedKey = unsafe_percent_decode_query(key); + const decodedValue = unsafe_percent_decode_query(value); + pairs.push([decodedKey, decodedValue]); + } + return new Ok(List.fromArray(pairs)); + } catch { + return new Error(Nil); + } +} + +const b64EncodeLookup = [ + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, +]; + +let b64TextDecoder; + +// Implementation based on https://github.com/mitschabaude/fast-base64/blob/main/js.js +export function encode64(bit_array, padding) { + b64TextDecoder ??= new TextDecoder(); + + bit_array = bit_array_pad_to_bytes(bit_array); + + const m = bit_array.byteSize; + const k = m % 3; + const n = Math.floor(m / 3) * 4 + (k && k + 1); + const N = Math.ceil(m / 3) * 4; + const encoded = new Uint8Array(N); + + for (let i = 0, j = 0; j < m; i += 4, j += 3) { + const y = + (bit_array.byteAt(j) << 16) + + (bit_array.byteAt(j + 1) << 8) + + (bit_array.byteAt(j + 2) | 0); + + encoded[i] = b64EncodeLookup[y >> 18]; + encoded[i + 1] = b64EncodeLookup[(y >> 12) & 0x3f]; + encoded[i + 2] = b64EncodeLookup[(y >> 6) & 0x3f]; + encoded[i + 3] = b64EncodeLookup[y & 0x3f]; + } + + let base64 = b64TextDecoder.decode(new Uint8Array(encoded.buffer, 0, n)); + + if (padding) { + if (k === 1) { + base64 += "=="; + } else if (k === 2) { + base64 += "="; + } + } + + return base64; +} + +// From https://developer.mozilla.org/en-US/docs/Glossary/Base64 +export function decode64(sBase64) { + try { + const binString = atob(sBase64); + const length = binString.length; + const array = new Uint8Array(length); + for (let i = 0; i < length; i++) { + array[i] = binString.charCodeAt(i); + } + return new Ok(new BitArray(array)); + } catch { + return new Error(Nil); + } +} + +export function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (typeof data === "boolean") { + return "Bool"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Array`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Nil"; + } else if (data === undefined) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} + +export function byte_size(string) { + return new TextEncoder().encode(string).length; +} + +// In JavaScript bitwise operations convert numbers to a sequence of 32 bits +// while Erlang uses arbitrary precision. +// To get around this problem and get consistent results use BigInt and then +// downcast the value back to a Number value. + +export function bitwise_and(x, y) { + return Number(BigInt(x) & BigInt(y)); +} + +export function bitwise_not(x) { + return Number(~BigInt(x)); +} + +export function bitwise_or(x, y) { + return Number(BigInt(x) | BigInt(y)); +} + +export function bitwise_exclusive_or(x, y) { + return Number(BigInt(x) ^ BigInt(y)); +} + +export function bitwise_shift_left(x, y) { + return Number(BigInt(x) << BigInt(y)); +} + +export function bitwise_shift_right(x, y) { + return Number(BigInt(x) >> BigInt(y)); +} + +export function inspect(v) { + return new Inspector().inspect(v); +} + +export function float_to_string(float) { + const string = float.toString().replace("+", ""); + if (string.indexOf(".") >= 0) { + return string; + } else { + const index = string.indexOf("e"); + if (index >= 0) { + return string.slice(0, index) + ".0" + string.slice(index); + } else { + return string + ".0"; + } + } +} + +class Inspector { + #references = new Set(); + + inspect(v) { + const t = typeof v; + if (v === true) return "True"; + if (v === false) return "False"; + if (v === null) return "//js(null)"; + if (v === undefined) return "Nil"; + if (t === "string") return this.#string(v); + if (t === "bigint" || Number.isInteger(v)) return v.toString(); + if (t === "number") return float_to_string(v); + if (v instanceof UtfCodepoint) return this.#utfCodepoint(v); + if (v instanceof BitArray) return this.#bit_array(v); + if (v instanceof RegExp) return `//js(${v})`; + if (v instanceof Date) return `//js(Date("${v.toISOString()}"))`; + if (v instanceof globalThis.Error) return `//js(${v.toString()})`; + if (v instanceof Function) { + const args = []; + for (const i of Array(v.length).keys()) + args.push(String.fromCharCode(i + 97)); + return `//fn(${args.join(", ")}) { ... }`; + } + + if (this.#references.size === this.#references.add(v).size) { + return "//js(circular reference)"; + } + + let printed; + if (Array.isArray(v)) { + printed = `#(${v.map((v) => this.inspect(v)).join(", ")})`; + } else if (v instanceof List) { + printed = this.#list(v); + } else if (v instanceof CustomType) { + printed = this.#customType(v); + } else if (v instanceof Dict) { + printed = this.#dict(v); + } else if (v instanceof Set) { + return `//js(Set(${[...v].map((v) => this.inspect(v)).join(", ")}))`; + } else { + printed = this.#object(v); + } + this.#references.delete(v); + return printed; + } + + #object(v) { + const name = Object.getPrototypeOf(v)?.constructor?.name || "Object"; + const props = []; + for (const k of Object.keys(v)) { + props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); + } + const body = props.length ? " " + props.join(", ") + " " : ""; + const head = name === "Object" ? "" : name + " "; + return `//js(${head}{${body}})`; + } + + #dict(map) { + let body = "dict.from_list(["; + let first = true; + map.forEach((value, key) => { + if (!first) body = body + ", "; + body = body + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")"; + first = false; + }); + return body + "])"; + } + + #customType(record) { + const props = Object.keys(record) + .map((label) => { + const value = this.inspect(record[label]); + return isNaN(parseInt(label)) ? `${label}: ${value}` : value; + }) + .join(", "); + return props + ? `${record.constructor.name}(${props})` + : record.constructor.name; + } + + #list(list) { + if (list instanceof Empty) { + return "[]"; + } + + let char_out = 'charlist.from_string("'; + let list_out = "["; + + let current = list; + while (current instanceof NonEmpty) { + let element = current.head; + current = current.tail; + + if (list_out !== "[") { + list_out += ", "; + } + list_out += this.inspect(element); + + if (char_out) { + if (Number.isInteger(element) && element >= 32 && element <= 126) { + char_out += String.fromCharCode(element); + } else { + char_out = null; + } + } + } + + if (char_out) { + return char_out + '")'; + } else { + return list_out + "]"; + } + } + + #string(str) { + let new_str = '"'; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + switch (char) { + case "\n": + new_str += "\\n"; + break; + case "\r": + new_str += "\\r"; + break; + case "\t": + new_str += "\\t"; + break; + case "\f": + new_str += "\\f"; + break; + case "\\": + new_str += "\\\\"; + break; + case '"': + new_str += '\\"'; + break; + default: + if (char < " " || (char > "~" && char < "\u{00A0}")) { + new_str += + "\\u{" + + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + + "}"; + } else { + new_str += char; + } + } + } + new_str += '"'; + return new_str; + } + + #utfCodepoint(codepoint) { + return `//utfcodepoint(${String.fromCodePoint(codepoint.value)})`; + } + + #bit_array(bits) { + if (bits.bitSize === 0) { + return "<<>>"; + } + + let acc = "<<"; + + for (let i = 0; i < bits.byteSize - 1; i++) { + acc += bits.byteAt(i).toString(); + acc += ", "; + } + + if (bits.byteSize * 8 === bits.bitSize) { + acc += bits.byteAt(bits.byteSize - 1).toString(); + } else { + const trailingBitsCount = bits.bitSize % 8; + acc += bits.byteAt(bits.byteSize - 1) >> (8 - trailingBitsCount); + acc += `:size(${trailingBitsCount})`; + } + + acc += ">>"; + return acc; + } +} + +export function base16_encode(bit_array) { + const trailingBitsCount = bit_array.bitSize % 8; + + let result = ""; + + for (let i = 0; i < bit_array.byteSize; i++) { + let byte = bit_array.byteAt(i); + + if (i === bit_array.byteSize - 1 && trailingBitsCount !== 0) { + const unusedBitsCount = 8 - trailingBitsCount; + byte = (byte >> unusedBitsCount) << unusedBitsCount; + } + + result += byte.toString(16).padStart(2, "0").toUpperCase(); + } + + return result; +} + +export function base16_decode(string) { + const bytes = new Uint8Array(string.length / 2); + for (let i = 0; i < string.length; i += 2) { + const a = parseInt(string[i], 16); + const b = parseInt(string[i + 1], 16); + if (isNaN(a) || isNaN(b)) return new Error(Nil); + bytes[i / 2] = a * 16 + b; + } + return new Ok(new BitArray(bytes)); +} + +export function bit_array_to_int_and_size(bits) { + const trailingBitsCount = bits.bitSize % 8; + const unusedBitsCount = trailingBitsCount === 0 ? 0 : 8 - trailingBitsCount; + + return [bits.byteAt(0) >> unusedBitsCount, bits.bitSize]; +} + +export function bit_array_starts_with(bits, prefix) { + if (prefix.bitSize > bits.bitSize) { + return false; + } + + // Check any whole bytes + const byteCount = Math.trunc(prefix.bitSize / 8); + for (let i = 0; i < byteCount; i++) { + if (bits.byteAt(i) !== prefix.byteAt(i)) { + return false; + } + } + + // Check any trailing bits at the end of the prefix + if (prefix.bitSize % 8 !== 0) { + const unusedBitsCount = 8 - (prefix.bitSize % 8); + if ( + bits.byteAt(byteCount) >> unusedBitsCount !== + prefix.byteAt(byteCount) >> unusedBitsCount + ) { + return false; + } + } + + return true; +} + +export function log(x) { + // It is checked in Gleam that: + // - The input is strictly positive (x > 0) + // - This ensures that Math.log will never return NaN or -Infinity + // The function can thus safely pass the input to Math.log + // and a valid finite float will always be produced. + return Math.log(x); +} + +export function exp(x) { + return Math.exp(x); +} + +export function list_to_array(list) { + let current = list; + let array = []; + while (current instanceof NonEmpty) { + array.push(current.head); + current = current.tail; + } + return array; +} + +export function index(data, key) { + // Dictionaries and dictionary-like objects can be indexed + if (data instanceof Dict || data instanceof WeakMap || data instanceof Map) { + const token = {}; + const entry = data.get(key, token); + if (entry === token) return new Ok(new None()); + return new Ok(new Some(entry)); + } + + const key_is_int = Number.isInteger(key); + + // Only elements 0-7 of lists can be indexed, negative indices are not allowed + if (key_is_int && key >= 0 && key < 8 && data instanceof List) { + let i = 0; + for (const value of data) { + if (i === key) return new Ok(new Some(value)); + i++; + } + return new Error("Indexable"); + } + + // Arrays and objects can be indexed + if ( + (key_is_int && Array.isArray(data)) || + (data && typeof data === "object") || + (data && Object.getPrototypeOf(data) === Object.prototype) + ) { + if (key in data) return new Ok(new Some(data[key])); + return new Ok(new None()); + } + + return new Error(key_is_int ? "Indexable" : "Dict"); +} + +export function list(data, decode, pushPath, index, emptyList) { + if (!(data instanceof List || Array.isArray(data))) { + const error = new DecodeError("List", classify(data), emptyList); + return [emptyList, List.fromArray([error])]; + } + + const decoded = []; + + for (const element of data) { + const layer = decode(element); + const [out, errors] = layer; + + if (errors instanceof NonEmpty) { + const [_, errors] = pushPath(layer, index.toString()); + return [emptyList, errors]; + } + decoded.push(out); + index++; + } + + return [List.fromArray(decoded), emptyList]; +} + +export function dict(data) { + if (data instanceof Dict) { + return new Ok(data); + } + if (data instanceof Map || data instanceof WeakMap) { + return new Ok(Dict.fromMap(data)); + } + if (data == null) { + return new Error("Dict"); + } + if (typeof data !== "object") { + return new Error("Dict"); + } + const proto = Object.getPrototypeOf(data); + if (proto === Object.prototype || proto === null) { + return new Ok(Dict.fromObject(data)); + } + return new Error("Dict"); +} + +export function bit_array(data) { + if (data instanceof BitArray) return new Ok(data); + if (data instanceof Uint8Array) return new Ok(new BitArray(data)); + return new Error(new BitArray(new Uint8Array())); +} + +export function float(data) { + if (typeof data === "number") return new Ok(data); + return new Error(0.0); +} + +export function int(data) { + if (Number.isInteger(data)) return new Ok(data); + return new Error(0); +} + +export function string(data) { + if (typeof data === "string") return new Ok(data); + return new Error(""); +} + +export function is_null(data) { + return data === null || data === undefined; +} diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@bit_array.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@bit_array.beam new file mode 100644 index 0000000000000000000000000000000000000000..26eace97e057257824a2c6285fe4d48e8f06db29 GIT binary patch literal 13616 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@bool.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@bool.beam new file mode 100644 index 0000000000000000000000000000000000000000..2c0430077d7686c1cfc6f71ca154882633dcae1d GIT binary patch literal 8492 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 Zf`-o)LC`Qb?1T&cmMn%L3jBj0{tqx?ujv2) literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@bytes_tree.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@bytes_tree.beam new file mode 100644 index 0000000000000000000000000000000000000000..8292b2c58fe6fbed347ab819ee26170210598f70 GIT binary patch literal 8852 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@dict.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@dict.beam new file mode 100644 index 0000000000000000000000000000000000000000..8d85788277e268d1af01dea78299de6e9b2a10c0 GIT binary patch literal 17072 zcmd6P2UrtL*JuhQGz~?m%1RGX0s;yM1O=5M(iM>sk^q5_#1x8HKu}P@f}%#mUQj>* z^|c`)q6k>97cAHts93P;o!JBk3jXis{cefRu(PwXXJ$^Hb7q||CC~%gLT7TFy@MJECw}+LTAzhGJNJNh8%;(qO#)%NmOnWyeBaEQH&(6APw*0}Xq1nq@}m+NX^P-=*aWI_Og5jv6X3Z* zfkG^glO%=&9`NOosVpIbFC(BPGGtPif_T{^1}}~wM`y4Y0)`xqk;F-6$k2HluAGny zVaPIgJPr@XNtEGpk{B{<4x6D6%VE)@SR4*l2G$hepklCiP?d{ivIGpC41-FG$FrF% zc^W4vhRJ3qC2{CN79)zuj^zvn(~gq5SGAOMvL0m_D`Z=eEeBb`_pNOux0vx9Is=2j z=KwqsL4m(2P{x9yjU|eRI5h(z77-z{Wr-L(UL8vok#TB)L@Y%_5jQEx5~t#cSn$YS zujwZ$xc4HAPh-mOvD}@gqiK392Fjn3bX$Xi^gq zRQ-rtEJ0mFPy=o1piM(WQ1>HdU`6SV1|UA6s?3M@faM9=}v+Mro)jLI-|Wg_CPt}Y`Y=*l1}Iusdo zSwuw-3^~kBWw^RJmM~mI(DMdYeGy?8cu$9nB_PUVGR07aqOL)~8;J#>gciB7(jT5mYI7Ly87o zmi!n@$UyvvqBtBcA|Ss#HUwjNd`hb&7@|MFxzbVhn~c0i*#dG8GXF0T@6xf*A?|u1G{Mk|!b*889hzNq3Tn zU<~?=0B@S3h&1s-YO#coB7!MsHU!NUXtS9g(t;&eiU=goYy_IEh@;6EA`ycSky4DI zCQ+TDXsj+rRx!g8tVINK(8~mjP44MME+v9qhTVjGq)O58-m z671lTKr8YFORyIaMuMIs3YOrYOrcQlC}9kZD5LC9!Z-rLIQ9_65hctRK$y{3!f1di zb&8!K#Rw3^j-p|divYS<_<;5Iq01P642qE$gO9;Dj$lYg2qzK25)5q)nw*u1;-T>r zLv_k1Kq@N;2Cqg`$76y7ykIDVUP)Ydtp^3lB_0$RP_UA^9Jt~@A%G$e3T#&bMHv*> z4*L(1)M1})7_hDi3hWQ-YEpG|srnF5?}k5As;(tfH;}3uO6qW2Gf=wc3F|n|RJax_ zoEwB?DtT@vse=o~78Dau;QM4yj6i|oTY=II+XB=_NZQT86#=DtJRM0LwrPU`-_-*} zQ&NY|yVn8Npdo38ZQbjJZQb~Q*KRyP+zkc=jsa-)@CWhQO%q5b zSx_K8ApPKbu#TG`WCNUFAP!&~Tn~Ki3<~^VF+*Z}z?B3FYwk_*OhFg~(u2V^|D&R4juk5b_v&^g#+RFljN2 zC`KxmmyiIu`f_LxE~FV;tMr_t=bPopN)cM6ESnceG;9#yb<{w zLAfbjWjHXxcrSJ==wF2P$AfvvCo_0_CWoDfksV{@U}XcFI9vf}>7F5-5hIL4O^s1*TD+(Pr!J@#4!PT_+|NHFkz2V*O$+D$q$~&o49q&sqr2U^05lXrcsdk zll3O;1{O@?5!pnCqRI0cazrD~<;A}8J(qWAgnnS*gB7z+UJ32U`6hp((7d{+Du}eH zt8{XQd>$!FUpBJyMt$&OpWUe)M=s5|a9hOx@?Lwg7irE#!N%5|Q$FtfD%hAF8*}w; zRSADqthru_>E-*Qjzz9qIeFo!=QCVK8hqv&4HL#}eze7N$q$FnhxWO%U3J}DR?4p{ zQ45JYM<1*3bBgsB&kIK#O^aTNnij8}^ueQel#9X2a~-~pE<58MG?q-kHr5rt5P3Tp z3_1UJYvZTq8!EmTRi(wLnVj`{wK;xl!M#NfOV2XLM@EkQRN}LFb*rK9?C9 z*z7XW>Jr=*dK{oGnqE<_#$3ex!8(2L*j{ZXuk5_eX4wQ4Jnbq^S$X-!6$ek37SB9^ zH8b`YbG6Q;s3qPqGHI@f;rEFAw;ry=Zyn3;+AiAX>w9QYS=a6p_g(ikDCKwU%66fQ zSwHEF$Q%x+E z318gxpDWDES6$(YOFUk(V2Uuzw6IHMUzDBMUAa9|@#OQ&{ik?r+s3(-W7pCn=g!`T zb9=RYZu|9bC3N{0&2w9pzB9hm{H02NQ{$Jas50BxH?1AWHSL<=)n6_@x3f55KgSVM zW2Z6oyJPexJ|<$*mwnfiwvVdS@+cluBlMs72ATP0(~~y$(JeZBXYz=^?i(~-P{^Gn_5 zm$@(S6*?8J-@T|~OUyy9O1aPn8AFal4>6yKH=lViTIsut`-E}hC(L)BfLpHWJLQR2 z?h{$hc~v;0Z|a_Pjw%XOm`$;6@=km+%B+m}GM=@L;Vm0!^MA}BJ==BseAe;c1Hn<) z3-23cAFNbbH^qwVdN|`{7U>D|(&fbG1clJ(epX*tfUVE7}Pd0g~ z)t5cd`CNgoF=fnfm(~8Hm)uF?iuPO${P;=FayWivq-xQKjeey(=f}P;F1MCXNl8E8 z=TLM$q28r!duqXnGda1cr?Sl_xUT9fn|6PEc5QU1&RoZvO#i}Z1UF*%e|{>J06nZzLn&-_ciWR;Km1Usu`MNrX*wW zIZrK*)~4wv=hz3h%kEs7a4J9{Y1(1iHr$TnD#am+n#yJ~2!Thv=bJyxo@FuAp@mhm+;9GjGN;rIS)7rmgIoN4m~5?mWu7eNQV1qE z2r~np&BYut3C&2n7od=s@rFHaJ8RSU>5qxDrIxE5kL=2bsKMYzU&oH7cbK#G_}mCy zV-%seH{iyM2Ca*FvxZ%pmadjQRo#0uVHG>x|Hui-bGcWtBGK53j~3c=197rX(lNeE?gwYo#63FjvEq}?g1F#I z347<>$bb6KU>Ek1rm7reXwJgQbZyJE_S+_ZsEH>m_2*izUPYM^kWpJrJiFaRUtvST zuFGt{f;O+`mOmfHRIMej&+D8vtf(FrzpGvtc`kb;&7reo+Kz0s*;_)5M@_&Q*O*P7 zP-L>za+0=@!Pc0>nH}cB(P85?T2!~?)Q^40+dco#w?v&aR78>qEV;hU`$eQRkEfuTXr$-T2^s=E9sOW&G2PPu5p(w^DQc zmnS`WAx})uBQIw+UmeUH9CPg(Wq;~s+INMd_#DQw(0L`U|6I52QgK{u(3Vc2h&*@u zf4Y07^j=n$j>-B}xkqQFcyB+L>hr~5h3JZ}nqINJdb|D=nXmFP?g4osMqIvyb2I&B z&hm!+UiR9{&iQ`5F){A`^M+01JEF&yzEWM*DKme{<|+F%6gQ4BR7-R@!CxPvQ|L5S zHR45v<-$QzqMff!cDxY%>9ykg`&KFo)2EXy@^@4wUkLMFo$jA7lbRt2*SdX@`1I{V zm)v0vZg;b474p9a>K<9-XmBh?NLE+)STSh$S7Ys?UkrNO-eX+u&Zwh`0I2jVY9epkzG?l|MJs#ACINycxyQe;KVQ}!FZ7@iv{tc~4r7N4>7 zedAbK(m(U3eJwbBtLz8PtHymB)h015)6V(2(zdYgvVk+p_xW$iK7IG1M|n&gGt@0R zbi?cVr{{=ixz?+$c$RERiw_<$xWjtY@D;lstOyMm8?$@yL@moPqeYJ{;-bu4cGd2+ zE{TeIk*`k)sX1|gesRs})2|t#)33Leccy#kxD^JCiLnZMx;;Kehw97!>QiDf=HPJ+ zXHg|*+UeoTX(W$Gs#`kq?rk7P$4IruP>eAGRmE@JKB#^GM_R z8t<2?OPZ#BPTJyBRy@36(%UXs#*9?~LGIii)(U>J_e^(tuk!%k;ZWMx`4pV*Bl+nCWwp<&df9k3xA|;bZuMa?q_can8f($tLv{@h_nwMn8jPY zO>P+FK1?jf zsx4Y2!_BW;UwBm^dho@4@m?&WhKmJ9E`{HE{pdlM=?l#z*{wTR`p@d7|FjZ4>LP_t zy1#Gg=yv^-5yJ$7pXLAfJ~Ha0Ug^w@@wVqK%jd^-I9G(OS$yozAv(3%>hzekGoGK%@t#TrbmK$ebC3@b)chbI7TrEXb?+&{)FDGjP*2B^9uo zecfLLOc&@`?iZd?j&^z%|3)XrKm0lMfKkc{YJ@wXXp)mu_Yv*G zZR?L8TUEx6eHHQJ_U+-ec`79dhK5GF&w4G)a#-cR=7r7anACcU1ry>)c6DpU8Qxf( z+By5|m3Wz1p@@D8vcp_aws+I~ ze51%BXIH;?-Hhb1?xwfSZW!quscX2sc}-oWy~5;*kj*Z6CEo)z@Yggl3is)sU@bn$ zQViU_=%&W>L_LqnX~ORj9`2i#80ROo3TzDDYwnp>I&K}QEuwODQ&QK9M^lx|XvI@s z8x^m5IJ9Hx5uEu%*3b}-WlQVUl^C>6_MG*6c5Bk&_6q4)6{3i_xtMTa*3RNOSc{|1L{yel@wxTsMW6{n_bqu>9K{lk!K) zwq}_xw(N|Vu}JfwPj%{Y+dLi4y7JB)UiqWXT~EEtNUSz0?<|=1aMzQ^Z=cQDv(D#> z{HJv#p_cP_1xG{{qHjM*FD@0HdYkTRadf(ce3Wuboyy7z5@7@53emfR5L z?835oU8SdaVXqkRhu7S1KBl~I+1}D!0dg1qQOUP$8x*ni^Emr(?ckp)GG7>f-)8se zflk&{pRSdcd>(CEb@GMrj}6=CUqE5FGneMYJ7nQtm2|G9X= z*1=VtO`O99j}OjX@%HsKgU9OsO!}OyLE8Anv&odPWYrYrinqItb7HenBI(>w!*1(s z!(V=~@j<@tN$^*b#*iKNEF5S5R6qM?SQzn#yn6P*_jLW)`XYss;a&83iA!}md3p9X z@72-WX6CgZH>c#85@u$(E%&`kyfcnULdC3c}tgx1JkydTpG++7o9qqS|7&I~T}Y)4ct4mGzBtFO+6o zja1uwQE&aso7-l#-aE1C&0))-mn}Q~nO0u(&S5yG_1?7Ga&|Ys--S19?T@Pr+JC(A zlkFMHFBj)#`Y!D{F4OT$cZszR=gv)Keom|wa${NKt7tsi;{Kp^r<%@1kA~XrKJ`)V z;0EU{#bFnQu}<=zuNwb|74#}LC~M9s-S&~!qNAvO4)+$!mi=1(*2*LNYDB``qmSE# zYYtqGxE7hR=-4Z@bS8gXwOh2q zXzxB=HC}eS$|`Mn;gt8Pw_Z}5eR+2bznMQ;G}nAqX~g|<4{F3Mhp2Uat&PvBTCXo4 z-mA}1k^QO|Y?$fVwYNFw^2*fIvyWREPHaybmt=cfZ-n;CjC?uhg3||mFQx7n9r!kdzV^)A zSkAT$D<&*1ZQF2DcURn8Lt#Nn#R`LtFQdkiH+<4{N-K)k`;RU2zIG%-hUt`~w6!VO zukg+%?)<=e=KlHn-`xILZhY#H5pM%u`@Umqrc1-hv4gl5I;WeRBVad0wH$P$ka1aK zE7z}%w60e)r#q&sdxJ}!_QO=yC}sR}Qmach66scYP8!_rm@& zEpw+Xs+U(zim`rVaIF3MF}ITwRvzYk*M3z<%QDA0G*xaiwY$%H{owKkuOX!3;Py~b z=;n6Z;?K8awB|7bJ|KlRO^sWQR&N}yOpXnU7Ox?61j1%(|7gVxph|&?wA77gS1?nreIKOvr{^V|L;+1lvwSB4L`C#Yvq-6Pj zZZ?<@R4B9Z?%K51E;;KkY`W!{RkzQb)hKS)xO0o6!yV}u9o0A@cHP{0I#&FYn2BYr z>mR-Hd-c9-Wk;^_i8_^sVe-NFZ54}-G>@(C*phQ7;@b$e=I{sJA(IyzK{N|@n3Sm~ zxio$E@_aMs>bf_BlCF#-e%2M59HOo-$90DBGjvbiFegU4%kp9}S~lSvZPsp5PpW!Z z(Kv|R_76E||GpsB$hik6e6S*S4VioH6owhEzFKqlV?nOLy(>)hsgW4rt^v>|Wzv`qpPelX_8Rdy4ke?ctT19Vn@v!z;=3U5*oVO{yzX3y4Kt_f@uqOiR_| zyfXJm_~^XwQcJRiqt>BmPwfH@clbYBKHv39KnoKqJEx?MJN-iTWry#k35(s{pYgcj z@MCHM?wX#xOCEJz>4d6K-2RD#B+HhiR$O@;*-<(BY@^!S zg!Hv3m&vdH$@x4e`C2i>^4#>icN-2rtj<~TZbRK1+BlZO(lwcf7JgL`6$rk2k0m}U zOhukgeK6BkgpZA0b69QgZT$KdIqgrIH%Gix!aO=;hrDdqPD$GFw3!m#VcA)3otV^h z#qP?;(C1q+qFwA|pUClt9Xp{(ThwM{ySup{FnvkG>FnD+A9gz2I@uaOIB~1XCl&0& zN!n*#vL-fdK6YhHdb4(%b=>-6@54_P+}Qp-SE0<}QHb+%ug1I9ySF)ju-RTG(;tJ6 z-T0>*gYn?d_!x|_eOA1DiaZ_ML?zo$u_=;NWfBOBst6dV0_!9yFOkkkVW*%OK>=vT zrYLa)+$iu)6bP@zW3UjWGHf;T zb+LH73~NoiDqcwBhUrHg1|wDUC0u^S)o`0lQA?zJX5JjTo!{5?m)O6 z#hfAnvcq6;F6b)JY_eInp_u{IzycwYED%tQ0aY7P1WDXArr)l%;;uB%brjmQ8{5QYbOhWXBgMDK901wc8nJZkX9^Oy;whlB=^X+r0a6e13+JHe zX)y=>=WHV<%{GH!qFTZ;{W442cq)qpS*3?iu^hkv;4Mg3gvzE%Xak5sMG0X6{_<&5 z9$msOfKDJC!d4XbgFFM$3b8^K0s(P(Ag@k?J*fzvNe3(x8_R(F2nPX)i!_8OU?f47 z6a$B^_tKS_1jP$Mscg;UfM<}>C`0#0Yy&D6u!cb|$qiztZ17Lg0?}?j1JvWC89)Ln zqRTXc;85}=S|G`Qu!;zRFgaFS9+NF#vCSYB#=0T~hztA!YACA$diT=YkI6#G4_MF@ zLFa(p0yc9+#4|weY4Bb=KDtOSfndPq93Gv43MDw?kOU+Ql_kjk05d#P9RS$@gg^i` z#684~K!~VJ7LXLGKoQ}`bA&89!sZB&7$`X`CXh5Cm&3N|kG~|RApVlWuxipArYSyA zA>lE99s}SLXrJHJ5^G?!)T@px5TF)>aJgwc+6Jx=ut#5gq9|cIJ`z2F%HlJkAxlB- z8AwO;oHQ9&H_Qg&iyjX#1HumI4)_6{M}fjF)=wi`5V92A`-1G%F@S-=M0(k{Z@+%k z(jSHn29{;OLHh*;M(&U5Qb%F_hVs;7(qtdfd#>gW>IL&Ogi9COA{I-GM3lX|sfmg* zG(bQJiIqfODg!0kql*-KmC?VZ^C+mxq0Y6nKy}<_vl-QG9(q+sA4|vw-WfX%(B+TT z@Lx{W0IUFrfz*_KnJu)3;t{QYZDX+MzxC~73=OC;Gy`-2{plddxxK%Yio?=UF;sj8 zP$CyTP+#}!;=Jz1@Sq+n^xz?o)NqS;>D`_dYJixrP?IoH0lT1^`@i;;QF@|>vf(!S{}8`O;L`?zKM=q4 zXLrO0$^Vv`QPR}ZLeHd2i0Q{jiINEG??jCsn5h3Z12J%ZY2pYFP%vPx$e?k6{yXO7hO|0(2o5o#y%l4fZ+d31xpVAsrN@6JW!x+0J2Ix5usxL^O!32gEUo@#rqbN zuD^@!^oh{jq9V|;qS2`Vx3AFddi+1yA4zS!dbVBv%`MUZ;nsg;gT-^}_9Vi=p2#L* zKx-=l8U3$ldR3aHiV(~I6bE_m^4WT_cEI=kj3956|-|ZhYhy+eWcaaQW8r=1VWfBK%xz$ z<9X3A(a;-jhTFLm5X%sEji)Ay(-Pge4b&@VQK23HTOL4X=%u52A%zLF0tmOl2JlP~ zR6wK>geQPK<-=W-q%+D^{dpylFX8@XH%#3vjU_Gd23BIEeBf3%6b)VemK*|~55N!S zpl(AY6wDDI1FithvNyBSvulO&Al~qbdr(;*yF^bzz;}H;F#fRBl?(#dhsWTusKCwW z9iu1l^QXNF=wwEM7E7{3$@Zn29edfMH{~O7>-!k30l@qU*!~Yri2a{}ecj(V{*A{$ z6-v`mP4dNLFEM{-`guB&OHBM+5l-Y8Cj2>0e=YjWl)#0Vrk@z!uyB0S4hW%wn}BFa#h+BgNa| z?K&zQkk5a?UvRhNzz`&~2&n$(7Orl=01DKiPrMXri4-1;r-?W6VAX+Wy7QN)PTzg} zAD9>}OPU~463xis-R-}n2ns=p8lLdeS~HN_5`*baf59(*#aZq%$C%R9RHY0$VkmV%CO4=Hsj0X_%OTZnx(04-z z6TUFA87)~;G>o~!2qyfv8;ORD9^I2%>uHBef%*ct<&va(4>L;ObZg{rv11^aC>qFz z!+|LLuL;iH1V4(XKV&&2rgh*fXa6(nHW}i`)vvmq+{diINWLxF^6Pr~+oAO2@oh;1 z`$0XQ%>NYw+DkLwpzg2l`{zJR>A(h|ha~}iQ5yd{wJ-VFzniN6Qo&1M`WFCyR_^G3 zIq+9#GL}Y@BK)5U20+ngDHK7Ru!Tu6;>3GjaqG#yqi!1%H-NbAh&{p+0<{Cg4yYi$ zfC_v(0TUd7fyX519AGt|1z?u;T(?m-1PWqbEh%#NDhbd8EBqvT0M>#V%1g>GY~3)N{^XLgvRR1vK1yq zttXVCUarDE%|S^~dI6!vNrqsoP9}yXNUftrPhkw7AQ?nSFba&OF{^`~FfooS>4ejI zjMTb8j)I{SjM=Eig+`h(;xt3xCIv*{;Fv zJ=;B=xK_j!h-?CpOoVa;Lv4bgJn?0u4g7!u%t^6sF)bs!JQ zKpL*&VyEHSLOTt|5jzce0y_=g&UPB&cC^#b9-f`%&BYlE&>=Z`$kFjEBAmpOdR(p0 z;22}3aT7aW5gIV75?A0^Mmi${Or1lipr4>F&NPOh!7JdI4t}PIWW`7kryeN_f9>{F z>$xS=W8WWxqJeZ=0;vJ>-(%T zFz95W%(Mz$##tqZwR- zsTiQ4@2?sPM1YYqlv)CqcsVB-e6%03-re8yIH`H&D30-qw=7G73|HUy=;v>F8MEKt zAd-vZYlrVicpS2a5HD(N@@^>g{r1w$`Zb?-TykhVGc_K49cf*;x?`&4fq&biX5$xO z<`C(q_={J4^##eT+1R_u6&{USM!j^T+r`DDqrt6;moU8=D@u1AhHafV^S!*{&qJOx zpW1|MZVufL?qJw>45Jc-pkh$8o`&f~1m~wDnsZ3Gu6GVViZeX&Z;~ zM=U0G)}KB4^V<45E2AP38PkdwE4Q=t_lc&;t)D-U;9g{ug@uG*dPtJUGeztL*Wb%Z6S4T>9!)h)BZvJ5X z*cWntso&dvCVPk6UOXD>ANp1e+%C#zZelo$xbafty+EzQa;7ECEANxQoAw|3Az&TVPS3O zN#VlnhmZNU_^b;n-X{6PEhe|5?8=ZeZ{~jdW=3?;C(sQ%Qca_N{Q z4@QZ{rqShZSGg>?q)VcI4J-aG;6mx>s3}tqd@t`fJ+ss^Z()M@TKw`iQVtH0UF00k zOHO>r@4~5>$K4zEr!3u2Hg2BTEoCWR{xB+~y8GayAo;?QqUxDI_IkIZ;Cg3JX=u>R z-)K6?vxZaT>93-tNdigyCLy!M~k_x;O~F1N(r+9j)Z zC*3+!#smlEdWV^>=5_8!*3`AhQyVI5UACB7=CJC~g?;Ai#VZm^F6C-6vzy;PcPAx0 zy6~LLO>@BM*mvzacYm$T{Ge!e<2#$4?D#PBH*4Mg>sO4WkqsMF7nk0e*f}cPKlt#K zH?1{NALWsfwhcG4<}JTSGgvAO4K=Ra9&TW#4<@{>L%>0GV! zSi+>P+?SdrwyY|4?fzy}{=%Ren;imI$H{T>o~V$xpH+C%ZAC&+e9g#J0`)bz_Bd=VKkl4yjdXvYijg2qgEq*c7C%4N73yiMa_V+40vU$hrRdwWv z?PP1>+!KpNuO))(UdP6b9^sgJ^iH0s;#yAF#shaJ?4%A{EsNg##XDtpPPm&F=5Lzq zH8fN{B4X*p0td4du))(Cc721{m6`4BP3TV8<=?~3xB8?f3~|ox4tHPY`$E5 zsIGiP!Bg(0vB4@3<0zF0q>o)WI%kWs8gvwy;TYFquP6*4OuI3779%xa^fEPNAuSFh zMdA$Lb1g0uV^jbc1qk;#KE}m37zc)Z7oDSyZ*gF(M%*H>mo*BEqvK)j7>~^hP_M9e zL=u?MSE~Tz7z)H?HPAqtaaNZ=V#lWJT; zkhnTM6yo6g!PY(%9L9yf|9_KH`ep@Tkz%l3i|^|-XJ~zYP8^VdZ7TWl}&;;yxv_EiT26i1Q*DpHzNq4aDLi)l( zdQQ##;nNR{uSamee@sb`7;Qy+W05trSDAa<3)DF?8QI-h+kx(diw|(> zRDmm$bhPJA1>#Ll@0lV*pLqqQ35nk2bLDH<{r^;^JR`1r9RY*CQGnFC4$ zko{9(iC}-=eSs%vTrm=igdhQk1R0M^Kqev)NHj7TnTAY9UO{FdawHW=LllSx(f(zT V#Nng>+kh^3cff}_-Jfze{{_{kP#^#R literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic@decode.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@dynamic@decode.beam new file mode 100644 index 0000000000000000000000000000000000000000..1c557029d32d8e12b085f85b35643630d02ad151 GIT binary patch literal 38440 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 b=RPE#Fh6n*JHD^mc)n-T`kveSco6+RIMk@p literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@float.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@float.beam new file mode 100644 index 0000000000000000000000000000000000000000..a1d441dbd74175009587f012a9f34ba2657238c2 GIT binary patch literal 19520 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 I@M8@72X60qJOBUy literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@list.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@list.beam new file mode 100644 index 0000000000000000000000000000000000000000..41002b75be044fcde52b682a64b28f3c23aac1a0 GIT binary patch literal 73044 zcmagG2|SeF_c%U}89bJ$VXTQJBc_;aqlQvri;@yqLiT;nt|&#J5^eM#+DjA?+C+&Uwyr?m6e4d+xdSo`>cwcF-qbste7n%G52E_%71;m8=LtM08v-+0?`o_lt^* z^9hNJ6%7oDiH#G93ZujX#KuVm#YDwN^L0q`?eL0?^A8X46_4_;?`+^+%RV{{4)P(a3;EKr`TTP!L8%?*gO3 z{rMz5Cwdwe66qh13ff0M<94;25HsA!BW5$6*YAP|i(a%4avB{9Y) zTFfV!@1!wj1%~^?#RWv-2qIY&q*0P@L`+CfaNKx-w%=As{{4(2jeoPlG=+roJsc7l zA3%wXivnT5jiVn(G}$LSoa_^sjIRt4jD!rx_}I7@@Tk`qP4e$&$@s`Iswf|&g+zj* zW25;qj$9%22SF-6GGs-(V94UZKCxb50m^pT_QFB-bVTb#8P5?0s}+>R)_?} ziG;^V`Uk}NLDYmq21)pgVYG;Vm>>wMvFBL%e-XT*eIS5j1k}GJ#47xoB4Csdb`KAy z#74!$Nyb263oMlo#665d+%GC3+9xJJl>br+#WKtY8l{*3myC@L4-u{eK1vf15`#m+ z1;V8MAmA{3FXVYi0fItQ8lllq0_TehANa)B0D)jW5gsT3K7PUc`9;V$uq!SkE+i^a z5P-iQrC}-};^TbKt5~T-&=!>_Fj;_)k$jWA3?xxpdhv}N&yUT&?UwxeS<){!J~E6i zLzIuwVnbF2_qR5`J=s9Tx{P5gQ!^*@eICem}wz0B1tJN(fMj4UP{C1oxwO@QRN_D~!)A9uOW7 z5fB+S!9U7tj0e2HX9G6{Bn8BZ3+b@VllXlgBP7ZB#)rWAhpZG3lMn?mk!pS>K*JvY zueXxnQ9)i{rGHce1p#r0^}wi@2q{5S1%^lY#7O{;PfSQ$a0D5`99Cp_03H}0>4)Y_ zz~?1MZ{ZLFKCvjTQNlwa1H>Z&Vq<-R0>mPs{Nuv|q@q!th>7$9A=EKEHVy(qRPZyw zCpZx9FP<(Cg4W7FIJ4-KUPYh%_}4_ zFls!cUavo%W!OTG>FTp#1Z+LF2K#@z_cs%R{ePyJ?^Rs`p%jHb8DfQGefEEn^?>|m z&6jj&Cn9UEhw-@aWNAG;9#f7-*DxcKDFn}!HjBJok>?QL>x9`8 z_Nk&Inu{DwhRM^Q^C)CdJu5xTnD+cna2dFX#{Tp8OtNQ;pZMAT10jo1FPa; zOffwxtcgeyk=@3?Zgcy|GzP2xth2lklrmCU0<|Bpl-^u%ez9ue7nGz^y^ zsus~07%odRiO60A0$oZ}k1PV5xEyg?MD{7Xljl+u$w-7iaK{saj+cXbf{Qi9U-?)l%e1%2PEYX;dbLGieN( zIhjVb(jYT=6x69gQIDd*A#eq8J$oLRX-b`f;Tkjs$x1`yUmS`84h)~dv!wInU=pe7 z_86|op|S)Mhiica$aEHgDjm$Uf3}AP&vwbPCS``svs*_y%bh@?(mLf`dn$2eRkW^cZMqkm&@@M#d~4 z@adqJ0ruMRL=44%4Z{}_xGoSULkBx9brFo0$1@b<641aT!-NyKo-MQ2AyFW0gz+Mgr#u$ByFGC{>h3bJ0L) z4uX>m-avj>3jLipRA+&YXYhUMOyDz-Y8L|Mf(i`=hP#4ll;xlUhA$&+q3OvFO%Di7cMNwIIEeg@7;yt(9*G`5;#ikco2b`LFcJpQZS1eg3fk_bpJApZpz^#F(O~UXf z9zW|x6SxgfbZ8j9f*-ehY7BwT2Pzvn#}fF0MT}?+k0WqfpiKu_JZv{sbhPW?2?V|n zsJhTUk-+U1(b6zHiNF^DO%FJerAd&(7gHEiOPrQQ!tj*@ZV&JDVX&*X)D*Hb18tRN zuuqnub+N>j!Grt_s~K&K)KwrNg+omhY-V^WfjgkFttN0s5MlsA)^Mq5zlBi1O-m_y z)HP`7$uVsivJ5aWjYC~46tI@SosfWa1nvw1Aja@?E;VCpkuf#+hA<8Jwz$~p@naaa zYC~j{2Hz+iH67GuaH#8rGS?HhE0Vc^z?Xqc4!q6eVQ4j{V|W&Uy8+P%h}m4~=HHeI zhwF~kaSp_8&hOaG;m7VKh~14Cz7ehL-`>auZ*1ZZX)}kq1vXB8I+3K&VURhgWWG{!he@xLnq+maR2OxNWzym?iEZ{lF zr5^c*q9FcY%FtjA`%({K_@Uo24+8&TzMdl->QS=b_*8}j9wqQ#1j`9L1O(3p#tJUA z@*jdj`GTvE;N!m3V;FvnFY5Sj@fFakl0&T)p2Dh-z-j^yL+}KFhl5~Ka9<6VdXk?v z0McppJTtll{eYn&!_Y#QIchNcBtOqY@UuoOfk#5uIUv1GkS&0rp1`AkI2Yud;!sbM zIn*=su}m5Le>3H24)rVq#Tnsw?<|*k4w+y95KOQ)gOEYX&8PPwDUyhU?#|E zCh$a{TYv#qxYQOhji-mwvK5`l6ngXuhPQC2t%6*f#P@0|fhQxOR|$M2bhd;cUE@-( zgY`^99qJ835tPZ9pv4e50|Z>>P;UbN4RGU40$+vt-Xic6=nHoQyp2n}^RE*koeYsd z;Hlz_JUAuZMRC*aOTCTZw^6zpI~BI^FuWawkfb#b$vg@ti>625tKkrfay|vpEy`~w zk9*P--qk+b?l*zvUpp!<%-vVCp1v~};k3hg<4DaDk zUr|h{&oI1KoB9Am@gx@+^5iV|-f`qD(5VvXeE45F zH~g*h^}lsKW1i$FmZw*JmpZ|QZW1(jR!Xb5m;xIWLa;BrRUK3e~h}HLwyeyy%&ba%idN@N0irJ zNYmhCi%y#ao;BtR;X-){4o5-oiomlMfU?&Fz5zYIA@Ggpd4Rw((eqmZ--Mpu3D28k z@M}7H@t(jpBlv;9b0ApkAvQm9sGrc5!ZYOGUhz*H>L8rD1rLK<>Ni+1=*azzE}iDh zvlt5{=29NrpGS@}qoX}W5KUYD_U2c%7(Baeouj0n&Uy+&L{>V?ci13}j^T6&Uuuz7$)L}5qkj$n2;GZFwzYprL`V7f% ziY4%^6wtztCRk<~{D9M=4ngl9e;mxW{q1EOcrkpK@BHoj^*2J`J3ylYcxseG{rRV- zesZY4etYT{mn|aj6kFu~-%~q(dy0)APq9go3!&Lj|HAOU{=*}qX&8(2A09+>3>?D} z`NLEBhyc;E3G8;%!&nq9TTI|7w&?%#Q~`Ku^k1H0Q=qr#AD-IvFHf<=_?{w=r&!_y zUI-eOLLZ#VmPQ&aIBZE53!XMxf)1-69i)r+tP+6JF_xq@TMAwXcL+G@h%gDfn4-s~ z@F+}JHgr)vHcrD>Qvc-G4X4Z@KF6Xl4r!1^CGZl^?*yidmYV_AD9X6;y><@}Gz! zoRG8hXav580*n8j#>#To@`hjz9UvN{9B4ulB2VCZ5mX@XePE_DxJi*;tAf2zjz`uY z@crV9Jz$Xv-=Ya%kuq4Mgt3$e`~cLgyyaxb$P_v7jc~_cD}oed0zZh#TL0tq1b#R{ z0)Yz`O9iwbBcL912#i<;zEb7y^K3Y*po08REEl+gF8r37f1mjOyN-=dVmxS7JCXtN0UbuXB$P z66}KIB)TH(?{HYgSVjb12OK`YG2;&onvi1-#+pgs^}yi^qvdkhCVaOVvyBZ+pfTW( zW&wvZM{TyT1xyKli-9OYyUZyHql4xxEKCS)1^oI1%lP+Ym(9gkCLH!G;bENx)uYpB zEKof<11kN%C{w{$fN>6ip9P{n4`a>cvdzE_3$ihrXJG=3VQxVJ8+eXzD)l}44N6LlKnw(<=5g89|2X3}L75VEE4bh?*z?Zve+h0m>_ub~XbeGJlf4Mta@Y$cX>41JW&2zD0_eUFT_9L?9QI;x90TcC zgcLyC=Q4u!1l|maf_WHg375ST!V~H`8e@f3;oa>DKRlgKcslyB9Wa&yKRh|GpBbY1 zCk%zhUIG#7C)S^XpKCf<@Q@5&9peaF!E+UqMzuNvIV;7XrTu)`h@0 z_$48zR)Qjo1tp5el_|IZ0q1-s2<$~o#8Mb9~Rpe@*AqR zuzb;m03j#>_W-sh#_}WZd%zX}EKJ|M2J$5;tmb`n`S+MYjK7W^9p{}^aC_7UI_9BXJU zbd>M4*@@(($RZ7Nwu76G1v>UYJ=UI`5RI`Cd6qDHOL=mZSqxYPk5Sg-p;9v0iXt)= z!eqEA@H>F+Bn~?nqS&5iA*iN4K|NqMBvZ)zLmMlZz@MT)K#}Vi*c$_bSjA;Sk?WtO zkmrJ$wHzpcFAoqdA{J;y!76Zd3WuGFrUGhR{YVznx?X^+SkS+Q%U(-{>|{oEBwINe z8fvlAWS9j0GF8;x+lA>Z!xXb;ufbSp(t7aq0;g z9CkXH!(QiN$m3tgUh^kr-5&#eGuD4>py>oYfQ-u^@V8)G91L_lZmtfO6P7 zcoh$?GP&$5*qr!ZsQ7i__i%bzCESFCbyijuhn+o^+OrA#0}{WHz(0bF1RloP#AQSE zOi&9Kl<9beXps^4r?G-Ne+9|$2gYM>f`M)3uyX{l_MSha90DIiVxdg-8N?<6OD>NI zR->%431j6E_!poj(JptwsY7!#?0M8;OMHr+DYKw zpnoz9IbWMyK*xj$r+~}e1;S9!e@CYnx{M(j2@^h538sinVX*UmZ>Y3#JxF1cEE=48 zhG50R#pwr30E%GPHpp^WkPwip;jv!ufs#R^mGhX2Bw=zu?!{QUIBWui5+OX8qx#1P zGPDo`gP|+I&>}9om`r7irO&ZiTDd*Sq7WklK8j4>rwyc;z<`}4_hPJl9QFaj-%tDD>5pm-iv)i8uYKeIA-IwpBv>M#EfofOh{Hb2w~|HX zTX|R-Tnb-Q;7~0>Cs-6X^6y2vDeU%SF8c_bU*e|FVUIop12_VALm^s5utY)TYM>q! z4C@faDkoTCKwJaF3TYCJV2M*`?4tw=7i>Sr2$lrAP6IoRbJ>-GU|>l~iB?T!GHDDw z!FOBsag0^TVOJqDVcMz)mK5@1HNldE&g($-2^1v4>Gq~8lEA0qFjfu0k_Lu!U^vO& z356WdC?L?_sA#=`6tL+85MUt3Nf@h^V2y)r8G0D2j>|s%&-`A-M46IcjpyG`&hYO8 zr{F$N5BGsn7^@x?rQsR^Nkorb$HQ2s_!X5u2&Xyhvt)=<7|0nkin9a@eg0*gBUtG3 z?|N`W1DAb%EH4l&S(t&keKf+e3Ks@KFcWU(*0 z7~0cmdV1)f#@Bk0%f1BXCZ4c54CRC}GLvBOzwM%R#1t5R0SvjsVPA$-F6b))7GEY< zibz*8C;(kqz;i|L(UyGyW3>=0C7@=LFjlKHiA1oJ#Ywk)$XX<*)%qpntx8_eN{A>_Z84&-k0J}rUpzV$m|5ipxC=l zu%^JI?uFRvlIAhc?jq1`g$h=a932_YjP|AAR6~(+ph>78%W+e?=tAp)(i%V)KGvX#?kB;CxB2bReV3 zkRg!R2%$sjn+^h%F&0!S(Oz@}*k1qM4Z%53wHyX|8PErQf7E0_?Go*eM}hk8Z|Zx3 zg}%&}>tU=9)Ze=`I%t-sk>QREnU$Ym^dQ@25-jwsonRS2&UO3EOe@brTRR-yEn&zX z36>!UgikuGPk*Z!Bv>4v9^+xG&)V!ShD2y4Y?Xw3Nanz^CA0(3z%J~W5J!(s z;KyEQ&=2bZxL$}i08EF5_)h{{Bg88Jt`_1)0j?6_$nIolNKQV$Bq4n(z(iu`!~+3FKtuNU0}L0^eE^0E>23f+gmg6iAR)d0AnK3w zqInH~hU`H;@e|Tb0U}w5X9hrTA&z|KCBzK?E*Iic0lEuub%4u+xGF#=AwCYE4K%Qs z)Cmpg1No$D(9EGB`ekT5Xo!9u+8iNX2N1;0iyAa$w9G&_&))Z7^5!?i9=(D z7{sVa#deFXk6Wil^U$A=K0*J}^Rh|aj~`#%KC|r?7P4nBx_6sHf9Rb_-{|4Cv=@5a z#MSrXNa2`w(6v48dIt}@d9lwtjGePVO+`^`&{#wJS(5Ype2dt0Tx=q>J|);GU#^w4 zxGFUMt@VKQ9O@E|I`KDqom1srY$6rT|k@<*w0Q6MM(1-7BnhDn5Wm<7 zfN9VWKe9blh$B5I&`{sK09Oj>MF10^A-$UbqBRcjhM_!x);Pk^`zUCrFIwMWLfjKz zFf`P62|#}#J{O=bG{nyZi1-k$4bVe~YXEc;;*$V63voq&CdjZ00pcz6#GSi_= zg@)*8tW$(IvYiPH@gRFA3voMuXgr8M4;tDRP+uN26(K$Ypt2Cx0VpfP)d5OCgSjJ7 zp&=QlFU2e_E(W01@3#76Q%Ig&=QztXDU9D1oixw*E?wn;<=BHChpWFYVt@%hQH z4#d&lRKcGIgpowK(`QWAN2I7|{vUY=SA>6nZ+sB{m-Iv7rC4lKe2iZ}7|BJ~3I2W{ zRyQcdC)g)K*FPXZ*C#qAc6vmBF8?nV_!Pn4b?N^3hgP~?f+zTEf`C9Dzc`Ta`_I9q z1Ai#V(l;ms!fGJho+P5)npAwQAvtAdNA1k%$`bo;7-~$W*z6K%m6kok!x|vO?yIZ|e$BgiZiXJD~5AxX^ zPG#(yY<;JP4o(kU>D?vHiS1UqXGFDSy*!ei@A@vkQ(;fpqN9$p{lX$tM;o5)qtfpi zS^M6k*EiowaGG1Kc_M6I=tiT(M{*ZFxZ~#TvVUq`O=#DQ74FL|J6w$F@7?Q&BwYJ{ zI#lPkIJ>QzLa)!&60WN ztS$U@hDL-`96c5ly1Dl9s+pWCP8EBP*6yt}c5tkNyVcKlnn zUefOS4-RBnB}Rl!zGeofF7f17!^vRHGMRxNAmaL~*nF{xpj%*|_N zvR1I9EuHRP895tzz2xZC!fsLV8B5Pj=bqd9i0J5bS4kLRmpzmkEY;v`3Ue!O_+U_2 z?v(D*X3{SeICEF1d#K9j(Z?FIR6MANiGzqy%P5US$Fbjs0BE4-pPH*x5A zolnu3)@#8P=E<28>kjv3Kk>`We3ZlMUOO+@N@kI5nB#7*>@P_hLPIL<7kfm-_?7S$ zi&wNi-?T~MdH%0(>(Sp zIO-nmIVmslNZRghUe5IPBW5>pg7#}fZMuy6nPB;yHvpY;nmaLtoYx#!W=8-ST53tsPqmIO)kn9#@A9`*5M!G)IJv)EQnBm=K2841vJpzXj_8HmW}@|XXb&>B z@|r7TLtC!u+__{BcIfqm>)}(fGPP=!q?2o4y?L9R&!!IW zD2Ddy@6CKO$Mx`;4F|}lyk~{ny}c(v>YA45u}fvICL-XwcIK*qDDV_`AO54 zH@o9{dW)QN6JF)1shx>SzdvhsTy|ZgGnsVFWnRwW*!6E?v;8w-uGYjV)7$#)bm7M$ zvI;ks&E65=EH&||gXq(XUlzFfADz8*{^HJZ$t$}U%jDxMZv}XV-@BM(b@7YOr!RNj zgsMC`KJHm>hr#)&Qu1=?lJ3!cKF0HUCa9={UF>otHwR8PTV=X1ee!a8NFc*ldf6y{5kGwL;+io?3BPopno>8#?|xvgGHHn&Bm9hnLh0PhOd= z8_@o3+WHN0w*#0~1-r%0P|B?&b!PdTi8h?{dYftuJx5f`HDO)x!H9~i38mv?PE1nA zt}mk5Xcugq?5%ISU6mwDCh4oFDdg@75N%#Mqj`(cNh9N1@n5r-{Pfwr!ZVri}G_V&7+ zowabHLfg@dj=*=3D*K`&!gjio`hGs2@xCwg^-g!?h8UIBK>J-=N5{F>K9F%{C+Z#T zALm>ftUNbdsqf>acSd(iGcU~fNHbWLeJM08cm}q9G$pMbtxxW&U%KIgsPdr>>ZXeg z`F5$5*S3bg8OgFsEqx<9A?fiI!|KSJV%1^$QXFols-7&HWaGogy|Xsuf>LXq?v5?j zr1Yjeuu)$=;i@97>2&jLsWj1VzOO`2mRN*dpLkl)=Xu5O`poxMVXr);b=tjOiKx8R z(7W^UR$BRHk9eax>(?gbjJrJYf~WED_Q?-@iegVw4QQGld=m=K zjenL`x5AIJQ2FhWi`kziUK+&4Ngazwa-CDfxgdU_Dr3I=h35FJE8V3=r&NgklJ#^y zpwd6uaR*yN9Z2&QDX}g{4{D!qb?(Xdrc58zkCXS4=TKB{mtE7oC|5Op#oA!JEAw`B z!mvn9$JNl)88h~K&QPj7=Y4URpFijow{7&{$@ZTQl}#*uP49ZOMr+0yVncoVUt3mRzjMcdeB{?SG35_y zIwy7}jwW*Msw8H_-ufCdV_UAm_VjPLmwj{e)45Boue?{1@3m)Y)R)Dso6lG68Qj#g zqh9NA!4rw0gXd2Dm1%_iB~y~-c{Xi$amVhu_oa+O&I7-)7ns*i_qd_ZdThIqR7&W+ zlD??0D=Ym?LyoPStb6llq4hf->D|@?s;96XW3pbsjXEuCb^f9k*qseZju#&7)^K>2 zdVgn;G-kVNyxLinnNwyv>+X2i{AAgacJa@2=7r}Oy?*1`Qx`gH&I_|=-19Cj&-;|W zEBQ;=#o6ZX?H~A!|E|0B%HBAGeyeevxm~AiDOWA~)x?_BKf-?w62|$Z9=^3}Hs&md*q9S^sEcyB&Sb(JjR7 zG|Y%Qyu{J{p*d0WOxb1zTO!xUtH3I(!S(&Rn96G`a>~!n6JOm2j(Y9%Xq-^Dx;EzL z1lg~CxBb*j`XkyWZ;w#_dVQ7Uo5Jr$8lEi+Qz=id{6-sooaC&maPNliEsb@?+lzNO zUi4X%{cfq*p#PWhp(%G$4xL~b?A+73)YECPQK}9%!r*K7q}&oyGY#^e?3kci750uiPOwBS&rql^R&t{@M0MNy#CxLZ@AaHmv_iQ46VQWV{Z| zt2^{+P$b!K>D->T%Apy=JLv~A@(#V0*4tX+Z7Q2x+g0Ny)^*LJC}_`;i8f~DPXmvX zJukNv$(FJmk~X^DnNc&ey0H1%U7ff$bgLOs3ii7dKWsRCXnb&Vs!{Lz^6rzBfoF$9 z>&hzwrBaQG-j#PBs0`E^xu(%(32W=;`PPgTE%OrRrksbD^m)dP3uxpFsLnXe7VE= zK(Cux$KB~~zZ}D(!hTTdPrA4kxvSOA-G6b~J(}b=dAW(xqPOF6mWESazDeJ&x{IOh zSi}h1CE=@f^7Wh2JbAlU3x4IfHpT3^z4OJA>gWRJr#{tpM5Xp|tj>ElpZ6gKmT<8o&%KmKr{?o93MV46#4y3%$%*<9-lr&epmH0IaLyziFTGdr|2X?Ryw)h*c-`*APp?uljw$BOx*R2Q z?D4$LjE6Q0yK>G+oNed$+|6=2o$b1_=wopAHJft_oLq`_pP5h9JL|iB!h&t%I-dE@ zjG%j`#rcc=aB+P(C*^2r^py5d?XORA{gqurqV;b!%ATx`-yyDC)NL@+y~XY#;k38% zqKf){Ejc42xsrHkI}!JL^1F`J9ou^kcfYrDnvL{)>$jT=?|H{fA@6s3k=*=v$RvG_ z)9BXbw0=F#(HrTT0vo@ZO*yN-z)^bp^$9O{x2Lh?7Oq}DS|*>HobA!D%rjx4nrDtR z>*hG-wj`q<5f9ag2Q==f9lyjbIqC1P>_)hw!YciMsYZ;HJ5!{$EagPy zIA~aZF=KC7lk>Z)?p4>O`Jd7*mAOz@q%lppu5Et8+2@|U{k1XjcCyxsjY>7PtP(eo zFsw;BUy)XSoGfPMrB27hh@x( z+n)tePe{#}ClN1gubA(4aADqnQM0Yj6oRQW_3L&$kyTP99$}YaPOq==h^)RsRDok670qb2j4igGKCuUeW9Q35Ve^`1Hg;cEP2~F~&FC zr)M@lyVq)J{`INMgVgPZf5;46F0}p{u28eidZ`*)r&Qy*;=orq-2PJK1 z$vi)PkM>+edfh~Qn#S@w71q&aO^bv5jX47{u8O$fd;HeAJE8;oIHIfGP4>R}c!lLA zl@~z{wc``W>(?O5aiSYdjtwP%GzXN=yx^_hp2H(yq@e)9MrX_?Q|);(`M?=-1d zD_XoZKSNC@Zd86;J*a23e&;^d|F!9Z4zBZ^ zTjzHU%~x8oM%wbBnx^{4++>kbAO8`htOU&keiDF*rxqeZ%bW(P&-NzIKb|@kGU;&P zw-si0=e)mnGIvwqx0V$5)e}!nDZZZDKwkOe#ZTAxm%W1r9_DL>xR=QF3?8UqFWwmO zL*h|>DJ4Qb?(5>#rcsLjUdO4E*UtCo@vx$QV|snfO?2bgq(2LhD*REBym10!@e|XQ z%bXKh*Bw``@Ak0DvZ%(*uLo@2cK9C4ZLRsX3O%142V@q>yxV^GUQ%$xj@z1vUGtJ> z7&Uw%&x@KJrsnm{Ttk1_vt>Vq25X)V#h3(aYAGn~Xem&fzVVJ6`MKPywH`K#Lv2r4 zHnrMuM>Yp_1TQC>PkgE9>u^{-eyS6x?da*42t{zB=*Nj_LF2y9B=Xu;*p|Fpsvv%* zZL(5V*I&g^d#fB@Cx=q73&uN3GL>)c_&NJMwCM(Y~XKCsl(ClvvJTSUr za{t5hk6tI%$4Rc*qR8?$);Zw#s{3*C6S)bG4ocmJ9ZuwQg-GVdk~`Mx6g(GYS*1+g zo}Dv~POdp!m7dHX zs0H=3z6B+Nixoa9^odQUew!e|OS1jC*SW<#bWgTSluz`OD{qpdDi(IbPwAibimr7n zQLeeoQCTfdXP$%hz9GM+#}`k$y6m{^t)~sruVhc?uTa=vT;1Z6aDUlO+c`Job=KAl zZ;_VSR1+HhDkGNlDE8iEOhm@Z-KOnHnc?;Jm~o1(OKsZr)?5xNYk&CiUee%0%IcaI z6B!msoL=gy4+q3vHF}eNZhlw%RYb$Ub@jZ2TO})I1+}%_>Nf1zdn!79hkg4wPuKZ1 zGT5)p^v7*UB(M2dR;#aSXepzI#h=?rjh#J7T(a|~;=AUD);4b4`eUY=L1q8eAK{OO zspHkK%$j1=xcvB^B~~w+Pi*MPcXP5+C)Rh($*gW(=eFK# zqPC8aSBZy|6?r`{Usg#$T`nvve=C#_Y0Kv(@UEt{X>TiTkh0!B1No zw>@JX3jfv7mV4;6@|Gt7noa4Qn_kW9OFj~#zW(ZP(SyRqKBuD;GYoHuJ2*zpbz#PZf7G~@+9y-mqBu1> ztjEUPAS-y4FoQd5X%r9^={60RvTVAd7 zRP)7><#t6)YEsnJ12tM*K`v`Gif-ZH zAF`WvU2s1ZG9^WKM^%IUMYS!WgL{%*_-a@uVC`ls!#U?*aWq_vM)M!u`RbLY^( zL*F(SghrJp%jkdFCBFaDi%(`Uf>;>&hSJeieRrUAgnzuW8MC`Ic8&b=UznTo^C(j+V=r?p*hyur6&^rA@F@ zo&tmC-mKGPyWc--T-K$Yxn7C~XLuFpeg3*2mfW){DwC*i*{E{6uzwdHHeIB?YW62j zXeD=@`kB^o^0%(sU7RFUM=$&)r?%{4!E(^8Dkcp9Iw> z^*k`1_vU62Env#>Q>4>}&ty5(IbGd8dGhOWbBS?Yw$y?Z@zLqscb2(#-AKE(e&%>t zr=sa{Ll1j>_HzAq(kI4kXC5teYK|~lY2iigIC5!*>iI2s!`Fj??$$Y``_6hV zx8Jhs*?HCcf|AKH6K=foULH4L@%iihS7OdiYuYoY+TIjjcJq~6;5=))x!J2-=X=D@ zvznV7XzaXuN&8|EoiE#UG_7UU&R!b*RwV3XaW_}jP&+%0uHafTsv%8#%PY<7m})7O z7(K9CwYZIZq+zx)zJ2&w`EC=s`WvOJBhM!9Ta=NtGQs)2W0u|vi}e1NqT61-Y>w*c zUzC2mP0Hg!TT$ob&YG(^b7n~lzm40sc(X;Rt8D7#Il*=Ns8~qVvROkL-lYeoY~;O7 z4@@;E8c26m=yQ`eSF8CnRCdr?{PMefH1UkQieA|UDYC6Yaqs#z)f}xyIZr7uigS|u z>--8PSUYTa*;6g08P%dz-{kS_kk~dEF^%s;VD9%*jP%?Q|C*rE-nZRaMW!ROYYyuy zaBK~1o74Ta`z2u-pwsitx<>1PiF(e6aZS+Nuy1ecZrjCZzOZxYupW709jy*Yt z=>}&^vzYf;j58~I=H04)$cMr!slkC-4KsHo)I>G<#$Z8iB0o4t`nxutkZh@(d=nYir!FPhEHi3Y`|O1Wo<7M~RbUjd zWrf-Yzi{b0C#}EqPWNo*ls>Dd{K5TXG|BqG(}{aqR=8!?wfOmuOput@*wgUcRedOL z$=;SYoBEGIr&HFek(&!%z4#WE-Qrke_TA9%m31I*-(z{-z`;=)X`2Jfwp{(p)Mv<4 z=`q@$8Z9aG%`5gjRd8{E`tioq&yO{BR&9T|LR#B@MiKt-*@JV*9`P?;+0I<_rGe3>mH9H2E_PmLzU<2X zUiQj%O~*UiHBR3SHXglSy=kVEM10laDLQPDA<#Y#ApA2IcX`AoS3 z4fCJBuv^+?GTzyzv3cs-`k~JWAwl7DZz#XXG-eL@+~WS!3$mPhV_Byx*H#DnmZxjK zs`;#LNKS2di%q1fR^75MN~W?m%xW^>RPhbt$?1GMUxJXdq8_v z{I*PW|Kk0+%O}5!pg;cE=c713>N@GKy3wrSmiJR{eXj36c&B$|*-8JswYftxlpgyQ z>SuF0D^kVRmTW)&pwrxx*5Y-o7k+a&}44uVSbTJTDEb`{$+!qKbNOUZnzq? z*(3eaF5iPw)_vHxHe;=k*48Vs7ruWyPkuLFJ^jOq1y+4DAFcb(M>jhy7}+*K+v}+;X{77@Ro(RBUXk|NQ6`b&`?X9biu2DFj|5PqCe|FefcJow9eo1NA z{)~;^GxIABciU9M|6EjD+obv~AV{{QddlLC(s@&pBYB5vX8iP3Rk;0TmgALA+O|*A zS~El`p;6A8)ATKi&%SQBaayWTHFjphOvA*jtv4QinX~0|QD1J+SsSAhuUc*`XUuvL zxpGbHDy21h_NJ1`P^KP;`VEirYC^zMx1i;qlEUBlE*wGTB+;u@w~ z@50I(v=wiWr1LB#U5_mr%(?W%m*P z6yM6EE7M$G$i5*Bc+R4k`Odso7p`@0^zpO_nUd=%@{%(0RkIc3=fxh;E3{s(KRk3u zbs4uI%PK>C9d0#SUCvl$@2=oj4cCWJi7_kGSL$7j(D)I4;QocWSMme>y2^RJ-zb#4 z!!ZTqwR2h~H9p@e&6qwV@q5}y-l?>*>_!S5=_E$o?pFU zUefE@x;^9df-jaDLQYs-c_EqOuZ(bj_?P0L)tnEi~)>AqAWhD#;<2VIVRM>-e z(!$N=&*_m#sNdGTv#nd^M}_KET>$V|>&C{d&o5`ryHfYE%Vzp}J^Rd$PDYTQdaTnA1D7S`$EH8gt z`Lb`7_R&D`^!mvAwr-r+)0{GB(i+=7 zUvdxoQM35<;EyM9D_3{<+NxMJUCh~MFt|uLFS9j(x;1g`+F3i=DtRey$M16VH~hM~ zrQh3oQSIimk*`}P91<%yGf0#!trBZkxPN@q;Wz2`o;*=EA0gE=7ycsETZrC^{51V~ zVR@+f&Dv^wRq>476Hjb-G<|e*PG;$&0-ZaVuA9D0o^5eC?z+XP8FwF=+y2C)>gF=M zN62d7YaUa2GpBaVS=gkoI&@DN@HDbp?uy(U>O1>*)b9_N9*;%#e5W4la@nzQ;QOwLQE7{t7((T zd+grc`|-qQ8eU};b?JIZ{a%9wjzH$vZn#kJbuvw}QQzQB$e|2--SX;uUPDD&&W>X> zlEj;9FJ<4a*W1%3Ag%V8>-X_M<1P2ql{NW~1~xlBj-M`;OLT`QTv}|Xv}JGocB1{v z`K$N8+SMJ88r(EI^Jb7nj%Vs7kzekw&f}I36rR_+es6X^Uw_&!c+GU9lWWq=M&=e4 zjN6;6bNjC)=i-hm8@K1L{X^dJRUa=LJ@{PJgkd}0IV4~D%bI)RLNptF5B>3n9(rjxHN zYks6P?;DRRq&E4ri!ag{mTKPDNYh#OXz!fr%rClC87n5=@ml8ouJYbO&YS3xTMs@D z{|Z~a+cfXx>H0ToO)e_gxRs6XUXU8BoF_KIj1wPzJC1kZaGBW!Q58vpm2_5c*CjJ7 zMbm6;;8lB4xP)Zd!M$m3KmR|fzA3zu=lMFev$36QY}>YN+qP|IWBU`^wr$(q?3?fJ zfAwBeS9SNy#XK|5OxM&or-3wsK&DX&fZBxLzDy{AN`H?1u%MK1i{`u?LyI}cX#rdbO^X*06!Vpm zPe_s;2=XW)dfMIWgrxbVrUh!1)q_DyWDm z3012Ae1!YRdMPJqy3fP;n1?z)MwKyxoC5|u!8Q~+xLD$#frLa{CNEP_ers|nGiUq$ z!BkZIf}{PwHj7kj>!@K$7UA;*CF`PvRf?KTbU~{e6#LBWvt1GK=ORbsL z3K}OZ$kDeGj4l8CB|v~4DbS9b&z=-$TgEre{M<+==L};2c$=oFMQB^Z!~xyhcG{?> zM)S?40+K6dY?}OZB4ID97SN8lByf#GXt@TFT@%)%zjabdZa0bPNXz%{o>%IzG6J?Hk}NFTp8f33YKM&}h@{bty_U>Z0^Keh`-E%PyoAh+ytwD*q`A zBCGfJUND09QZis@0b4VtWdmD7*M)1GAAekNR6IH1VFy;YgbwP%%B<+ax`g+#8H4BH zV}yjs458&TG=Q`+RXpei-iU6lX%xtNLye3`O|EH-W8qM98XK4Vs5#GN)g3Ia{XWq( zB6K6_^}a)xikalVU{tuiyA>$j-wk95AU7H81>Hve#%oi0dyQfBsakcY(G#YrW<9Z< zGDAqU8Km~y^$;sL!kN_=Rd>KM*R2NRX+S8s7X)3d!_;E@ZquvYJN5ymH;-MKl*G`Z z!>LH06uUSclIY$tE!NA6O6*9)uE4n;0m*!L8QK9u&2Ck#>x-66s_`P@)rCyid2!H# zM$eh!RIl7e(0-Qc{=33>cyqDTbPXc5X~!nNK<1s;e9sn5an3Sncxa0*zW@v?zd%bC zcpktbBNzA@o3_v=BS4?#x@TrRjf+CW<6?Qggk9#Dg27C~vz!b5e?WIsKa1;X2u5T?8}IQuY_cs!B!z~ z4r9x|?!z>P_n1^>nZb6D1;axs0YBLUk1NGGg$0juMCYKIZ%<=g9P0SWZkpuZl9tWc z-X_&%mNmGZgz1D9c9&eGVs=wH1cNf9YBIH@7>mbSLmnF(Hzz6nxEYFGsw&@aR!&W* zBcBXgm2-K9_`7A7VJiu5W{sI)%V@x+?2d`C0nK+sPDImqG$+@0Lq}`_`y! zJNma5VOxneMy&}iDLlyrod!)-FZZ6!MsC*HUuqIJb}S=zM!oEqe)*UL@{70ZIlW^t zBuxZ7e^fbFKL+~;mKH27&~g&iR5KFrK#&y=`fN&BCRsVAP5A+dd3J%QAw43HXLz|} zzhLhr$a2s_&eTM5w4$=tKvt!f3ZG=kMSHH+wBF(K1^fF%aONJ{&f8wu?bluOt=C<* zj@w>ZQS_;{OjQH+WZui{_aD<;{b05$@PdMRk=QtNg>_$pEeGGfXR7p$&XVZK{iTxb z!=CHIuA3C7J&*{o2@TU)1_7gQD6sFwyyRZKxF&jkZB%YQ?L-r0k0I;}Dt(E;41}%_ z{;85AUyvi;kRFu1?QXzgU+O6$bGwHgJ=M@@W51EEa(b1~5qNZ9Hz0S_@+dg!&VE#26-o}EJ;dA zrk|(K&P+l+bbgvxtS+gwDx9o&KqOsLy#ye*tLsUj z%0PE@7B4U#OU*w1wk1p4c?MSt{S(q33yI90aYKQ6AUH$lkuV$!*)U2?k_aJ`N-!|} z#s{2y%WWGN&cWa*Q4b!s(bA`A1&fPj6Idjty;p7l%QICtIta##e=>h)c>3OK{PeZK z=>2+bx8W4`r-{idS1T!6PV8TQtnfE6o@I?GR z78-yo;zDq|@;AP6M(~%vm_z)cDL>K%l1`V)SwGLXB@o)yp%v7$j{r}R9_tUlK;dte z@>0Ovp_R$!@JV<@h11$t!y9ZsrGz zw#TFtAk`rZq^Lo?pn?B7F#>djNMIn|lKG?FF#BaWy$g(N^NUjBHsgV5-N- z_%jS!+DOmjWso6wI<_HgBg}Thi3-q*kOn2o6oqAgF6^OO{2LCcBS_7gaAz3(0f!Rb z7IbA;(C>w31~&xJUQ5YT&h%?6In$vhxGkJLaDzIpyS@QGZ4-F_6L*#_nsub$70TFz z$6V2t=3sfkL^i@)2SN;?Kn`Bhn$o-AM}{d_)*0S^)cMQlG##@8)T4W>wL9|xA~;BT ziO1&71cAsD-Z3*QQy6OzDKdvPm2(O%AEwtk+$(b0pTnG*5KW+@oohiM*lCidFNsr# zzb#Wlp74p{44M>`_a0}44*Wx5oetbi(1N8fM14T4WNOM7C#(Ugb4etJc5*dMp%IFw z84m>_Ih6s);=PC?8LL7Jq6mpgP3$1Vqrry39Q{HN!IlWPq_ukM^x^MdsoxK|{1#Q!a}?tD6ElVLBL0;2KYUb44if?{tAtivJ0wQ8O_S zm@FGmtYlZRm6G^95DSF7=c6${L|PLFSgd07l_FkI+Wm`{8S<{WsExj1-%?Wty402Z zlzMGdl%+aa>%8i)jXIjNt}2bYYQvW5u#P%fv@UDjZRNdJv}uNId@6V`}8hy0e3>{0>EkpMZx!3w)9p|s*R_^Rwu104cIc3H(kk!=?6k)&nW z^m_PCu+<^kvr@}qj55IzaLKIFTL_DB1_&bvta>cLwO?*lmawrQSFsD2n9C?>93Ir(g2RL)b&JYQkxhQH{9rWc9eT{S@El1`I)LU-?L zp`lA2c+}Cdnb_22iN`58pRRRWWah?sF#fa*M2WZahEI9^jz`AHFBIClF*MVIf%=t2 z%`&LOHmEek(3m{!5Xe0!Y7-XCFlg%ok0BfuHkX~NRXR%g#EX<8(Z#|!0pW`^hpJ&C zA>Tg1+%v@eD=j9iN^wMdl89TFZD0!K=|J(&x-`BK31-6XQ=;~9JsbF-@z9=@RFLNttY7O8I4Ite|X?o6|A<-X#bH8>K4ww;Tx z%j;jYt*yYT%^*7BqHQ~ZdtQ)`tK3jJtL=Lod7+mO6gs0GZE+0_c!w)Q4JmsanN#0p zz_r=qCKh%$wb~jg)|NkxN~d+hVOwgyLp9)1jY6lDYp+8!=#pcz-UG&=JNxOt4y)E3 z)}cEcZcUFu=k{>V>krWCCzZ}Eg+uqB;LE>YwXc&7zVNWCt4M7OMb6ARb?RX zL_kSLbR>xH$wYMe;5Xd)#7gxop>*kan#nZy2q@6>|?UD1t(pnt-+8T)#s0F^WQ#MguN%IIDkh#8^)-+ImG%D5Z# zX-Rz}-;VYQsA9{7 zVh)rngeNciNPJmEumoS#c|84bt(0JR?4~+^XR77h(B_e?XL{5kJHBM)#CXjNM>ftd zyO{y0ap}akczP7YwvW zJHqBfB*#o{i2DN&hxAuTgPCF=ixasl6E$%HVT9e=sSMl34G~Fc-q6FEdkZs}UAOvEu9<-o zanPt)SrzG2I0k!207+mVEJ$NcJcLVau7r^_(}#2Tj3t@9w+Q2lNn3fbR2<9pBcwpq z+Y>M8Y5z_ygyQZ5v92%S_>TBXLy!F5nl^dzT3x361XbRVa!$hXC3Kk=@BXQH1n*xV zj%TkR)jEoti|3GPJ%3{M7YadR$)qw9`T^xUjDjH5B>CW^l<;hWg~c44eak-0kp~}a zd-gTzn6g1R?qo&M%PDgj_5tRfNvxgNI~g3i5cBtvOTbTGv(d?SV9o~@jN@M*vhsAnhVq0=4=#7hP zExa{to+gXu=_#;fnbWZU!fc+Y669!saiZ$MT)r( zy}Y|xwa7CYe>P#a$op@IBB%>dhf(g!!kKXDKzHK8p6Nb-c%_?%&RI`pIT2@@HY(>h_)02HY!6k9NvG{!G^q}cUlYJtwbPkm9;EfL&d+!D6 z;_Z_F*w{&cSX#6RYv)*n8HOkR=W@u|YLF@*TI2slLYHYOK8@A|>ovHcCe|Y)GNtb} zYFPci4ALAn?4U=IkD9kpx{e0*IkZrmkm|YWrXIjk9D4$o+Mk$;Ty(|AZReHz@H$c+ zp=rn_=Ss{>p6|*gRor27(;r1?&C|OkB{e4tGQ03~@tC4WaL{_O1>`1CrRSPOuI$@nsZ4uHJMf>^v@ZYUFnEn{61n;gEe38@yjXA+u3W{b5qV7bs4;8| z0?Z-&;tPs#mOdo9>m>@?8V5-t6&`9&j~EN7Pn)o{WvU7a!~ay3fiPx=V%}Zv*odkp zY9$H{^;#9q{Hh+F$xoCx|L+8r+&wED$cFWJi9^QMzx62Y!(TZ0SHGYY++cuDoJau5 z;{s7)3#+msfxEmG3#+Q~RrvPx&mO@`hwx2;^b~=j0UOCa%gj5LBt*~9^d}3lm{T6f zDj%{#DaE$tF|*lRQtFf+^Vy`O>|bek$9=Rar9LQhumRE zJ^(m^iXkj6NAh^Oau+h(HFLA5OtJO@`7t2T5xD2Z`^3i`GbtSDFERzj$e6cthn7Xbw5dSEu4VkQC z+IaY5b1_JZqL&v9TqdBU2ca{`E^*$bLbuU|Bz%Ik0X>1UIw~#Y8n8sh3^QpXYoU<@7%V{ zUwAFYw+54=$%rLsy~eFycnc5iYiYg77M`Cqe|O6uLh2X=-Uv>tu{zQ@oC)|+^d{$M z*0&(t+@a6DLF2i}7$P5r)T;v3w;E5J#+aQ_BlulS9>?N&&R{J|W517MNhAXb*6Yl?qs#w6Bgmd3%g ze#~;&oj*LYObbX_eADpxf>bkd(f^kA50fM(&pe?pEI!kPlb>$N8C&Sgk@CS9RHnC% zTtfY!Z=7swcpb!esKckJ9(ey|j*-3%d@7#KH7@o?EaHS*&l-EmyC|Z25DQiL^hMX& z9evdrbW9pN_6bO|<^+FMXQR*msf?KCl}Y&G>k1Zpw|GDEgfXskV_zgbTKy8ecnnw) z3eWi=h^zcz2VEJwH8Q)JsT#)%yNFlHPWTs|nLv{U~LIsP2bqlTnMnAwT<2ES?Ut1IXcsGV>IZ~*_Tbab;M4T7C9?+DC=e6zBwn2}2^@dKH73*}0v$0tb0@%XY7*o} zMc6^2$Z`f+j{${X`+v9!^qa#=!Y>0bRS4{Ahh5kmKk)ccR*bU9>V^Zhb%px&E&9^w zb}>t+hRCq*U`##m;}8ucL}L%5vuMgPZb}UHJ;CT+Vs40u`GOkA0y3rvAECD1^;Uk^ z^3zf-bc_@UdueAna7eaj$-vMj*`9@mlf;ngMpqe4tL zQ2?&lu*m(hkiq_CDB6({N`m;LX)HOtS;l+p{$uv9|1o`i7X(VY3eQDYovELl07)s6 zsD_1Fbf@lE>Yb7YyyOP1_tt%~At*7n#PIl;sAM_KN&~!&P)mXLa?((i5p4$3SvGbQ z1NP!eU)5AoZp0{_s$8k8{G}TwqbgQ@GH6rr6>^Wpl{vccsb14|7r`+c?|Oxjd6i zoMG{VW4ejcpwzR`R4E!o{gBHbVoF{XC&sL)-)8X{16y+iH+&U1rNsQ~qk$TW z;?(oaCIz4$2=7E?6tyi?bh9XDEELc>L{J(Nsk6zNWl`r_Jj_hgsAd#9fBZ_P;B<@+ zY||bTG~pc?_kvTgZaq%qy&ut#RmDT=$0UT=(Jcq38ajp0tgtUtLIf)(P${m|V_g?* zDaY-Uu!tMA1>gRIKKt@}XNs*@)fKRxkJjDfS9?V?QLX!Ah*i9{ycvq1I~IZTImEnL z)uHxC3^x}}F2y<>&yj+z6+f!Tb~?jEj1SzbB9EX$Kq~mm3MH?orn>?(`7x5{+AqldHa9^9R1SL{u-a5*nhIJvPt5VbU#D}!gu^hT zC$*s+Z$<*DK@PTRUN_Zgh=!0QXhOj$(b8!}(>?FFZ5{%lWqcj?gs5XQ~7VcRI!j`dQ9 zVYv8o>9rGIfg1sZ;-yEvIRsZdggo#CFU>?hv_KxG{TGSnI0^X6&h|eZgE#JYwXNepgC_{OG^N;&Wk+Bozo%2*+4_le95-B2Ou3w(m*364GEV z15jP?fI?c#j-cJDPQd6&9QeYPMQLBn*K-~a6c~b#47?WNc_gg` zVx`b-22$X;?Md1*)sTzWLMqX3O3oq_@1kGYTP7ysF1HUU=343?1O8r!Sjt7?m85V> zY1*YfDE}R3rwh%5<%f--;_@>Q`ihBkffAX?_`ouk`3pBHRhJ9J$({$O1{SRlt#9;` ztFHdTT~nQ|@%JOi^tNkgotu9BWky=>3`EFzlbhc0CvNF}L}_q`J9-0OKJJxZ9U}C} z#JEraQ1}&$B<8(^V$Yf~2Clqd)c5S8fA#|LyiVhBVfLCp9;Oeiy_4BreKo=xpQ3FD z)`5-45l*!9^$=rn|HN^UxOfrOivQG?z#g_mYQO8s&%-PhXWr3T@!!x0+<#xPQa6Dn zOwA#@!FQ^@XECdx)`ufSddR{zlO3?S@XgVA!GFXiN3H_#4BFcFCUK=^C3(duDwWy5 zB9R6^E9WH9_9+j6$duWvgYX>J1Ic?%o}q=5r>;m9{*kkUo%?8+`%FvY>{t9l755=? zJdts}8m^322Wh5Kt{xfFJ44&AZ$4eV>dPF3^hwTRH&x9cTT`_d=t?HsXSveBg{PrT z?x+C-w9o0Kh1R5>w<{x?=RZ02*lG3^7E!q~LubB&cF1m#X3Y6mi`fgTf!S*a{yfu5 zJz_sc-!Nlj;K;-wT8N^OvuuBdw@-P=YS;Wg9!RNq%&Az-#dr#A3lZxaQXH@ zZd$$D*yj*}=dS0=IVi$5Ka{t(Q0%94y-q=Ujyc+yXQ9CCBg|8m=UoJ@-#ZQ`8hr1% zvzULd=lLIICg!(Rf$H0d(NuAEeab zqXm>vun4k`JsXT&r(;0-5eQgPJuj&(Ond(p2yPqrqc0|wi&qP7VCLw0Q++%B?pi95 zk{b+(TTYqjjNRKn4u#aYW&ySoeRwXdweC%_t}DY6w2QzqaWk=pjH0P;?Z!T{3bTao zwtEnYvGSa=9SllejJKkqVkpZbkJUOa)$!Mf7`!^1K z1JqhH&AKf3)i=rvq5!I;;Cc|HETa^ibqeU|eGpvsF4*}V_np~zb7#t|Z9`7s)(@w( z;@7MSh;vQOu2?Mu=y1_P-^Iadz~G)>K>vV2@;Xz*y(MsB`!ev-_dOk~ph7F_h*dU8 z2xRnLGhz312oGCcGuZ2Qwk8~o%$;{VYHzs18?VT~ZNZkNSN;OvNq}i~;gCHC75FR; z@YIKQ;Vzhhu4#b5nP#R-_)GJM#>uJCo0brF<|1!jF*vVWn;Wxqd>`YM>IFt+a+Cbjuur`EMBGHu?!AWLA#ont+E#f1PdWK|T z*+f#2*d}k1?W@EkT6#Sy)A;)As4TDQ%K6&7)GimlelIV#`S10Haw01FpVpy~>iq*-OG*W3nlj zV+K*d^*9sA>t6MPSb6`52{d&na%IBT5BzrMw1oU#G-gQO=th}M)abc}mg~}NIr8W4 z`;f2HG!uAY{il?XLu6c3%LCKzi1dJM!ZxcwitPsQ6%KxGxysUgKm1iWVvR)*FOEyg z@zzevVfI{1n#Ej*Nw^tM4kR3|D~MSuLEWJ@?PnH$jQzZ)Ta0H?$>5CBS!wQOGb zXRAX4dY^^W8C!gdcDYF?O9LKfO;y`i|9;Nkrfa1ds^ne$sB{&V&8alq%CJmYP@%5q z)yA4wSJpIfes8{!n|WDSM6HUrl1!Tmkhg6yWeg8)d9xeXC(ru}E1{`)_umx7iuY3w zCZCaSbPA}#*-dxOY0Z+bLlu4)C=WdR=4wkAl{_PMni0S*Ar8{((GJg}A=(pq11F*O zKx=FYLT8gplq9cAF$D^868+Xeir9p#ojFiqoVBjJ1?=#;bz*(5i zJ-F)4g`E0vw@#N#me*;?8?^E(Kj;dC9AvXZ0fzoLI(N=|%Q>}1w~G8UQ}7PRwRYV= zanWF|P}3fv<5sdqG^-Td8W_y}+H^AO83b=|#$oEdUlbV%1!l=UAm-MMxi0|V^{4d! zoBbd2VI!1g1wTca5~~J*B?6j_%jmLJVg_1afDkD0+-F6gT*1Vctr|RC2vwg>dJPQR z7FRh*HBtdHAZn@U%GrRxywI0nT9Fn~mPr}#1hTI!a#A`YHAsC=J*0_k_Ha)OS4Vus5!4o z?Cut&;V%JGP2J|e==>0saQl6y#>H?j<1^GpqDa|v?+JdzlF9p{Sbi3A-(m{r;-QA7 zp@#dIEDe(2?)1Y*NdK;w48gw4N-ojyQRXI=dAs!?w@GsIl))=%o4u|ekW(}e2fckS zd+;{l13Wm1jBZZWC7qf46ErgcA^T!Y`hGMc0ikIp59r!Htg*uxG%km;iRS;fJ`oP; z8JA=O$#zH}RYTN~qHWZSDFy2u#BAzLlaJJ@<`4q4L#m@vD@@%JA&FI2P!0lz#C^b; z5kQbdv(QgwT(g5OUa5ZzgVKUC#%e4 zt3TLqRz-iA+z45*HiyU7nooS~s@rk%z&p2v>%r3pc5mG?>uJx*>iLh2|5)ryefY^`8}!-QN=M-K zPJ4fQjVp<6@NPMQw8ETu`w41BXW$ zD&%b;hX+P~f9FQu|LnFwx2`bHHoyo=h?uw-VJ=}EcY@jnz{@%{d`=6b! zelkv`_xj5A<<3wqVwSkb86WG~)B)dCt-(*oV@?+}=iB37V4QukD-Z9}+aGXixL7QW zfMvaamnPdWXqS9bZ?k~+BGd6eDNB^)5}r%GZ8%#Dcy!Ki2{-+jG+#&sP_Akefymdk&yVI{gJ5E0oA{h&qCnC!Oy5B`_>or<$&OK`LAF zu1~D)hOWQ+Bb&VO}C>SFDp?cJNom`y*-&{|i*|kGKEMARmxl z`-$-4(-J<0I|CzbD{XCTNA_ewxS4i*4XtU=EiEb*Sc$I28+Ve(q+Cqr7X^N1ip^8`oDk?=_Zac9pCQ}*jV9MY`v^AWt8)H0XW`E(FCKd81d)kOpy!;fldV0rQFVtTjBGH91#kuW3~$$g zKe(jp@Yb={aljsfx1j0~qQjsCV2m5xif)DJVMVG_`9BgX{=;}C_bi9hS7~4B@Kn5A z3y%u7*SI_p)d7xNnU1ysIS;1X*Ppnm%_%1FYOF!#9gjPc^cInCB=Jg$IU7HU2z%a_ zWKH#9U2ev9D{YrI0+9mZNsb0!++%p(^?f$6nfsrnCn%apuGX!z{2JeP0)EJ*L!B2r8zFAVdo+IaPk1n@0QciQ{r^j()3bk`x#{#UIGV>#Qdq0=xzEJYRl|Y=L6N^`Oi} z^}fQ7C#)|Kp6icO{3wvC4iHztiEq?s>qs(U8PxQr%Cu7MSgUhz1H*W9$oVtpCgPvY z+;#sly!+QBt^-&eQG3^+bWDzEv0Z=CaYLJrGHjCw&C_TfAq8$iIC228#7Vp5S6Fte zz-+2HiNokyHxAiTQe5XAw|S}A&{rO#(YKghw`3exC)<0rkJG9BjJkaQZQj;2mY54qplJRf z{?VMtWsePhSEOY#fVJ4p#qC3VBXaZx- zH_S=z1xGU_*rd$BY6`rwxJSM|JR_D>u^dO5gBX$s<~Z>j$C*?d85QH>u--$gA2Qgq z@QA>TG~Z=56l4`b` zw>f#UMp`Fyxh<%Q4FzRdF+|iLrUI^USpQJmejLMqyAr0%bW%J6h&D_xG!0y^r>1F& z!ad8N>7@mmk_zl}(!6a<0?YYrITtAG+A zPa#+690vTn^;(uHxdzV657kg~n5c|QxJr7V;@`AGG4^k46g)7OqLv&U4E+eFu74dn zRzyCah^4S+7V4B`X}5Kf-sMtGWJgeHQ;90>6pMPY#vXz{^*379W+q8?L+@p0on*U= z{auEw7CI~WMe=99ny3RhRF`GCPGBD1od|iGIs=DFU@D13&!s1ca-LeZ;FMc`m}5bg#00ss-cpCT1xI&?6`E|{*|v2wyOweQFO-` zWdSn#!8B$;B=myG$iPn}e9WF2UG5Z9zeuA|Y`oEUCj{0UOL@C!YQ^`|%=@y(nOa|k zT3w||J!QU2&B(OX$b7TKi@M|AS0)aP=HSQ&UD7n2j>B5NO@JNOVWNRlf$p^~W`-or z(s&IdA$sCZ6KhC!4C0Ba$IX6;L-8C-0ScSRs1{%hfi46>;0DGa93)mo5gZ59UXxF9 z7m4Qr77==13!AJv7-hcIMF`Z}4htgClX4{LZNh$@xIK=~c-Zl?#fGlKjhgVZ+(vBO z924x!_SyI^jGRtJa(JA-C6D-(W-s|!`?*pdLiF0tydRG6B_e+!7j>l*R~ZQ%wb!qNT(9rOh)NSTD?H{MCj@nxD1`^1BU6W=Do8v-8cfp0AcS z$FoQL&hfh0SI4^|-nwq@aO3jH@jCUUDe%tu<-yO0{`S;Y`%`vTjSF}a6wGGdy{mPm zYhoF5&0B0yyIQ=QG>Mg;P}C z=dlJ;9}Y#~sh+JYMv!eTn1)jhk; z@Cn1YF0ojf-ZNY&Sr>d$k<&KMIAQ&<%_!!oOjjTRj9JGYpgpjU4#Eip4^;+E{ax2v z7SnHq(P0C-KI}`f0xEK@-wdiVwx#;O)V-lbQ^p2#Nz6JUs<({qEHrn;i}igMSSs<^ zaQs6>R8#p$mUqH4;D3c#W>#57vY~$}ZPtdyy4Jp+1&EQa5;-{4QG#4618>L;41OWD zgGw5$eTO-L_iac2yn|rp5mm4Y2_(!S{Jz4Px$_)C&meE+^63kkrWD;WMOkhYg))a{ zn9A1v+N|@+H@YDz#K!q3xiUVCn7f-&>_b;_$s0gbCOE7Uy99CjK`tRzL*)XI8M4N< zTv4@{3Y35WEafX|bI2ZlNjSR~Nes~S4b~f&lOAW2V-!EZ;$oU@;$)ib8za>=Q@h2&^JDwErmVfq1Kys3KV+^)Y2nHzNt=JH zsA%=Ze0HmQ*OQf&VP#=wWfMP2z3e{lX3aX*Xy38!Q5W_QCI#zN?`3T9LS3eR<&r7& z9=`ML`+W}pJY-*w+4tn^9uV@2^=^eD4&HT3om~5Fp*-{XV2&s;z8bRN%GZ0~Iq}aE zy@tC+G)wpfED|9?MK3{Ki(Uk~B!1-AOZd*UOZXzizfow3Qok!Kfal17h)`8}ofdh` zgg5WbA3-QHMHl6-wMlxh?8CBc`m5X?hhe+^il5{tIHIKS?-GP_zf)w5{K~W1nY{S| z18;$I)Y&?8(aB$cHqRz)|=ZSGYuY#)ZFT@#lASjBSGk#l$q?&Up!Nj2|C;j7vQ9RGZKv#>7Y6#REm>%2KNX^gUxjfTKK8Cp~6k9*qWEl6cU}TmTc( z#XC^1iT7=s$7Nrr#%fowC^alRQtFQLMaic(k@3a{$=aC7i8O;!ua7Dv=ip$Dw=c)^ z1#OBmzWHI$bG1exYp_fbakXY4Ye31vEJ4ul?6!L~lX0~cX3I+{=SUb!j@n{|4%v|* z$8U1nx6wuj4OFFVMtXJQ?LL{j0Na2wwPRXLQ?E`zfmR@wc!#&_3VZGb zrW&N&;1OOZHTf94Am|BLv`XMh%98p|M-;znef0gGD7}x%(S3tFa6xd}*jCVtZ{jVD=UrC&Xn*zu9<(*?rk*!E+K^Nkk4D}6i2893WNStbP&avZx^x`tywh-sz_WaJx zlKU6;y?HW%>HP9$t1*(PiOubGYf+cuEPji(JU#P*mr<)(^0MU*nFgc@%TsY$`K|38 z`Kir?>K~0jN;~-YY@k3VGkP)dL5?OJXV@69d){vU>yFzC=+ylU3X*-rsA7B z)p|z|Vqz?xBEt0EyYqK%nd*DDO6qQ_X6mlC>N~F*+1XcI-z0%jaC$nHhv#HKx{be5 zy~YE&Uix9fj|M7@C#>&q7r8&Iy?sh;LHr}IZ$=L3uKd8%4KqWhB{faxxXdxLposT( z+opYl-apxeDc13RcwOdq&7?1y5ivvgKe=Q?Pl<$h-dwQ0r|QHu0y)d(c}W?LYOxlu z%s^M1xx5Q}B_U@!6)C(WE^6Xfu-=(7Ug59{7N`{So^ER5_{>_oRC&PB!Prtgqs0Jk;f5ss^y)5KFBrOaief$A5qhq+;#NhnZP%gJx;X42o(Q z9a}|AP;bzL`OA+cJ^lmN`+g|Zs!-2HPfwPAWq+Q#bLwB8YsRPY<6xgl?Fb(++K|2@ zb-{e2u1M(8%RiIkBD?n&`O7vn{T|U{!0Jokdl%N;$QiL-I1Z10|;*Y4`35_LM1m|Idj`4h*|U0 zM%CCTVpY(g<0e3|D`*tnCqRt5=yRGXv20YC>njs;f1IT%^S0`=NmUk=Dl4<%GD1cG zCuc?AODCL#zhQtI7fXyQ)BY4P!!Jz)ibV_~0agP;fo9h1pJl2+dv!lT*S8S&_Noo> zkWMcWLS3(dF=iJ;C1_o5-_J&cdfKk^skgV5r7pKOu+4oPyU(F~tG2Fl=@$M{?>-fc zYtlCQ#4b^B0C{(C|zN?8B;xD$KI0UjUng?QiR3kaMTj2pm_SMB&f zcqbRQ3hUm!0vI>X$HmSUU=<@rvgXUs3AzoeK(=jMW(*Ci0c+WQ%bVbQSRNjIAb;SV zo*nj*14k8o6>fn(Ov*y|IH&Noa+pAUKkO`PYN{%tM6*a5bYl(vNu7`s;}8pkn2nzp z&nPi|kk&JNn2<%X`~gfsnT`iY$hBjf%!45pk92wvD*aFD+hCYD(=yNxm`lZ=G3+=` z&`Pv!Rx>VnM*yrdZBms@Svr5BStl-uX32?D4As=SU59?YA&q4iv*I%SahoRC)ZH?EmovnWn6#=5N~32vG_uu@$lb3m%*QuedLPZ>q}v??y?=UN(aW&$2bx z7TQua5!tm+Wi5yW+t9qW57MM0=?2Isi&&Wf6j@|I1x1LUh$sSzf+$iD7e-uwaYGs7 zh$1d9Zv4OJ-nTXjHT*vQ{fthU+}HCX!BOdy2Cs2p1=G0SLRLV^g)wdqBP@?Cc9i+4obEDrUsO zv_7A#>XiEB->Yv<+S_B(EOh9(aSz=UQ=1HVam!A!yY=A^PvCC z_DA*{EY1C@(7E+OhnZbH_B~bK+_Ym}zr>AOqxV12xm#l9xz0Cu=8o3{7ASkU-r z>E<4dbKg8x{c!jA>?O}#OikRecfvzGwnf>-40v(iu~S=jN(=XF+<9$5tGJBgt?$kK zqhk8Llm$z7tg#Ilx+V75lEqIn>B|f9>4uR(X$3T_PmIy?@ep(U z-hJ`zsC#^EdKLcCBPR3E>OZC}Su8DCoc_j{Hm!He+Zuaa$3HH7cVo-Uydjx+^M38! zqRGypiKDy|UH`dv@`|xt^5Z9$U)VIcb^a?ExeI>!_4(EQapx1;HjjV(#rTKZKTUb^ zV8P1&Y_M<3c`+~X@H7AZdHC?@Kfi7|`0}AHcfXZ;=lFBydbUh&GjLVfq3J8zr}yqQ zdgskQ3|Q>#_uZz$#lKJZU)qhiFCQ4aqQ@`3^Ecdh+&z8N(pLEkYpsJG+3D)HeMQHO z&#pckoBQ-{$O%*ZbVhpOsAOxMaj&->I=D7ZknIrumQ8MDM+N)ttsNT}ub|89DrP z@9B9bOB37V zHT>6I_6|7*Tvf}TxvJBPrmnW_?Y`}8UVOaon!KkEbWWMra(ssQjj?ZbTr_iT-{oa% zU+DM7$p)u?yr%nsw5Vg3S}rdekX3r{bamE|&h5X;m~n8%?30@ZF8iZ6=T-BGQ;m-| zJJ7<@^|QFF+n@d{?)RK!z(@IOo!4%D>f)HaU5D(gT3)uH-E|*0Hq1SAbhBky#gtYD zzr0j*yz9HyuKVJe!FI>1+0!44pO(HYG3(fyTjF9*o$PI^>7Mg$*R?sGwSVt-zV`?A zT+^lNyN&*@wbu^oRsH7gc>am1$wyo5So37Vqz8{rIP_$bf0jMD=B|f+ZkxGx!GO^X z7TBEsJeQc&bVvI(jyJmP_v|@)*Xmo}`th?q1FCLqc(PmO`yaMD)i$YLUVm5re; z*gLl^ZBfy#Vx;?Y{ofCu3{^ud@OVyc6uTM>1dc&wy9_z>Z8=Y z|JV)tV?I80civsAOt0Otxxp_B^9!F$eYAJnoKD+f+w5zf*k^s4S>OHC;LHnS&nKPy z`SxMm{+E>V-HItE-x*RpRCvD4wJ%9&q)e zTZU|yde6VM-8<*~h7Q|~Tyf&C(F1x7ZhIlN?^oRq-16|DZ@b3tI{f4HCr70BdbY{3 z`=q&#Reh6sU`&3y=HD#2Zs@ObyUZ@jD7MZYIjY})DPND+xUqeQwDR@GGM@NC#3#?H zm;Qd>fcW$SNBRwTZ79ykSvKVDdl%mO&C666Blkn0*d)5zqS9DL@c;@P99}7n;(_bEZCTsP-|9MUK zmj^#FdCA_7)_;Drec!8n4t1}6anGO*oxeTWG;99h)w}=kgZuPvoerG)N7{}%hfP^D z^PlSu?CP`Ut`nWMf0Vtq^#N(Y%*Q{pG@CT}fl9IOo<-jr>N=>SJ;B<1>$)jVKfXPu zi!`DBARown?1QPq9-&fVR|ee&M3Z*+LJ#q_G% zKG?ByXxi+RT~|H)r8%!nb;Z5s*WT~w-KqBe_Wjp17`C@{!QU%3ypZ51oib?j>{g$y zJ~3-c)aU`{W^EaCW3ALG^VPJXR!3cN+g?aW>~s3;;N*9n`SDV-*?TwMxAEsOuTOOO zKHql3gzd-kp1e4{SyoE#Ew(K$ym#*8)_b1%c-(>F9sPIC8ny1jikJGY#J{tyzvG&G z{5$FT4#&sb@@Buux11Z7^5FeL?r=2fFlhcl$EQpFmcBCW@vgJ_J!W3>+rB)@^m(@~ z-M_hUR?FvSu9&%|rs%8O^<6jbX|^bBQp}k%@BP;6-USs&ojR{RvU}XPZye+=5v12kHt~v8-X5hk_YAwM z(&@!F?5&eAq7%Qy%*>HIUXNgNi-OH5xZHNpE!qW-II~=I7K(zaNDv)jspzCJPCFat zapE)zY1

hA7Zj!?BnY>Pl^TsgTx1$9Ww+xh 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 j>>BIH@bZ zz@jQd2ejfCrXmr_NRO&8Jz9jR5Hn8c^ax22Iwhqq0wPL`BvGP>Ub)z#yaqNu`j< zK`w|$goH$c4zs}jzKr6~8(VX?~~Tcbr4Vg$adeIKD58G5b^C z+pbO4Gx#g>-vp?|2nwJUN0`_^W3&Ud!3b$YfbWwbl$OCC@MZvT4YCTw(5(fp$;}>a=k-EeLQo zkwMm9xqQbR^}`%~l)b5W9Y~K2M&jOf^U`?hZ5Tu!i?K5T7NB}FFenH}Aaj5tFwz(a zMoa{_5i6N!3F48ZL;PKK>{wlz-w|Z&y!ai?X1lC^n6JgWW&rE8-|A{_8(`BY=B1eY zfP)|p!Yw#G6S#eWc+cb@#HeOsx-~_;Bl_AFvU|ah(6@u9P09{);=dJ2dWCqaroVC) z+jou+GnM~qrm}u9`8!jcdlQrY2OQdVWM@;G)4Z0DY*KbMmFB-~RGXBYQEkbMv1)Fr z4hP?DpaePv*?#oB-3<^d;D&P}xMR3k+-xqzt>Dh*ZsqRg)^p8&Q^Sk_g%p@ae@me6 K{czWp5cD5w={DT} literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@pair.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@pair.beam new file mode 100644 index 0000000000000000000000000000000000000000..d5fb3e8a652a4a12965b5892692b00d710e29bef GIT binary patch literal 3648 zcmcIn2~-o;8lGe#SwM(kQxv=kiVF~e;({9rs1y`rb9<5uWFU#jBqkFA)&=VmTpr+3 z)D)_S;Bf_9o{HGIA+%DSD~h`o+$kbzsKwHEX97xHIPZAQ%Q^qKcm8ee_vOF;+&eie zLWCgJqb3DSoHmh+9)%#tJSaR~q7uhc{u)fK?Uo?d>PQP69N= zhSDJ{0pFH!(zq4|T`=Y`1#y6JZ}e-_?{!BIi^^^+c^AP#sfZ@yNf^Q58!s>gTEO7+ z;Cq9PC2#~rgemw2VQ_5y1?Y4>oY>JCK7(WLkJ3uOM-e2F)J9Rn1gkXE*ar#|3Kt3w z3Zv7U8I(->NTH6?E|lHAeGUi2777~*m7@m~i}txS9J{s8E#b(5Ld8;f;40{Ohn>YC(hJ>1qw@dLjeIi|k3TU*@srA};d_FQ$7_Eb$!bB}5!&E{ko+QLHTAh~) z7sl!3N-3=|*R7D=0Ad{}Rm$UpV)GNGCGi9-o`f0RZ4WQ#uRsFh66Fw{+wyR@oBo-c zTe#`E`sQSQ#lFiMzdIUy<3{5$yTc86vSpkDxy;`pJ$p@F=5lq$_N-Sc^D{kz1Y?g^ zFTHD=H~YqN7Rzzr{Uu|DjVZgEmF{5QrhPi?K zVQMj%G99Duqz=#6w80~&`&Z$=)?B|-`E04FjkxO`n|tVy$U{=IWnq?T<*)UBo|_+b zpm2gcFD6ZLXG^Qg-dwlu|ELPSxz2TEq&m%Vpw_gBv+>2(tA*FAHl{4LpFZqvUA3yD zSK5RhpQr8N^e!;%dF#z_{^`<%*+u!@)8FKPdOmx)gLKtMy-UC8zppE*K5%l{Cd|Kd zlFe!Rg2r!*d!ly@elFe}vZlrnkInI{b35C%VBm{e-kVoHQ=IN6n3-W8m}xbnt|a)3 z9%Kw%R=I6&ap1q@MWPm_FzrfCv%)E{mNB6zz;WlyhKKx@hp#T$QeHH+=J2TK1>9*m zOEKc>n9`WPmkb-azFWTGe6=0!QVzp(TuGwXtc zw9bpZv$i?C)->X;XZdf{frobIu3r6%&)fB}&QG^Ql?gq|gctYsFDpBCdtOyz(Sn;v zKR3EWuGn`w$8ToL_d|DIj;v(nJQBUAvkqP4Z9IB)bGW$gj-RhJ4RN%(6z%=0^xB(> z*bu9>sO$wlt0Rabb-cTX;_8P`|eJT5!W$*6Z$q)`6@394k<7d3tZz(R;0vcB?mNfS-?b zi^X?;ME+*6rcQCb?sXD7RvjA4b}GKnlEH0A&Gb!oxwIzL8Eh(@W%ams{?d_A*|rgr zLqjGEoz=XTQ_DDX6}NlBUSAO^TpWGnI(yH-t=HZRED2zZc=StDT)M;lfJMi8ms>wE zRl6q@*p4}{(z#c8W@y}$l=94de(|#tLz;RzJyp79-4p$|mQ`}TziA0Ou5#f1%*lJ- zGDptPH&vXgOCz0Ys;Bo^7}oN$H${lc5Gqf}V({`k;aO8e>e#!h{Wwl^|Eb_GhQl#+y5rkovHD z(M=4RIZAarMuo|kSQN%o(7l*m2h1`kAS}uQ1cXHoR?thJ^h}(fh9eO;Z25!^U;sJ- zDkm_=Nf{tzI7pNy;RL{yxC$poofn9b$#ozeBLJq*Pct?Jvcpa<~dy z$^*I-g2a-6oY0XtCiMdnY8fIA;4>JE8wXs?Q;8Rk2V7lG=LIEWDvc7?!AFTiLSy1l z>oL3WfKUiL$9F{0J`@h*1Hw9;WWI>Epw7J6zdsfY3WuzCfXRB|WB#^v#h>|9)j=ST zVM!EIGE5326vq;PX*5bXE(N5T2jrxg4e&`a+8G0j#)D1^OCSajgTdE;07HNeSUmV| zObv&Rkj+mq_5SqtMMRD0OqAWblVn#sZS9ID`W*WIpovaA=<_W3PzCu}mgs{r#`uCA z=-!zi9(CTPx%s$!2|z_B|NhJfq9b>zBn2XKA3!?=^Uf!qM@3~nSh af-Cv-X95OArD&*p)cu3L8`%7XApZqvmcf_+ literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@result.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@result.beam new file mode 100644 index 0000000000000000000000000000000000000000..68bf12b7d6a0c04e7289b633f7e3c091dea16979 GIT binary patch literal 15204 zcmcIL2{=^U`!goY(9|Gn(nVqHOIceikqTL(5O)|%W?^P*X;Uf{Z4^_K7OAKxX;Vtk zzEP?#EuX%$YDH=DKj+S36n)>X=lOe{oMKm3WswFb9Hy|cHsxv z<8XLO91f>DIF?CASczk()E&>o4l7Mpg3_gRyj$m>)2_(r+c`iMHiAK@MqN@TI#`x8{~&dxOO-&cT4CEz0kmNLp*3O>Q1gy2{r9$x~+Z*X0TUxbZZi$N6&oWb}C zfv=46Vg!HMp_Aa)iH+BH((eT0pSs@0-x!Po6e$Ejz@ERs=PkKl<)4&-43N6_FL0S@vofP}2#N>;`bl~wRW6)~>05?t08F5)mjF~p=Q zsE|?KPQeq^9LSmglcsp~WKD=k!i`Bs4j~W66LkedB^l*L(4pr* z9t}{AmY^IBQI2vY>*I;~qN$8>R)I4bEg&jGYz6|Nii~nA05)_W8v|ft39vB)rn-`i z@I)gKFcr)Tzzc}Ors1%884HN25RHj|s3xQQ0iZE;AX@-577{cT5RJJj*$huK6Vf&p zVY3hr)giE@fT$s(tUv+Gv~nQZ0B9Qw8mJE020~lAlCAMXYY~`@fT#(<#t4X7089xG z9qT~02VnLRqV^EX&XsJ7C)$G5+6f8U3y8xZq=SH{4Iq^Pq@x3QJb)Z8fgBGZ$GMW7 z@I)s7IZnLd5uz237Z7zIjtK(dNPt5HOnM^44!98t4xv!Wa4PCJ0TJ;*aCoA#fT#`g7~`IsHix*5#%h% zE_k9F)}gO2>6kQz>`tIqT0-qs(FZeh7ZCN}gggX9eLzheOlY#RjJ~ssiV%aRfH(^D zYkjf!Kb0ts36Q@!v5zJy#0M2Qkc?pQ4Azp6*(Ez|}0(c(>vLAr= zlfe5ycwblYbUbl70Pz*!u!cDN1Vlp!?=K)40eCGiuK+1VQ7}ePeGt$eC?FbxA=-dM zkOMgckO+~G2!SMmUCA@>#2El zg)nD=3hYHJ@x*WekqSma!m|O!2p}%-Qy2VhG{P|)BQQ_zNp?hV0}EV|bN z*TJHD1Y8wG_i&vGpg}xpppig>cpx33=pMq!g9gXID|`;`WjvDDVjjXiT~U7|xMF{U zW~A%~Hwb8O{A|$`2m8J0d=&gPTf&6BaWW|sIvb@i>Cq7}bd;Y2Vm0<4MS+E;(dZHM z)CBIFIbf(4CkoOu0*wHgG))Bj7Sn-ifzMrB_=-b<2pdlT^O6T)l?S48JWkf$+}7L*c5xD5ycW+enodiK#X{~J z@KBD&N#aJ)<8d=Bf_MPbB9@EBp)8ANda?zYz~z~<=oYjj1~VG#5yof>EG>xO@uQgx znni^07f1`}F=!MYV30~*%mD=C!z5ZP1E@gr5?>r{x?WfwK0;{uHY3&m@$gmkKul9f$ z^>xM(&dK-oekV91MrzFyWbg65bX{ple{<|AvnussVblCK4o4Q&KKlOren(z9?|9+0 zmUW(-gZFbf_I+w|c#%4ZA9IkQbk$=!JHIJFZL2M7mfQ5Db^+0cUOc=OrpBZlFL)Eg z|J3mJ+Z|0^cTVOeHVTgGGj8fDCx!b&6nU1|yi)cFkKJ$g@M$P=&{JoRlXA)=z4aH9 z>(iZH>3zuej4fivS?Zs3YV4u@T|Fa%;c(u{+_t*7^h(+5tCL!G___$}2tW9Z47>IoMoT8f)Q!v-v2aGp zdEK44dFu40@23vy-6t4)D>KgTXgss;&=Xqm#O)e7>lT{)9V5Td$L{`<<))X9Jb5(y zo00naqi>4@i_hO!RsUsTS(A^k`S#TdZx%jYu6%Ou^m9C)hT3G?f3&7J`5n2AFMVit zcld&RlM6?s9`aES%)91r*Cf%-xWeUmt!zSslJ6>;7rW27hA)!sSsvnfV*Y4;y1T*C zN$HpJbk5r<*{k0BkyrCl>43IQ$rbk_!KID3U2)Adv8#gx(_E9=!XIC3^M7Al%{|~6 z{UGzLK(T0E;ECi39SH{~sx@U#pG7eJX#9Obv-v{vESK%&ANM+it2-L3*fN#lp|kJt ze4WpGQYM!KtL7*=AMThMbu4&D#V51dvx8PWx>Fgl&0>39?Ys@UO=lmQdgW3CwJDfz zCri+M`e5C5?|p~lXoHf}TAQ=d9(H(|KAQW!_4eII5A?Pq(q@Go_6j{56MFcD+Jrn; zx5Mx9?k;O~b(>(jWXq3Qmzw>fCh7^66@I@!d}q2va`k&K55x+^L$xlmM?2-xFW8Ps{$nmJf5wY%9>A<&F6Mo|D^W`$> zTX)9Hw7M}N&K4=0lllDWv7J+zzZ=i|w0vDB?(8;#!SW%#2X&kez6l@(9{pNe;P!Sx zi1x!Bmhm6VKCY@9(i-x}G|@7Ati?v}I8urwDWw4X-}%){vPL}7Xp^~#vLJLDi+n*)PJh*P5C>65ts0{AO70H;Z5v? zm*#$L^0;%nH7)yHjMq@V*gd7!3@H0k{TlqdH{Yn*oXM`(_#pCXx}n*Ldqz%l)vRIq z6e^W+LNmi&P6nO8+@NrNu)tn!6Z^tBtIE@QDvTh5M$~#88j^1{Gk=@)y2?wFnshcv!~vVJ?h*EILu+G0*5!1>e3+K;#fLU(@^4oNy6Vq--MhACq`@dd&8{tD?xn9+xH!dl zRL1u;zWR3$+xl3s3a#(k*BhPNQWo_gC@<=ITKbl)ijJJTeWwUG~eH9>6ok?GFU0Op@R}{)>(eo zTe+eBK!KO-tZ6NASKrfT(ZUmd(oNNN+ip!cM(fSD=^>wooZZp5<((zpIP#MnSlQ_2 z`}tZY9S1ilX1((OsujPdwAowY3< zRlXlP#OSk5*UZ^+=$+yO&GeGQHMU1iW)n_5?J~UT{r+<6y>GjYY8|o7Dl3@1-e6^c z$s&zL8{?S$8U@GnVhXN*Qef|^dC6Byp8YMykv(6DRxVma3i(RiBiCOu^5?B$(hU8(!e;t0?0Lo02V`<1Km{EoXf{`uadB_-R*OIOn7 z=yX~Sy;^Oeh)`0_U!WRzRd4< zB;Rr9`wrUEQ}~{*i^dRse5!AyeD2v<*Hdcwd17R7_vy?wf-bH21WV^2>ZsF-FQ`UUSMSIVX|EWHF0LsY;q<}$ z@{B$FP>;2Xa|ws}FP~&p{q5VhegDIfd)AvgpK;&ZymDSw){UyYu1lS8;u@*L?6gb9 z3zNl#viv8$TF*j04Y^tCtGoCc>zT|K_4n_>&eidhbeC4)Ewn(lAta_m> zg=1in#yDF)@A7_)oT!=Cr~kgKF9>JKSNM``+CAiCMMk3BJ~ji!r_Z6GcUt11O?OZoQYg)Cz5fr3~Vj z-k$wxk&-4-Ry){zghX|;4}W7q%GCY{TZP?4_57~^8S0$ znTCwOyQX@wVLPk5yW=-D+eMA>@eV1xt$igRwc%i8r`eLj)c5hjulmyzAI)3xeRW&0 z>fFosXEmHVc3` zjmA!B59)rl#QODxt-AUXx9q(#IiHnVc(B_=!(&G@rzUdDP)f0W@HjVLrvCDe%uR7V zrbY%+hj)I+p}k>S2UM(Y8)vo3Wrw_*w)NaKvd|rMDF= zy+!@LDO=YnJZW+A?G^sVUk>62Q8wHSzO?$rB}d)nwPka3r_*Kyzb@aihE!{j%ZFd$qyx-mN{z zaxHT*nR^Dm4>flCu~A{;8KozLmaWK|jW=2e?1imMS}(F`Tb~70KRN&Mwdqqg>uKHZ zbS+puADv`N?-ea>x*}K4IPS7-S@#8d4eCB#j^)TRj|CR1+ESNYe?NHh6U_y7PrU9b zacdq&+1_4rHL9@j8}Iu1sJz-dW1WSxb8Zuxr}RuFc(^WGcdRC}*kqFHvdUS*Kh7)7 zu{vuR(`Y!}bPMiyReSbLdy~4>aq-$`)^&|-NVH)@tYO`_$qKo(T-AT%#?vvo*0Sd5 zdZUS(9LAAX+0jpxXBNtm{vK(mdugVR=e5NRJXfyTMAaddSBMuK^hQ0?(Ho^dZp!44 z^{Xvit!ZD4$VJa)CU1$&{Ab+9B(1+J-gSpZemrq{)dkrvKRj|eNSj*?YZlG>u!?x$ z(Nxv7sE4yhXVdQPo}Ns<)qX#m=R8!kzNfSFB`df6W(7}U2l~v?LjbNn9I~tL05iJa zknPtNxwT6DTGvg+wcYdcdAGLuRh_)%|2be>^WGGzGtWv}T0RF@>Ca=2i+SU{`sT@t zl@%v1S{3|rRb~*qXiV*R2e~qh@$!Wk?H6nFr{)~c zoYT^HU60W-g0keF(5^$CM_x~!d2{~oh~@X}6P#X$-(&gF6CPLB3Yxo;vl}YsS(z7o zbeMm#oHf9a3<*=Rry3zT0_=oIY=C+<5S9)!3xTfy1ef&g^iCxs*~jwRTBs+^%_(eadHb zPdS&8>Ywdmz3p{M%dl3bHcDlcMe9Ve+p|y6GVi~;8BkKX@n6iHoFCD_ZQ^e7M#^jA zcY>2^&uK5c1;m*-El)nyoNr58v(>Z3CRl${d5`DA13xY-_}gIo$Ep>R1i^2PK4|#VMZ@^D@4uo)G5FUp`=f^SF zv7jI2BcRlT@RFjU==5lW!$sH}zPSPtIXylSVbM`G4`J|;6qF|%!sEpxF-?(3cX*EU z(*OV{HOL&BR*E8rpAZ2S5&`N@aRd~Pf-@CZhf;}?jU%KG!C6ccEGnf)ALpPlaD)t~ zDh&eXJ)owf#^Xi_%Rv^xRhVP7Auxc*4krW1G62?36dI9rLF(YYdNEA3if^0;QSVl6P zjfhvHfNw&IY33 z#sc~9IpACiAVnB#J_k?{i`85~0htnmQ4-0S0ifAJF>+B11PB{+h$IJkB-2H}SSUQW z96$qQ13Gblum}^6kERJ#h=;Q1kWyeAfDkVhLMQR)KrfIOpgvJ?D1(jZmUyaB99BXS zACnS9Bht7Sl)+RG(&DBG#{+`caUK%G<*<+h4v)tGrBMVsoaBjCn8ry$qB+=f*-&9o zptn4LmV>PwQ06mGrVvCZOH(*GBvQB*bJ3w>B*dn#kGQ9ztOO=FR|E0n}A5`4^#$6B!+DiK}FILjEP2ia1EGH#532UBJ-&Vh=m1WHbIC7L)-_w5cW3| zu=PSJU?SK(VuFC-eGpp%DqzNci1ZpNv>^N{izE)PBpP?RTi~#8zaw zykE=~mopi&IuwBi%h0ij%*GVl2rY}lW~O0^Aw&hNhR28o+5nu}?=(O}I26+aQ?ayB zJ*p{`i48SeBI8giQ^Y2GK!)@^#Qt-?wpp4l+I>#OC7unF*RM<}^%tI}V{8zrlgP1& z-Og`Jp)Vz&MpywZ_%N6f76^NVJwK~tUw9EarGc@o0of;h7vRqsw@jLGYNF{#ST+N` zRPZayHcPV%(*VL7nWs}kG7;Gi9`2NhU_vMK{w>+jaqm(6YV+?3~_|^Yv zd?=EDGPqJPFowYec1mZ`Ss*EaVMA!SAXB{3;WAKao7;G$o`iTvIO&~U-2oHpK5X(hj7)w^5 z$VI}0;=;IzL4&MEn79D`LaB(dBvCdK$6-ce`2t|Rn3zzoAZ-OX5Xw#yqlG#qmGJc9 z!m=NsHo`>qcd~*D7fT7)w6rw9Pw4-xMIz`EjHSUu0;TIoNwT+ZK=Fy+p!##~=PE5i zHBs(keF*fO+Ru*$R5|e8-k)omuC%tP7;?CV|E6lw z{%2JaI|Ha_qIiHQ=kF|-!xaZ(%zh<_3#JwrEBXk&clgh2`wx(PKrku)LbE^N0-C=< z_UQovm5~4W!GPkFekJqI1A$B*xk|m|DGCU`xDZ@}dn%s`-{HV~I)lvy;Z*2Du$`Sa zi!w)CVHk$86h4JJPdaqS2rCI>3N#R1W3c@%0(YJWKP>^KWA0P9gnwu9^S(@mrLcZEEDC($Y(&iD-pWY7e8zb9?}1A+S3?T+UoQ8mW1jhs@lE;(N=PO2A~<65aKHbjq0t%{lzy&ctFc8`hwjGd|2v!eFV}N=q+ztvo zlBuvR*eh)4tgtbl*e2RRAVydb64tKuMB92j%&B3@1NUy&WJC%;6(*bz4}%Sgkz$u8 ze2hpJNJUF9#gIv+39{b46;feXl5GCOju?y+PMaPLed#ZSQaA&8ViE(e0`7sq##dZJ zjs)K{M1l$`lgUW|%LJ^86n%jKa%~V8ft$vr{o7J23&actC}>KGvp*GFf9KzUpv8F- z@E56~R5|rO79abE);9t>R8u6C`cuL!>c_(K&o!gIn54_C)8l{;`sCaqTNFL`HNrz& z!ZEP$f_c#a7uGv&z^EktCg#s_DHK>_uQ?ADNmpcBzef5NZ&>n&RslBFe4rAM{+Lxo z{2F%2z@(SU&{*pesuPS;&ziZCknvxdqL0s zS3$$H<9|Eh>sQKBr)<)J1q)37UxGFgiuk_@WB}ocu>5a|@|(i6KkeY_3c3K6ad13 Spv(X+3ZM}{!w>Dj;rg3g^)ro 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 anb1DEA5TF^=aVZ2PvS@UB>$lc>;D07K?BAB literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@string.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@string.beam new file mode 100644 index 0000000000000000000000000000000000000000..a3b2166759c4cd116d98d983ab01f0bf9232b9ac GIT binary patch literal 27668 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 Ee_Nh;PXGV_ literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam@uri.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam@uri.beam new file mode 100644 index 0000000000000000000000000000000000000000..d1d64b4d4ae590f004be1b0825c91f81fdea8c71 GIT binary patch literal 26276 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.app b/build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.app new file mode 100644 index 0000000..e3d9b17 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.app @@ -0,0 +1,7 @@ +{application, gleam_stdlib, [ + {vsn, "0.62.0"}, + {applications, []}, + {description, "A standard library for the Gleam programming language"}, + {modules, []}, + {registered, []} +]}. diff --git a/build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.beam b/build/dev/erlang/gleam_stdlib/ebin/gleam_stdlib.beam new file mode 100644 index 0000000000000000000000000000000000000000..37a4d917c13ab0ad9cabc1de6b0684369311f5f4 GIT binary patch literal 27116 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 qKrqBzUN^^%-)>;mm=w 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 V5A@&2?;x1}aTM|o2PQ+X{s*jJq7VQ8 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl b/build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl new file mode 100644 index 0000000..b1135f2 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl @@ -0,0 +1,5 @@ +-record(decode_error, { + expected :: binary(), + found :: binary(), + path :: list(binary()) +}). diff --git a/build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl b/build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl new file mode 100644 index 0000000..a2fcfc6 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl @@ -0,0 +1,4 @@ +-record(decoder, { + function :: fun((gleam@dynamic:dynamic_()) -> {any(), + list(gleam@dynamic@decode:decode_error())}) +}). diff --git a/build/dev/erlang/gleam_stdlib/include/gleam@set_Set.hrl b/build/dev/erlang/gleam_stdlib/include/gleam@set_Set.hrl new file mode 100644 index 0000000..51fb778 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/include/gleam@set_Set.hrl @@ -0,0 +1 @@ +-record(set, {dict :: gleam@dict:dict(any(), list(nil))}). diff --git a/build/dev/erlang/gleam_stdlib/include/gleam@uri_Uri.hrl b/build/dev/erlang/gleam_stdlib/include/gleam@uri_Uri.hrl new file mode 100644 index 0000000..50150f4 --- /dev/null +++ b/build/dev/erlang/gleam_stdlib/include/gleam@uri_Uri.hrl @@ -0,0 +1,9 @@ +-record(uri, { + scheme :: gleam@option:option(binary()), + userinfo :: gleam@option:option(binary()), + host :: gleam@option:option(binary()), + port :: gleam@option:option(integer()), + path :: binary(), + 'query' :: gleam@option:option(binary()), + fragment :: gleam@option:option(binary()) +}). diff --git a/build/dev/erlang/gleam_version b/build/dev/erlang/gleam_version new file mode 100644 index 0000000..b0f61c5 --- /dev/null +++ b/build/dev/erlang/gleam_version @@ -0,0 +1 @@ +1.11.1 \ No newline at end of file diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.cache b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.cache new file mode 100644 index 0000000000000000000000000000000000000000..a5a9a0a0628d214a5b01a4936170ae94a1cd8f3c GIT binary patch literal 7752 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.cache_meta b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..ebeff6ea709194e04d7363a1ec4cac928b691486 GIT binary patch literal 455 zcmZY5u}cDB7{~F)v=gL7hnyk^3z`JUprRq1tSN=0QS$B-P6zLzA_yW7@q);yMr}>( zKgb~{{Tmuv9V8u$hQ62A5dPr9`|x{shxff(&F008$LkIO_tXtFTZ|e7({hR+=KgKU zs(EZ!A-d(MooST|C4Gf{1JTjmy1jIMxzGF;=bp3Q#1^jcf;WUcA}Ji8f*KlVp^Ybe z;0wtakzE|3j%R#hp67%S!w%BOAO{UPY&7wJcPKuQ5EhVt3JoSMaF0iH(Z>Lv7$Pz& tVxWiw+@g*S6h*|3MZ~a%IMO(R3Jqttf{j;n(Zd+q{t3S7H$Pv?I= 27). +-define(MODULEDOC(Str), -moduledoc(Str)). +-define(DOC(Str), -doc(Str)). +-else. +-define(MODULEDOC(Str), -compile([])). +-define(DOC(Str), -compile([])). +-endif. + +-type atom_() :: any(). + +-type encoding() :: utf8. + +-type report_module_name() :: gleeunit_progress. + +-type gleeunit_progress_option() :: {colored, boolean()}. + +-type eunit_option() :: verbose | + no_tty | + {report, {report_module_name(), list(gleeunit_progress_option())}}. + +-file("src/gleeunit.gleam", 37). +-spec gleam_to_erlang_module_name(binary()) -> binary(). +gleam_to_erlang_module_name(Path) -> + case gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) of + true -> + _pipe = Path, + _pipe@1 = gleam@string:replace( + _pipe, + <<".gleam"/utf8>>, + <<""/utf8>> + ), + gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"@"/utf8>>); + + false -> + _pipe@2 = Path, + _pipe@3 = gleam@string:split(_pipe@2, <<"/"/utf8>>), + _pipe@4 = gleam@list:last(_pipe@3), + _pipe@5 = gleam@result:unwrap(_pipe@4, Path), + gleam@string:replace(_pipe@5, <<".erl"/utf8>>, <<""/utf8>>) + end. + +-file("src/gleeunit.gleam", 18). +-spec do_main() -> nil. +do_main() -> + Options = [verbose, + no_tty, + {report, {gleeunit_progress, [{colored, true}]}}], + Result = begin + _pipe = gleeunit_ffi:find_files( + <<"**/*.{erl,gleam}"/utf8>>, + <<"test"/utf8>> + ), + _pipe@1 = gleam@list:map(_pipe, fun gleam_to_erlang_module_name/1), + _pipe@2 = gleam@list:map( + _pipe@1, + fun(_capture) -> erlang:binary_to_atom(_capture, utf8) end + ), + gleeunit_ffi:run_eunit(_pipe@2, Options) + end, + Code = case Result of + {ok, _} -> + 0; + + {error, _} -> + 1 + end, + erlang:halt(Code). + +-file("src/gleeunit.gleam", 13). +?DOC( + " Find and run all test functions for the current project using Erlang's EUnit\n" + " test framework, or a custom JavaScript test runner.\n" + "\n" + " Any Erlang or Gleam function in the `test` directory with a name ending in\n" + " `_test` is considered a test function and will be run.\n" + "\n" + " A test that panics is considered a failure.\n" +). +-spec main() -> nil. +main() -> + do_main(). diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.erl b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.erl new file mode 100644 index 0000000..d78f5e5 --- /dev/null +++ b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.erl @@ -0,0 +1,49 @@ +-module(gleeunit_gleam_panic_ffi). +-export([from_dynamic/1]). + +from_dynamic(#{ + gleam_error := assert, + start := Start, + 'end' := End, + expression_start := EStart +} = E) -> + wrap(E, {assert, Start, End, EStart, assert_kind(E)}); +from_dynamic(#{ + gleam_error := let_assert, + start := Start, + 'end' := End, + pattern_start := PStart, + pattern_end := PEnd, + value := Value +} = E) -> + wrap(E, {let_assert, Start, End, PStart, PEnd, Value}); +from_dynamic(#{gleam_error := panic} = E) -> + wrap(E, panic); +from_dynamic(#{gleam_error := todo} = E) -> + wrap(E, todo); +from_dynamic(_) -> + {error, nil}. + +assert_kind(#{kind := binary_operator, left := L, right := R, operator := O}) -> + {binary_operator, atom_to_binary(O), expression(L), expression(R)}; +assert_kind(#{kind := function_call, arguments := Arguments}) -> + {function_call, lists:map(fun expression/1, Arguments)}; +assert_kind(#{kind := expression, expression := Expression}) -> + {other_expression, expression(Expression)}. + +expression(#{start := S, 'end' := E, kind := literal, value := Value}) -> + {asserted_expression, S, E, {literal, Value}}; +expression(#{start := S, 'end' := E, kind := expression, value := Value}) -> + {asserted_expression, S, E, {expression, Value}}; +expression(#{start := S, 'end' := E, kind := unevaluated}) -> + {asserted_expression, S, E, unevaluated}. + +wrap(#{ + gleam_error := _, + file := File, + message := Message, + module := Module, + function := Function, + line := Line +}, Kind) -> + {ok, {gleam_panic, Message, File, Module, Function, Line, Kind}}. diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs new file mode 100644 index 0000000..cef7646 --- /dev/null +++ b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs @@ -0,0 +1,91 @@ +import { Ok, Error, Empty, NonEmpty } from "../../gleam.mjs"; +import { + GleamPanic, + Todo, + Panic, + LetAssert, + Assert, + BinaryOperator, + FunctionCall, + OtherExpression, + AssertedExpression, + Literal, + Expression, + Unevaluated, +} from "./gleam_panic.mjs"; + +export function from_dynamic(error) { + if (!(error instanceof globalThis.Error) || !error.gleam_error) { + return new Error(undefined); + } + + if (error.gleam_error === "todo") { + return wrap(error, new Todo()); + } + + if (error.gleam_error === "panic") { + return wrap(error, new Panic()); + } + + if (error.gleam_error === "let_assert") { + let kind = new LetAssert( + error.start, + error.end, + error.pattern_start, + error.pattern_end, + error.value, + ); + return wrap(error, kind); + } + + if (error.gleam_error === "assert") { + let kind = new Assert( + error.start, + error.end, + error.expression_start, + assert_kind(error), + ); + return wrap(error, kind); + } + + return new Error(undefined); +} + +function assert_kind(error) { + if (error.kind == "binary_operator") { + return new BinaryOperator( + error.operator, + expression(error.left), + expression(error.right), + ); + } + + if (error.kind == "function_call") { + let list = new Empty(); + let i = error.arguments.length; + while (i--) { + list = new NonEmpty(expression(error.arguments[i]), list); + } + return new FunctionCall(list); + } + + return new OtherExpression(expression(error.expression)); +} + +function expression(data) { + const expression = new AssertedExpression(data.start, data.end, undefined); + if (data.kind == "literal") { + expression.kind = new Literal(data.value); + } else if (data.kind == "expression") { + expression.kind = new Expression(data.value); + } else { + expression.kind = new Unevaluated(); + } + return expression; +} + +function wrap(e, kind) { + return new Ok( + new GleamPanic(e.message, e.file, e.module, e.function, e.line, kind), + ); +} diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache new file mode 100644 index 0000000000000000000000000000000000000000..091a0c419c10a2d651f7b668ab9c48874ec271da GIT binary patch literal 13578 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 27). +-define(MODULEDOC(Str), -moduledoc(Str)). +-define(DOC(Str), -doc(Str)). +-else. +-define(MODULEDOC(Str), -compile([])). +-define(DOC(Str), -compile([])). +-endif. + +?MODULEDOC(false). + +-type gleam_panic() :: {gleam_panic, + binary(), + binary(), + binary(), + binary(), + integer(), + panic_kind()}. + +-type panic_kind() :: todo | + panic | + {let_assert, + integer(), + integer(), + integer(), + integer(), + gleam@dynamic:dynamic_()} | + {assert, integer(), integer(), integer(), assert_kind()}. + +-type assert_kind() :: {binary_operator, + binary(), + asserted_expression(), + asserted_expression()} | + {function_call, list(asserted_expression())} | + {other_expression, asserted_expression()}. + +-type asserted_expression() :: {asserted_expression, + integer(), + integer(), + expression_kind()}. + +-type expression_kind() :: {literal, gleam@dynamic:dynamic_()} | + {expression, gleam@dynamic:dynamic_()} | + unevaluated. + +-file("src/gleeunit/internal/gleam_panic.gleam", 49). +?DOC(false). +-spec from_dynamic(gleam@dynamic:dynamic_()) -> {ok, gleam_panic()} | + {error, nil}. +from_dynamic(Data) -> + gleeunit_gleam_panic_ffi:from_dynamic(Data). diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache new file mode 100644 index 0000000000000000000000000000000000000000..106c0fca6ea3257538d475e42342b49373243f06 GIT binary patch literal 12966 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.erl b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.erl new file mode 100644 index 0000000..8b90c8c --- /dev/null +++ b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.erl @@ -0,0 +1,331 @@ +-module(gleeunit@internal@reporting). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleeunit/internal/reporting.gleam"). +-export([new_state/0, test_skipped/3, test_passed/1, finished/1, test_failed/4]). +-export_type([state/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(false). + +-type state() :: {state, integer(), integer(), integer()}. + +-file("src/gleeunit/internal/reporting.gleam", 15). +?DOC(false). +-spec new_state() -> state(). +new_state() -> + {state, 0, 0, 0}. + +-file("src/gleeunit/internal/reporting.gleam", 194). +?DOC(false). +-spec bold(binary()) -> binary(). +bold(Text) -> + <<<<"\x{001b}[1m"/utf8, Text/binary>>/binary, "\x{001b}[22m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 198). +?DOC(false). +-spec cyan(binary()) -> binary(). +cyan(Text) -> + <<<<"\x{001b}[36m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 178). +?DOC(false). +-spec code_snippet(gleam@option:option(bitstring()), integer(), integer()) -> binary(). +code_snippet(Src, Start, End) -> + _pipe = begin + gleam@result:'try'( + gleam@option:to_result(Src, nil), + fun(Src@1) -> + gleam@result:'try'( + gleam_stdlib:bit_array_slice(Src@1, Start, End - Start), + fun(Snippet) -> + gleam@result:'try'( + gleam@bit_array:to_string(Snippet), + fun(Snippet@1) -> + Snippet@2 = <<<<<<(cyan(<<" code"/utf8>>))/binary, + ": "/utf8>>/binary, + Snippet@1/binary>>/binary, + "\n"/utf8>>, + {ok, Snippet@2} + end + ) + end + ) + end + ) + end, + gleam@result:unwrap(_pipe, <<""/utf8>>). + +-file("src/gleeunit/internal/reporting.gleam", 202). +?DOC(false). +-spec yellow(binary()) -> binary(). +yellow(Text) -> + <<<<"\x{001b}[33m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 189). +?DOC(false). +-spec test_skipped(state(), binary(), binary()) -> state(). +test_skipped(State, Module, Function) -> + gleam_stdlib:print( + <<<<<<<<"\n"/utf8, Module/binary>>/binary, "."/utf8>>/binary, + Function/binary>>/binary, + (yellow(<<" skipped"/utf8>>))/binary>> + ), + _record = State, + {state, + erlang:element(2, _record), + erlang:element(3, _record), + erlang:element(4, State) + 1}. + +-file("src/gleeunit/internal/reporting.gleam", 206). +?DOC(false). +-spec green(binary()) -> binary(). +green(Text) -> + <<<<"\x{001b}[32m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 64). +?DOC(false). +-spec test_passed(state()) -> state(). +test_passed(State) -> + gleam_stdlib:print(green(<<"."/utf8>>)), + _record = State, + {state, + erlang:element(2, State) + 1, + erlang:element(3, _record), + erlang:element(4, _record)}. + +-file("src/gleeunit/internal/reporting.gleam", 210). +?DOC(false). +-spec red(binary()) -> binary(). +red(Text) -> + <<<<"\x{001b}[31m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 19). +?DOC(false). +-spec finished(state()) -> integer(). +finished(State) -> + case State of + {state, 0, 0, 0} -> + gleam_stdlib:println(<<"\nNo tests found!"/utf8>>), + 1; + + {state, _, 0, 0} -> + Message = <<<<"\n"/utf8, + (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, + " tests, no failures"/utf8>>, + gleam_stdlib:println(green(Message)), + 0; + + {state, _, _, 0} -> + Message@1 = <<<<<<<<"\n"/utf8, + (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, + " tests, "/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, + " failures"/utf8>>, + gleam_stdlib:println(red(Message@1)), + 0; + + {state, _, 0, _} -> + Message@2 = <<<<<<<<"\n"/utf8, + (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, + " tests, 0 failures, "/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(4, State)))/binary>>/binary, + " skipped"/utf8>>, + gleam_stdlib:println(yellow(Message@2)), + 1; + + {state, _, _, _} -> + Message@3 = <<<<<<<<<<"\n"/utf8, + (erlang:integer_to_binary( + erlang:element(2, State) + ))/binary>>/binary, + " tests, "/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, + " failures, "/utf8>>/binary, + " skipped"/utf8>>, + gleam_stdlib:println(red(Message@3)), + 1 + end. + +-file("src/gleeunit/internal/reporting.gleam", 214). +?DOC(false). +-spec grey(binary()) -> binary(). +grey(Text) -> + <<<<"\x{001b}[90m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 87). +?DOC(false). +-spec format_unknown(binary(), binary(), gleam@dynamic:dynamic_()) -> binary(). +format_unknown(Module, Function, Error) -> + erlang:list_to_binary( + [<<(grey(<<<>/binary, Function/binary>>))/binary, + "\n"/utf8>>, + <<"An unexpected error occurred:\n"/utf8>>, + <<"\n"/utf8>>, + <<<<" "/utf8, (gleam@string:inspect(Error))/binary>>/binary, + "\n"/utf8>>] + ). + +-file("src/gleeunit/internal/reporting.gleam", 170). +?DOC(false). +-spec inspect_value(gleeunit@internal@gleam_panic:asserted_expression()) -> binary(). +inspect_value(Value) -> + case erlang:element(4, Value) of + unevaluated -> + grey(<<"unevaluated"/utf8>>); + + {literal, _} -> + grey(<<"literal"/utf8>>); + + {expression, Value@1} -> + gleam@string:inspect(Value@1) + end. + +-file("src/gleeunit/internal/reporting.gleam", 166). +?DOC(false). +-spec assert_value( + binary(), + gleeunit@internal@gleam_panic:asserted_expression() +) -> binary(). +assert_value(Name, Value) -> + <<<<<<(cyan(Name))/binary, ": "/utf8>>/binary, + (inspect_value(Value))/binary>>/binary, + "\n"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 147). +?DOC(false). +-spec assert_info(gleeunit@internal@gleam_panic:assert_kind()) -> binary(). +assert_info(Kind) -> + case Kind of + {binary_operator, _, Left, Right} -> + erlang:list_to_binary( + [assert_value(<<" left"/utf8>>, Left), + assert_value(<<"right"/utf8>>, Right)] + ); + + {function_call, Arguments} -> + _pipe = Arguments, + _pipe@1 = gleam@list:index_map( + _pipe, + fun(E, I) -> + Number = gleam@string:pad_start( + erlang:integer_to_binary(I), + 5, + <<" "/utf8>> + ), + assert_value(Number, E) + end + ), + erlang:list_to_binary(_pipe@1); + + {other_expression, _} -> + <<""/utf8>> + end. + +-file("src/gleeunit/internal/reporting.gleam", 100). +?DOC(false). +-spec format_gleam_error( + gleeunit@internal@gleam_panic:gleam_panic(), + binary(), + binary(), + gleam@option:option(bitstring()) +) -> binary(). +format_gleam_error(Error, Module, Function, Src) -> + Location = grey( + <<<<(erlang:element(3, Error))/binary, ":"/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(6, Error)))/binary>> + ), + case erlang:element(7, Error) of + panic -> + erlang:list_to_binary( + [<<<<<<(bold(red(<<"panic"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ); + + todo -> + erlang:list_to_binary( + [<<<<<<(bold(yellow(<<"todo"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ); + + {assert, Start, End, _, Kind} -> + erlang:list_to_binary( + [<<<<<<(bold(red(<<"assert"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + code_snippet(Src, Start, End), + assert_info(Kind), + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ); + + {let_assert, Start@1, End@1, _, _, Value} -> + erlang:list_to_binary( + [<<<<<<(bold(red(<<"let assert"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + code_snippet(Src, Start@1, End@1), + <<<<<<(cyan(<<"value"/utf8>>))/binary, ": "/utf8>>/binary, + (gleam@string:inspect(Value))/binary>>/binary, + "\n"/utf8>>, + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ) + end. + +-file("src/gleeunit/internal/reporting.gleam", 69). +?DOC(false). +-spec test_failed(state(), binary(), binary(), gleam@dynamic:dynamic_()) -> state(). +test_failed(State, Module, Function, Error) -> + Message = case gleeunit_gleam_panic_ffi:from_dynamic(Error) of + {ok, Error@1} -> + Src = gleam@option:from_result( + file:read_file(erlang:element(3, Error@1)) + ), + format_gleam_error(Error@1, Module, Function, Src); + + {error, _} -> + format_unknown(Module, Function, Error) + end, + gleam_stdlib:print(<<"\n"/utf8, Message/binary>>), + _record = State, + {state, + erlang:element(2, _record), + erlang:element(3, State) + 1, + erlang:element(4, _record)}. diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.cache b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.cache new file mode 100644 index 0000000000000000000000000000000000000000..02ff42a2435e643dee003d6ba3eefe6f50e43cda GIT binary patch literal 3713 zcmcgvYiL}@6~5=pjCWVEBAtv}Iij{!BCgUc_EtN!Ws4eVcV*+MZsIFBG>-=7T6-<8 zyxNubQ8y+bSb>HHT1aSIT>QsPpiP=UQVMlnlos+Q(Bc$QYTEQ^N}E(a5}FW0f^+8H zU3o2OW&H^KF>~h5&dmAdoAcU!knq?c*yuR4eSy3PdEe1jV-eamq2G-SPj$Bg4)q^J z{Zc#X*V`ld<@Q^$m)ga(nS$@viuo!gE5}Q*c0x!WqX0fxo=~#EyeEb zJl74)cv?bVlvHQCQko0des&eMbIojz5Y1BmsO`I9^sf18zErdd*pN%}PUrQ{BbBPt znJeUvG9mm@_IYhv7vUC8OVl-SR>0Oi|76Vz&Gq~W%%|J~0p_UH%N8tye#6?9%S)+0 zwT3B#DqG>A)8`l!n?dPBU;r0apc-|*wv0*kqEn$4jZXTNTA|ukcO*ANjsbEJ^gIr@ zTN7cRz7;~V3-3WT)nci7#IonW`uLN9e(9`-zsa?1vPp4EjECVAgzn^*%cXL|ojwjW zRdA0DjXq%WWFh)tAIA(b52lw1R^a3#RjM&LaHsCAHyI7+XcgRK~&JDgiRLI zMw^1HL2aFfIk-E{820TCL*^LP?Vq>Bc$-$ySg^B~ZtJl-_ogV_Lwnl9T_+qTErZz4 zsfFD->Zrbbp{3j~A9IxWiW*V}k)Dop?V@3y9y(3uU!Y&SLRa1~9q?%|zc0;m@_A`4$;;BbDgP_YqU=^?i%Kdpq*BU! zLEUEocVQPN+#z@huEn`bh*yvMD*m8X;fkU9VElyt(5X^67ta?fRo~0SOUHOYz7n4+ z!&JTX=$$+c+n~N17xcY2p&!5=J%_XUBqq2G z>L+>rX`IyOc>XyazsP%D#9{pg%Qvu>TaRAk`M3G|Z61S|)k-9|4H5$N0wsX%11bYO z0rWGV-vj*v^sNATfLjV+$)J~NE_OCH%=1-b*)?%A;a^moTGKZRfM`}y7D%%aCR{RzIWkoOcTh%|rA6aowOj*@$ ziFd46kl&Dffx%d3wgF&sKt)r}c6IUR%*a_d2P_WBsrru43zw({6BQjIJS=qc<>Z37 zLv80EY^Kyb0l7C8%={+xf@#XB1@}Jg12GpPmZ_6=i>0B_gSU~%z!R4->%eO0CUnb06 z%mmAtT($E~j?ybHcJBkM?SMQe2^Ll!OppjFY=WL85W?(HdsU0&6Sh)pWVsu6{Sp6$ zEp}xZ3Gc=oy|SNSr9vJo6dULXhF2#L=%pX?UB1P^j>Q%EZ{9nT?h>?pmWD=XXqdbd zc?t3c=}d~wjL?}ux{#s^19V}=-n@ycdLg>H9whh6tl)9+O~GQD{7l_qgG9BQU@*Uy zuh<7wDpr5cdTv^|az7sA>e5`nH!-|&;5F+D2<%5^*@H~g);nN~O}b!SwSOkS+@iQJ K2b1N0LmvTBL-VQt literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.cache_meta b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit@should.cache_meta new file mode 100644 index 0000000000000000000000000000000000000000..dc1e870ae033d4acea02c709ccab91bcfe9da645 GIT binary patch literal 397 zcmY+tPNFR?sdz1}7nV2D<;`lT98H?7@PBWsS}8@v zg82@EM~98!{h804{+Eo>y4yOlON~=5x#pf1zUWGXFhZ7D=9ni>jRQ`ob4!yqIz4=d zG~-N=VUbn#c;JyHPkfVX4`G0a3RSi_roj!VWC-2#(91Mg^3*xwoC}&f^U6CP^mT;L QPnuE2$g#ju%-4VO1A65%eE= 27). +-define(MODULEDOC(Str), -moduledoc(Str)). +-define(DOC(Str), -doc(Str)). +-else. +-define(MODULEDOC(Str), -compile([])). +-define(DOC(Str), -compile([])). +-endif. + +?MODULEDOC(" Use the `assert` keyword instead of this module.\n"). + +-file("src/gleeunit/should.gleam", 6). +-spec equal(DRQ, DRQ) -> nil. +equal(A, B) -> + case A =:= B of + true -> + nil; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould equal\n"/utf8>>, + gleam@string:inspect(B)] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"equal"/utf8>>, + line => 10}) + end. + +-file("src/gleeunit/should.gleam", 19). +-spec not_equal(DRR, DRR) -> nil. +not_equal(A, B) -> + case A /= B of + true -> + nil; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould not equal\n"/utf8>>, + gleam@string:inspect(B)] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"not_equal"/utf8>>, + line => 23}) + end. + +-file("src/gleeunit/should.gleam", 32). +-spec be_ok({ok, DRS} | {error, any()}) -> DRS. +be_ok(A) -> + case A of + {ok, Value} -> + Value; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be ok"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_ok"/utf8>>, + line => 35}) + end. + +-file("src/gleeunit/should.gleam", 39). +-spec be_error({ok, any()} | {error, DRX}) -> DRX. +be_error(A) -> + case A of + {error, Error} -> + Error; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be error"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_error"/utf8>>, + line => 42}) + end. + +-file("src/gleeunit/should.gleam", 46). +-spec be_some(gleam@option:option(DSA)) -> DSA. +be_some(A) -> + case A of + {some, Value} -> + Value; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be some"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_some"/utf8>>, + line => 49}) + end. + +-file("src/gleeunit/should.gleam", 53). +-spec be_none(gleam@option:option(any())) -> nil. +be_none(A) -> + case A of + none -> + nil; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be none"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_none"/utf8>>, + line => 56}) + end. + +-file("src/gleeunit/should.gleam", 60). +-spec be_true(boolean()) -> nil. +be_true(Actual) -> + _pipe = Actual, + equal(_pipe, true). + +-file("src/gleeunit/should.gleam", 65). +-spec be_false(boolean()) -> nil. +be_false(Actual) -> + _pipe = Actual, + equal(_pipe, false). + +-file("src/gleeunit/should.gleam", 70). +-spec fail() -> nil. +fail() -> + be_true(false). diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.erl b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.erl new file mode 100644 index 0000000..29b9553 --- /dev/null +++ b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.erl @@ -0,0 +1,14 @@ +-module(gleeunit_ffi). + +-export([find_files/2, run_eunit/2]). + +find_files(Pattern, In) -> + Results = filelib:wildcard(binary_to_list(Pattern), binary_to_list(In)), + lists:map(fun list_to_binary/1, Results). + +run_eunit(Tests, Options) -> + case eunit:test({timeout, 60, Tests}, Options) of + ok -> {ok, nil}; + error -> {error, nil}; + {error, Term} -> {error, Term} + end. diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.mjs b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.mjs new file mode 100644 index 0000000..ea7e301 --- /dev/null +++ b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_ffi.mjs @@ -0,0 +1,100 @@ +import { readFileSync } from "node:fs"; +import { Ok, Error as GleamError } from "./gleam.mjs"; +import * as reporting from "./gleeunit/internal/reporting.mjs"; + +export function read_file(path) { + try { + return new Ok(readFileSync(path)); + } catch { + return new GleamError(undefined); + } +} + +async function* gleamFiles(directory) { + for (let entry of await read_dir(directory)) { + let path = join_path(directory, entry); + if (path.endsWith(".gleam")) { + yield path; + } else { + try { + yield* gleamFiles(path); + } catch (error) { + // Could not read directory, assume it's a file + } + } + } +} + +async function readRootPackageName() { + let toml = await async_read_file("gleam.toml", "utf-8"); + for (let line of toml.split("\n")) { + let matches = line.match(/\s*name\s*=\s*"([a-z][a-z0-9_]*)"/); // Match regexp in compiler-cli/src/new.rs in validate_name() + if (matches) return matches[1]; + } + throw new Error("Could not determine package name from gleam.toml"); +} + +export async function main() { + let state = reporting.new_state(); + + let packageName = await readRootPackageName(); + let dist = `../${packageName}/`; + + for await (let path of await gleamFiles("test")) { + let js_path = path.slice("test/".length).replace(".gleam", ".mjs"); + let module = await import(join_path(dist, js_path)); + for (let fnName of Object.keys(module)) { + if (!fnName.endsWith("_test")) continue; + try { + await module[fnName](); + state = reporting.test_passed(state); + } catch (error) { + let moduleName = js_path.slice(0, -4); + state = reporting.test_failed(state, moduleName, fnName, error); + } + } + } + + const status = reporting.finished(state); + exit(status); +} + +export function crash(message) { + throw new Error(message); +} + +function exit(code) { + if (globalThis.Deno) { + Deno.exit(code); + } else { + process.exit(code); + } +} + +async function read_dir(path) { + if (globalThis.Deno) { + let items = []; + for await (let item of Deno.readDir(path, { withFileTypes: true })) { + items.push(item.name); + } + return items; + } else { + let { readdir } = await import("node:fs/promises"); + return readdir(path); + } +} + +function join_path(a, b) { + if (a.endsWith("/")) return a + b; + return a + "/" + b; +} + +async function async_read_file(path) { + if (globalThis.Deno) { + return Deno.readTextFile(path); + } else { + let { readFile } = await import("node:fs/promises"); + let contents = await readFile(path); + return contents.toString(); + } +} diff --git a/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_progress.erl b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_progress.erl new file mode 100644 index 0000000..2883008 --- /dev/null +++ b/build/dev/erlang/gleeunit/_gleam_artefacts/gleeunit_progress.erl @@ -0,0 +1,74 @@ +%% A formatter adapted from Sean Cribb's https://github.com/seancribbs/eunit_formatters + +-module(gleeunit_progress). +-behaviour(eunit_listener). +-define(NOTEST, true). +-include_lib("eunit/include/eunit.hrl"). + +%% eunit_listener callbacks +-export([ + init/1, handle_begin/3, handle_end/3, handle_cancel/3, terminate/2, + start/0, start/1 +]). + +-define(reporting, gleeunit@internal@reporting). + +start() -> + start([]). + +start(Options) -> + eunit_listener:start(?MODULE, Options). + +init(_Options) -> + ?reporting:new_state(). + +handle_begin(_test_or_group, _data, State) -> + State. + +handle_end(group, _data, State) -> + State; +handle_end(test, Data, State) -> + {AtomModule, AtomFunction, _Arity} = proplists:get_value(source, Data), + Module = erlang:atom_to_binary(AtomModule), + Function = erlang:atom_to_binary(AtomFunction), + + % EUnit swallows stdout, so print it to make debugging easier. + case proplists:get_value(output, Data) of + undefined -> ok; + <<>> -> ok; + Out -> gleam@io:print(Out) + end, + + case proplists:get_value(status, Data) of + ok -> + ?reporting:test_passed(State); + {skipped, _Reason} -> + ?reporting:test_skipped(State, Module, Function); + {error, {_, Exception, _Stack}} -> + ?reporting:test_failed(State, Module, Function, Exception) + end. + + +handle_cancel(_test_or_group, Data, State) -> + ?reporting:test_failed(State, <<"gleeunit">>, <<"main">>, Data). + +terminate({ok, _Data}, State) -> + ?reporting:finished(State), + ok; +terminate({error, Reason}, State) -> + ?reporting:finished(State), + io:fwrite(" +Eunit failed: + +~80p + +This is probably a bug in gleeunit. Please report it. +", [Reason]), + sync_end(error). + +sync_end(Result) -> + receive + {stop, Reference, ReplyTo} -> + ReplyTo ! {result, Reference, Result}, + ok + end. diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit.app b/build/dev/erlang/gleeunit/ebin/gleeunit.app new file mode 100644 index 0000000..acc1a8c --- /dev/null +++ b/build/dev/erlang/gleeunit/ebin/gleeunit.app @@ -0,0 +1,7 @@ +{application, gleeunit, [ + {vsn, "1.6.0"}, + {applications, [gleam_stdlib]}, + {description, "A simple test runner for Gleam, using EUnit on Erlang"}, + {modules, []}, + {registered, []} +]}. diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit.beam b/build/dev/erlang/gleeunit/ebin/gleeunit.beam new file mode 100644 index 0000000000000000000000000000000000000000..40f2152944b9122bb307cacbe4f6003671282992 GIT binary patch literal 4188 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 Q0K^Um{gz-jK8K+H0>txoE&u=k literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit@internal@reporting.beam b/build/dev/erlang/gleeunit/ebin/gleeunit@internal@reporting.beam new file mode 100644 index 0000000000000000000000000000000000000000..12b2e121b77c483e56e785e3be43c1d412fecdca GIT binary patch literal 14556 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 literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit@should.beam b/build/dev/erlang/gleeunit/ebin/gleeunit@should.beam new file mode 100644 index 0000000000000000000000000000000000000000..57db51276e2e13cfaa295ebd755f9f2ae9ad7976 GIT binary patch literal 5588 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 RJrd@TgbbF75VErX@PF!)Q1Ac% literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit_ffi.beam b/build/dev/erlang/gleeunit/ebin/gleeunit_ffi.beam new file mode 100644 index 0000000000000000000000000000000000000000..0ccc792b5b112eb5fed2f5cbbb17f073f0351d36 GIT binary patch literal 1728 zcmcIki&GOv7{AK}0!ZOV5OhQhP^F4_pn{0D6SSa6Km-DU+B`4eAi0F(!b8wn5%E!r zJZcS*s*J4zjEY)BsznsARS{9BI--J56bI|5fE|U=?nbfx1KpY5ecyiH?|bat?uM_7 z4L}h4(@Vlaqe5v(FoGZ_0ocwOEkT$ml9sB~q?4MYR8lpmB~12&Q7fl3E((&88?&Xf zUaBQcGz6#aeFUafV2(locmKTNkh&Y0Kcq#N|{WikjZ+; zHrZ^=?d@OgP!@I_M?nK(ho6;2GAC`}uI-S0y_EWhQdW`v;3& zmz6FtbeH#Lf=o*zC^g_)Y!CQe?HY29)wyX0(cQ{>Dr z#$ZCka!GN}WPh&!>s62Z0`Jdey!tin(0Q+i1O02;{~3BRYh$WK+qY{AqbgV_2+$Ha z(&Jh8(u+o%iVogyo^pP5qG_Vvu$_bvdwk!H+NP-DM`K@|c~lTKb!~jqO~=p%=(;Q4 zw(MR!T=ak~NrjvokLf=HimpI&?-BC61 z$zZ!=;e*BEVAr?(V?tBSBs8k=DSs1ZXGGmVTI?dXrL_NTmy?H&jJ(+4(&Y49e6Axx zJhNsq^I7&@I;r7a?s9A0*OLo&y1IHyzcA}{VJma$FaFLOb%C{kXZBk!=7cjF0=GI; zT$~5n&Hv;oacN!I>&hE!ncaY(YX)QtGmkXvp7@ZVS zaeZ(2iZx?%GZgJFgQLCg>eovPKc&kaZRkok9T(iqns(Lm&f--^uOF!&$eibqJk7&r zd$=#*TiBU=;m@w*$gH}dmCaqs{sd(`THm4ltE#)rrQUkmiGMvubz*j5bMpDWz5ANn zE*}0S^pY2yR8q3h#njZCGS0Px*nxW08j{spipLMs3O literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit_gleam_panic_ffi.beam b/build/dev/erlang/gleeunit/ebin/gleeunit_gleam_panic_ffi.beam new file mode 100644 index 0000000000000000000000000000000000000000..67a7eaf0129d76198290e6aa1f08b8424ebd9bd3 GIT binary patch literal 3312 zcmc&$iC+`f7S75t1ehd1K(17zxn2#d(S!F`R-)qOcqB) z&&A;=1B*hrkzCEn`8XVYHx7rJZZDCcs1}oI_`pEqd?kWOg?zDCN)f9Ra=vIihRCHt zi!mpvQYlm>h+2)RG>{C{@W)KDF^Qy6h!o^hM5aZ_Y7L^&SSk^X2328vN?4&uLRI{~QphT)BuQg7K}M3HVvPx^k|CJH3b4!h8U=r>ps7p> zWFs;QEruGlgJ@6@eM}rG`WquDO@%1UCX|rGQWM4t|heg$Tvr2!X(a0Srei00Y1T59?t9%?-vgOHtx}G>!-} znBMdNI?Bjgv@$w0(O2b*_cCEx((s%y??GKme()i7EvtnND+Pz?3_)}-oz03d#_+~s z1o`aiz)#_DICK(+Wy4{+bBI2ACJD}g1u)3rEpjK>5IH_XGGON51)MM(k&ajDy$G~E z7@xUcYt-=?=+H6*5L^dQk3h6S{H}2aM5kNg=6M;m!-Sc~aYP1A&oO1y$ zL>i8cKR6LhrBiTB4xOmyk>FbsF?Pn7>aiFB#9%}AEXaXQVH!2FZ8$8VUSJBtRU{(F zs6HW;M1}EJOIwNiTMeSY)?b6I2e4X!aH=H?IlYCPpWq+B zJdQEdg-wT?>G+|sXr_(@XBr$#$cZ)K2Y12@{vSW}zx-5vCaCPn#GBFfTT%^$IS`W# zO=j)0q!Jmh_xPd!auY(V7|1;su2uqmB{U_5C1eNFjU}fVD$(^gz%&hqH?!f;h|6I> zX*;$A=|uz&ON>Sp3kF<-Txl4607w8f0JZ=GfJp$30Qhlx`af(!Xu2`i zux_B7Htx3@x4~fKGjJI=2#d9tp_bG5oH{;Qg3)-G5CcyvlWGhxEC5D&sZbyghy;QM zicY~yN#vZF?Vd9wotHcCxS1Qt2rd%UARul|whUbHNrW^Q#gIf9cnQTQqS1oxVRWQH za%6oXYJ4-3lR@Y*h0suALbofh4H{_xf7fIM<_6tnT#ZHr#%X`nA*QM^BQ*x&0;77* z;F~su;xoIDJ#~^MP$4)16NC7AV>}V)GEGHQhDMfxBhUBn^O$Q`QYa1mX+oh0P1H(^ z?|d?Fny3|8l@LwAsXbSMUaIz#sE{N??kPf3JrSi!?IA}!6SY#A$hb1rq&z1YwdZ)J z1|1d^BSHdab}}WK2Ofr!^wONqQq(=GU|(ze zQ)Do++5G1__R5{YZGSkW^+fo8%ib5^eZ}X-rdubtncH^RPu@_l`F^1&BJIem_l}>x z=sug#d2M6TZlthEb#C9~V?pf4TOCsmezTYIyW{0Aw@-=MSydaJ5)crO6I%3Khw7h= z{?cN9nAuv(UU~jLKh^Ki=6Sh|4qcI-H6<@x>GE^6-@Nid@1O1;>$$mIAimoFsIg-D znuNNay+7&-DHTULl(msVUmshOTb2DZ%w_9IZrrrjvWmRH_^PA`Y0(;o8{bw`m(NeK z-*cMVe!C9&JoP|T=-xs}MNNL?ea&Z8^zb(!ScJvXm- zTXomGxNllz^OOAaqwYhz?Z5Lbz2zh!YA`-`JTXB3q_E{E1}Lm!m4(}Q|g z4#RFiJxhOEVQV#CV|%U8_oudob%>Dz41F58lRq75Z06t!m}E6>l>It?HWM+G1Ly>;864|b)j;|v9sxO^Dmsy@{Gl@6Lkmb9S%nkHAALv&TmIn3o z?Y@1;I&e|S5s@OXb4wTZwfI$S&{n5{mU|1^s=Ut}Yb<*B`z^Z{$4A`$)wypnxvoJM zpTFkhsBrk2UH8V%dFbi@-|fDu->$vYJTlcWrS(F!L-D`&K3H3OqN1ZA?lAeg)z5;R z-W6q@ljK)*GDxGdmX6Z5e%x{JezlH2tN20S($ODnlGKCA1y58?<$k);fv(QM1r)3{ z@Q-?#L#+kW-Dh7+DJ>D%=Tm}LQHDp&K7_gF9a5No@S~1SqcPU%dZ?AB5-Jb3+SG54 z=^<2}+MSczAJ;v@XX=d<-J}OuH%b+8xtLsc>~2!lz572lgx3`eIBIprLYEB956BAM z(5`Q9uZ|zFAOwo?E3nc@I>BY6jqmDJPk-?s`xExMml!r;-h0(<8*U#sL-76~nR%Q{ zE2ycERxA!-_LKT<|JvNMBkiNB+sCN#kppg@{@7B-Tc*GHFhU81iGEw5lSe(j9!`Ep zuGwMXRu*)|C6(o#R#sZ=l4^b_A->~$WrIh4=?AB+K~n}8W%PK)nwE`IOfo{Nv$y?_ zun>9dYukmuZ^YV%^SnRyU)+A&LXpji2)XuVz&|}N_m|$tFnzmQW$B{;-IvO)X=U^~ z3rcgoQsosB&M~aMuvH75g=z+;JiEj4A13(^(=>xr=L~R~`wwr+3(U$3y!q z_-4-GdwbKV9tqUzS!Tt%mNs};Um~lwh4o)uKT^{NE|Hs`(z{medheiD z+r`F<=?fM&(O*g&n(?!Kc+=9dP}p+ujyNPndosV~%0*Mky84panQNY9{8rYKGVfZ# zdy^lF{C>K+A~Yj*|IV4~bN%ZZ1!o+4D>p7~9Oy2OjUQ-{d}WchfYvbd?OlfJ7mw<4 zRxN*&lHB1n;(WN*Z}r@Fc4tRiZ`OZZ3_f(rz`s~9d;>6XK)^5qz|**8=8onr=1g-Z bb2sxD|CcXX?0Tg^9|gehKZRiZ3CH;l1R%L# literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/ebin/gleeunit_progress.beam b/build/dev/erlang/gleeunit/ebin/gleeunit_progress.beam new file mode 100644 index 0000000000000000000000000000000000000000..349d580f345f4b9d50c978d7ac8626b0f5386671 GIT binary patch literal 3628 zcmcIndsq|K65q`R$i@Im5)5yGLAl5yQ4qBRSfV@&_(GxhAPHGQAS5vfg0xVm#VT6C zB5Dd!QCqFjf*PcP4}5`Ises<9s0igzL8=C96|awb7V+Nu_5Zuy_uH8>Gv_xmn`O=t zzG&$z2(oe)g@wk3>X*-hAUFkrAa@(Nk|45F3VpIhtCnjCoz6_BmuU4??~F=?PEV)^ zEmZ+R9N)*{3YDJFsw7HWOK8+uy+S2NRYZ0&*r_KNX%dx8NhC`Nxk5#sTo5XmnOv*R z(opq;PH(PLXK7Oi6r|LU8FZ+e&?m2xD6^BIx|_XPL?WE6770(b(UU} zrAM<=G9p!>B4jjBiX;ea5IZJ0oXtipsg)T#((GW5QnJRg5F=b+rDp4p2 z8AYA(ZmE&zbcD=uvc?pNDuqy@ptDSnR8P=ACWS5y#4FV1so7cuFzME-Qj$S4RGnU} zF$a$;OR1ldsg`Adh83z*wKdtu|E!?}Y8e4RlqKL=u;6lWggxJqiF^Pc5V0Y|P-=kz1!DmR z&O!`(!4gNPxIYW0V~C*+Z1KK?L_pw1w=pzZU^v_ioHZQGAE&bsLpunV|0m$HLAW9W zVg<4+Z8$jHc7Q(hpKv=)<>71=?v5CGXoAH!+#^CT)_hAF7KmpFL@dnjzY$MqxEP0@ zdI2W7J-LO3(J&1T)3AviX*P!TXauG)4F!>Gn8q^DY$!~+qX4FXy8ZA7&;bv@Be*;R zjTwiFVVbRh#sU#eT$na>zNIZF(RQLl9;m@DkY{O2mT756x3}cLG!6selI_#j7FYpJ zw?~)|3#QpIFdX-zPB?6V1LHzrR0?Yo2H_C`5Iog_TM9@JGtANff@$^!8V6+LVld5t z0sgdTjvPy8ZR z(q{!=4FCf$0a%kd8P5SAIY`|OfI6u=07=G^cIQdm1xQzb_nhvNc9NgeDPcJiwP}Ek z0`LGx4!21ih>879K$09&0UQCy{A>W)q)rFYVp1n>IF7oq?P7Hr`KdCaNz=O3qD9;9rk>z|Q22oDtuD$QMe6G|&ZNz&A~ z^kQ31!k(f~n3E70o_dsm*|G;brq39NpXol+z5F{b*`Q~0%#CHV%Tcl3am)V^?Q@ww za|u+efuYr{(>ft2me5N;Zl4WGaEH?<*%+acNWt()P9?yo0+VCHkxkE(td|nWM2<$A zo(@7|)G1`$n$2L8Am{9w0n#tR_F~292-~REo(2diNEdGbLm6s6??J?XJ;P&k5 zNUyvb=O64U3aJnI3VDFCN z&3D^fr{~IPCnPqfKQ#Z&lGx$TLXUp=@L#IY`$$tnP2^45rnxNxa3M2)MMuOMsAxpK z*1x9nWPaLn%8jEo7xHA^_@;1+57qwZP0M3uMC?yoRbB4#fm6|z#m+kwW)!*8r_(Ji zK8iLfD@@16J0b%bb{M<{+kCz~Kiem{kP|g*d~=0pdM*5lSh%!$PRZ6im#crSyXdwc z^Rc<9i?GU$Y8M*TE%(^Hv)A*BsMMd%cY1D!II#SQ%W_JM$)W;}K2Cg5so? z?qM%mjI&+_B&vnymtHkmobUXXQNlXR8z|_P)Ve7>2S%UXlD-&Vym9buHw)tC?+vU9 zep=Z+Q0{0v?1(}9kHe3gZMAbx5T+V-9CFt`+7uW0c3!IR#Gj0nSJyi~Za@6F!g;55 z_piMs@0bU&-P8=n^%;(7Kb#kC|D(IW!Z=zc&Olty6N!|BR_xivL-)3-R?MNTUh(Da zgZ+*Pyb;kBsWzP^xNzVR+1<+^E@13UT-Y?{>ib5 zzA424nT*K2$%VGe@nPlp=f=U5N5kmt?$$MSrd8#eGLBJ0(tLV%gvN_Q3l25UmQSfq z4BEfcJJPk&?5~y9PN%mhMpl35wp?8Cyc$a1Vo~I(SN(RK@$1xk9C7A3x&>6f49MY- z=C03vmr~2bVM8aJZ5!Fm0sdytUD2Hde>`i?Ou1Cy+?aW)W{wBrUg?KDnN-^^eB&0r zp$j*JN4o_fVMd!S^P!4>S;v0fF_e&YqhaXASw%K>ZFihLi(e3F`6Zf{__(v^~^@#@( z?X6FKceBxLDSvFcXi5LI%CdC_0vnJc_X2KqpXePCS67rcZ1{Ob(1Ou!t8UScx8>q& zzq&Hf?#nqIBm15Vzxj5k@#5vU`yMapCl953PWb5O0hd@w-7JUPebK_}ri(>em@_O_E?n~aS=Y{%JGWfcUdpcy zdrdj_To5!Ge6Q@2pFCb@p8OSjufjdjRr7M&s>Cbekyz&EyG~zg(pX#lG`nr{*}jLf zW{fWGXsH%eRgd{C3Y&Cjguipp~{7MqNqBnLZTQi)NY4c1ubW@+uloH@}u%35R zyLFCn=Z?i|8huOoy8cD(qaKv;vb$v=CktPp5y5_WGfzW{Oyzs_WM5sy(~m9Ny}v&A zk|d{d#qq7eqK|hKS-1I_$8WCfSbKc@R!7xcWxoB_XFhvdw>rBzW3|^_{e?nlS9Emj z^85=!=RBgX#e_!riHfZQg|B=xw@f}2*(t7a>%oQ>;=x0wSygwQ+!hQc-wpcf&Gx48 zz?#Ojc4NEx8T>1j~>V7Zge*57$2Dy*HYIQk$dr!G_bq%3DdND%=7-t?WWoT zI$_gq7FG$fuiv@x%x{QQa{Ea3zV!7L@o}iYkl4mboUya8&H3RNvdVYCf-xfB;dg+KnRtD2QEtHPWd0cZ`2>1 kgU&_gp@FCn4MQXUpJyv5D1N<$td;z}BEPv{>$ec}Z~DRrIsgCw literal 0 HcmV?d00001 diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl new file mode 100644 index 0000000..9360941 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl @@ -0,0 +1,6 @@ +-record(assert, { + start :: integer(), + 'end' :: integer(), + expression_start :: integer(), + kind :: gleeunit@internal@gleam_panic:assert_kind() +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl new file mode 100644 index 0000000..812663c --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl @@ -0,0 +1,5 @@ +-record(asserted_expression, { + start :: integer(), + 'end' :: integer(), + kind :: gleeunit@internal@gleam_panic:expression_kind() +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl new file mode 100644 index 0000000..eee44c9 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl @@ -0,0 +1,5 @@ +-record(binary_operator, { + operator :: binary(), + left :: gleeunit@internal@gleam_panic:asserted_expression(), + right :: gleeunit@internal@gleam_panic:asserted_expression() +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl new file mode 100644 index 0000000..e7ffaa0 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl @@ -0,0 +1 @@ +-record(expression, {value :: gleam@dynamic:dynamic_()}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl new file mode 100644 index 0000000..9d55488 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl @@ -0,0 +1,3 @@ +-record(function_call, { + arguments :: list(gleeunit@internal@gleam_panic:asserted_expression()) +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl new file mode 100644 index 0000000..cf36764 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl @@ -0,0 +1,8 @@ +-record(gleam_panic, { + message :: binary(), + file :: binary(), + module :: binary(), + function :: binary(), + line :: integer(), + kind :: gleeunit@internal@gleam_panic:panic_kind() +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl new file mode 100644 index 0000000..11f865e --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl @@ -0,0 +1,7 @@ +-record(let_assert, { + start :: integer(), + 'end' :: integer(), + pattern_start :: integer(), + pattern_end :: integer(), + value :: gleam@dynamic:dynamic_() +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl new file mode 100644 index 0000000..2396489 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl @@ -0,0 +1 @@ +-record(literal, {value :: gleam@dynamic:dynamic_()}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl new file mode 100644 index 0000000..0424990 --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl @@ -0,0 +1,3 @@ +-record(other_expression, { + expression :: gleeunit@internal@gleam_panic:asserted_expression() +}). diff --git a/build/dev/erlang/gleeunit/include/gleeunit@internal@reporting_State.hrl b/build/dev/erlang/gleeunit/include/gleeunit@internal@reporting_State.hrl new file mode 100644 index 0000000..575ccce --- /dev/null +++ b/build/dev/erlang/gleeunit/include/gleeunit@internal@reporting_State.hrl @@ -0,0 +1 @@ +-record(state, {passed :: integer(), failed :: integer(), skipped :: integer()}). diff --git a/build/dev/erlang/logger b/build/dev/erlang/logger new file mode 120000 index 0000000..590f9ed --- /dev/null +++ b/build/dev/erlang/logger @@ -0,0 +1 @@ +/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/logger \ No newline at end of file diff --git a/build/dev/erlang/mix b/build/dev/erlang/mix new file mode 120000 index 0000000..b57e932 --- /dev/null +++ b/build/dev/erlang/mix @@ -0,0 +1 @@ +/Users/graham/.asdf/installs/elixir/1.19.0-rc.0-otp-27/lib/mix \ No newline at end of file diff --git a/build/gleam-dev-erlang.lock b/build/gleam-dev-erlang.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/gleam-dev-javascript.lock b/build/gleam-dev-javascript.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/gleam-lsp-erlang.lock b/build/gleam-lsp-erlang.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/gleam-lsp-javascript.lock b/build/gleam-lsp-javascript.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/gleam-prod-erlang.lock b/build/gleam-prod-erlang.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/gleam-prod-javascript.lock b/build/gleam-prod-javascript.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/packages/gleam.lock b/build/packages/gleam.lock new file mode 100644 index 0000000..e69de29 diff --git a/build/packages/gleam_stdlib/LICENCE b/build/packages/gleam_stdlib/LICENCE new file mode 100644 index 0000000..c1dabd0 --- /dev/null +++ b/build/packages/gleam_stdlib/LICENCE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2018, Louis Pilfold . + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/build/packages/gleam_stdlib/README.md b/build/packages/gleam_stdlib/README.md new file mode 100644 index 0000000..5e1ed4c --- /dev/null +++ b/build/packages/gleam_stdlib/README.md @@ -0,0 +1,34 @@ +# stdlib + +[![Package Version](https://img.shields.io/hexpm/v/gleam_stdlib)](https://hex.pm/packages/gleam_stdlib) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleam_stdlib/) +[![Discord chat](https://img.shields.io/discord/768594524158427167?color=blue)](https://discord.gg/Fm8Pwmy) + +Gleam's standard library! +Documentation available on [HexDocs](https://hexdocs.pm/gleam_stdlib/). + +## Installation + +Add `gleam_stdlib` to your Gleam project. + +```sh +gleam add gleam_stdlib +``` +```gleam +import gleam/io + +pub fn greet(name: String) -> Nil { + io.println("Hello " <> name <> "!") +} +``` + +## Targets + +Gleam's standard library supports both targets: Erlang and JavaScript. + +### Compatibility + +This library is compatible with all versions of Erlang/OTP 26 and higher, +as well as all NodeJS, Deno, Bun, and major browsers that are currently +supported by their maintainers. If you have a compatibility issue with +any platform open an issue and we'll see what we can do to help. diff --git a/build/packages/gleam_stdlib/gleam.toml b/build/packages/gleam_stdlib/gleam.toml new file mode 100644 index 0000000..b72a41b --- /dev/null +++ b/build/packages/gleam_stdlib/gleam.toml @@ -0,0 +1,14 @@ +name = "gleam_stdlib" +version = "0.62.0" +gleam = ">= 1.11.0" +licences = ["Apache-2.0"] +description = "A standard library for the Gleam programming language" + +repository = { type = "github", user = "gleam-lang", repo = "stdlib" } +links = [ + { title = "Website", href = "https://gleam.run" }, + { title = "Sponsor", href = "https://github.com/sponsors/lpil" }, +] + +[javascript.deno] +allow_read = ["./"] diff --git a/build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl b/build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl new file mode 100644 index 0000000..b1135f2 --- /dev/null +++ b/build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl @@ -0,0 +1,5 @@ +-record(decode_error, { + expected :: binary(), + found :: binary(), + path :: list(binary()) +}). diff --git a/build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl b/build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl new file mode 100644 index 0000000..a2fcfc6 --- /dev/null +++ b/build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl @@ -0,0 +1,4 @@ +-record(decoder, { + function :: fun((gleam@dynamic:dynamic_()) -> {any(), + list(gleam@dynamic@decode:decode_error())}) +}). diff --git a/build/packages/gleam_stdlib/include/gleam@set_Set.hrl b/build/packages/gleam_stdlib/include/gleam@set_Set.hrl new file mode 100644 index 0000000..51fb778 --- /dev/null +++ b/build/packages/gleam_stdlib/include/gleam@set_Set.hrl @@ -0,0 +1 @@ +-record(set, {dict :: gleam@dict:dict(any(), list(nil))}). diff --git a/build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl b/build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl new file mode 100644 index 0000000..50150f4 --- /dev/null +++ b/build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl @@ -0,0 +1,9 @@ +-record(uri, { + scheme :: gleam@option:option(binary()), + userinfo :: gleam@option:option(binary()), + host :: gleam@option:option(binary()), + port :: gleam@option:option(integer()), + path :: binary(), + 'query' :: gleam@option:option(binary()), + fragment :: gleam@option:option(binary()) +}). diff --git a/build/packages/gleam_stdlib/src/dict.mjs b/build/packages/gleam_stdlib/src/dict.mjs new file mode 100644 index 0000000..f39cd54 --- /dev/null +++ b/build/packages/gleam_stdlib/src/dict.mjs @@ -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 | IndexNode | CollisionNode} 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 | Node)[] }} ArrayNode + */ +/** + * @template K,V + * @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry | Node)[] }} IndexNode + */ +/** + * @template K,V + * @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry[] }} 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} */ +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} + */ +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} + */ +/** + * Associate a node with a new entry, creating a new node + * @template T,K,V + * @type {AssocFunction,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,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,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,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} 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} + */ +/** + * Return the found entry or undefined if not present in the root + * @template K,V + * @type {FindFunction,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,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,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} root + * @param {K} key + * @returns {undefined | Entry} + */ +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} + */ +/** + * 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,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,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,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} root + * @param {K} key + * @returns {undefined | Node} + */ +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} 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} o + * @returns {Dict} + */ + static fromObject(o) { + const keys = Object.keys(o); + /** @type Dict */ + 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} o + * @returns {Dict} + */ + static fromMap(o) { + /** @type Dict */ + 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} 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} + */ + 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} + */ + 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(); diff --git a/build/packages/gleam_stdlib/src/gleam/bit_array.gleam b/build/packages/gleam_stdlib/src/gleam/bit_array.gleam new file mode 100644 index 0000000..1aae367 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/bit_array.gleam @@ -0,0 +1,279 @@ +//// BitArrays are a sequence of binary data of any length. + +import gleam/int +import gleam/order +import gleam/string + +/// Converts a UTF-8 `String` type into a `BitArray`. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_from_string") +pub fn from_string(x: String) -> BitArray + +/// Returns an integer which is the number of bits in the bit array. +/// +@external(erlang, "erlang", "bit_size") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_bit_size") +pub fn bit_size(x: BitArray) -> Int + +/// Returns an integer which is the number of bytes in the bit array. +/// +@external(erlang, "erlang", "byte_size") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_byte_size") +pub fn byte_size(x: BitArray) -> Int + +/// Pads a bit array with zeros so that it is a whole number of bytes. +/// +@external(erlang, "gleam_stdlib", "bit_array_pad_to_bytes") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_pad_to_bytes") +pub fn pad_to_bytes(x: BitArray) -> BitArray + +/// Creates a new bit array by joining two bit arrays. +/// +/// ## Examples +/// +/// ```gleam +/// append(to: from_string("butter"), suffix: from_string("fly")) +/// // -> from_string("butterfly") +/// ``` +/// +pub fn append(to first: BitArray, suffix second: BitArray) -> BitArray { + concat([first, second]) +} + +/// Extracts a sub-section of a bit array. +/// +/// The slice will start at given position and continue up to specified +/// length. +/// A negative length can be used to extract bytes at the end of a bit array. +/// +/// This function runs in constant time. +/// +@external(erlang, "gleam_stdlib", "bit_array_slice") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_slice") +pub fn slice( + from string: BitArray, + at position: Int, + take length: Int, +) -> Result(BitArray, Nil) + +/// Tests to see whether a bit array is valid UTF-8. +/// +pub fn is_utf8(bits: BitArray) -> Bool { + is_utf8_loop(bits) +} + +@target(erlang) +fn is_utf8_loop(bits: BitArray) -> Bool { + case bits { + <<>> -> True + <<_:utf8, rest:bytes>> -> is_utf8_loop(rest) + _ -> False + } +} + +@target(javascript) +fn is_utf8_loop(bits: BitArray) -> Bool { + case to_string(bits) { + Ok(_) -> True + Error(_) -> False + } +} + +/// Converts a bit array to a string. +/// +/// Returns an error if the bit array is invalid UTF-8 data. +/// +@external(javascript, "../gleam_stdlib.mjs", "bit_array_to_string") +pub fn to_string(bits: BitArray) -> Result(String, Nil) { + case is_utf8(bits) { + True -> Ok(unsafe_to_string(bits)) + False -> Error(Nil) + } +} + +@external(erlang, "gleam_stdlib", "identity") +fn unsafe_to_string(a: BitArray) -> String + +/// Creates a new bit array by joining multiple binaries. +/// +/// ## Examples +/// +/// ```gleam +/// concat([from_string("butter"), from_string("fly")]) +/// // -> from_string("butterfly") +/// ``` +/// +@external(erlang, "gleam_stdlib", "bit_array_concat") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_concat") +pub fn concat(bit_arrays: List(BitArray)) -> BitArray + +/// Encodes a BitArray into a base 64 encoded string. +/// +/// If the bit array does not contain a whole number of bytes then it is padded +/// with zero bits prior to being encoded. +/// +@external(erlang, "gleam_stdlib", "bit_array_base64_encode") +@external(javascript, "../gleam_stdlib.mjs", "encode64") +pub fn base64_encode(input: BitArray, padding: Bool) -> String + +/// Decodes a base 64 encoded string into a `BitArray`. +/// +pub fn base64_decode(encoded: String) -> Result(BitArray, Nil) { + let padded = case byte_size(from_string(encoded)) % 4 { + 0 -> encoded + n -> string.append(encoded, string.repeat("=", 4 - n)) + } + decode64(padded) +} + +@external(erlang, "gleam_stdlib", "base_decode64") +@external(javascript, "../gleam_stdlib.mjs", "decode64") +fn decode64(a: String) -> Result(BitArray, Nil) + +/// Encodes a `BitArray` into a base 64 encoded string with URL and filename +/// safe alphabet. +/// +/// If the bit array does not contain a whole number of bytes then it is padded +/// with zero bits prior to being encoded. +/// +pub fn base64_url_encode(input: BitArray, padding: Bool) -> String { + base64_encode(input, padding) + |> string.replace("+", "-") + |> string.replace("/", "_") +} + +/// Decodes a base 64 encoded string with URL and filename safe alphabet into a +/// `BitArray`. +/// +pub fn base64_url_decode(encoded: String) -> Result(BitArray, Nil) { + encoded + |> string.replace("-", "+") + |> string.replace("_", "/") + |> base64_decode() +} + +/// Encodes a `BitArray` into a base 16 encoded string. +/// +/// If the bit array does not contain a whole number of bytes then it is padded +/// with zero bits prior to being encoded. +/// +@external(erlang, "gleam_stdlib", "base16_encode") +@external(javascript, "../gleam_stdlib.mjs", "base16_encode") +pub fn base16_encode(input: BitArray) -> String + +/// Decodes a base 16 encoded string into a `BitArray`. +/// +@external(erlang, "gleam_stdlib", "base16_decode") +@external(javascript, "../gleam_stdlib.mjs", "base16_decode") +pub fn base16_decode(input: String) -> Result(BitArray, Nil) + +/// Converts a bit array to a string containing the decimal value of each byte. +/// +/// Use this over `string.inspect` when you have a bit array you want printed +/// in the array syntax even if it is valid UTF-8. +/// +/// ## Examples +/// +/// ```gleam +/// inspect(<<0, 20, 0x20, 255>>) +/// // -> "<<0, 20, 32, 255>>" +/// +/// inspect(<<100, 5:3>>) +/// // -> "<<100, 5:size(3)>>" +/// ``` +/// +pub fn inspect(input: BitArray) -> String { + inspect_loop(input, "<<") <> ">>" +} + +fn inspect_loop(input: BitArray, accumulator: String) -> String { + case input { + <<>> -> accumulator + + <> -> accumulator <> int.to_string(x) <> ":size(1)" + <> -> accumulator <> int.to_string(x) <> ":size(2)" + <> -> accumulator <> int.to_string(x) <> ":size(3)" + <> -> accumulator <> int.to_string(x) <> ":size(4)" + <> -> accumulator <> int.to_string(x) <> ":size(5)" + <> -> accumulator <> int.to_string(x) <> ":size(6)" + <> -> accumulator <> int.to_string(x) <> ":size(7)" + + <> -> { + let suffix = case rest { + <<>> -> "" + _ -> ", " + } + + let accumulator = accumulator <> int.to_string(x) <> suffix + inspect_loop(rest, accumulator) + } + + _ -> accumulator + } +} + +/// Compare two bit arrays as sequences of bytes. +/// +/// ## Examples +/// +/// ```gleam +/// compare(<<1>>, <<2>>) +/// // -> Lt +/// +/// compare(<<"AB":utf8>>, <<"AA":utf8>>) +/// // -> Gt +/// +/// compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>) +/// // -> Eq +/// ``` +/// +pub fn compare(a: BitArray, with b: BitArray) -> order.Order { + case a, b { + <>, <> -> + case first_byte, second_byte { + f, s if f > s -> order.Gt + f, s if f < s -> order.Lt + _, _ -> compare(first_rest, second_rest) + } + + <<>>, <<>> -> order.Eq + // First has more items, example: "AB" > "A": + _, <<>> -> order.Gt + // Second has more items, example: "A" < "AB": + <<>>, _ -> order.Lt + // This happens when there's unusually sized elements. + // Handle these special cases via custom erlang function. + first, second -> + case bit_array_to_int_and_size(first), bit_array_to_int_and_size(second) { + #(a, _), #(b, _) if a > b -> order.Gt + #(a, _), #(b, _) if a < b -> order.Lt + #(_, size_a), #(_, size_b) if size_a > size_b -> order.Gt + #(_, size_a), #(_, size_b) if size_a < size_b -> order.Lt + _, _ -> order.Eq + } + } +} + +@external(erlang, "gleam_stdlib", "bit_array_to_int_and_size") +@external(javascript, "../gleam_stdlib.mjs", "bit_array_to_int_and_size") +fn bit_array_to_int_and_size(a: BitArray) -> #(Int, Int) + +/// Checks whether the first `BitArray` starts with the second one. +/// +/// ## Examples +/// +/// ```gleam +/// starts_with(<<1, 2, 3, 4>>, <<1, 2>>) +/// // -> True +/// ``` +/// +@external(javascript, "../gleam_stdlib.mjs", "bit_array_starts_with") +pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { + let prefix_size = bit_size(prefix) + + case bits { + <> if pref == prefix -> True + _ -> False + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/bool.gleam b/build/packages/gleam_stdlib/src/gleam/bool.gleam new file mode 100644 index 0000000..26a6ac4 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/bool.gleam @@ -0,0 +1,316 @@ +//// A type with two possible values, `True` and `False`. Used to indicate whether +//// things are... true or false! +//// +//// Often is it clearer and offers more type safety to define a custom type +//// than to use `Bool`. For example, rather than having a `is_teacher: Bool` +//// field consider having a `role: SchoolRole` field where `SchoolRole` is a custom +//// type that can be either `Student` or `Teacher`. + +/// Returns the and of two bools, but it evaluates both arguments. +/// +/// It's the function equivalent of the `&&` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// and(True, True) +/// // -> True +/// ``` +/// +/// ```gleam +/// and(False, True) +/// // -> False +/// ``` +/// +/// ```gleam +/// False |> and(True) +/// // -> False +/// ``` +/// +pub fn and(a: Bool, b: Bool) -> Bool { + a && b +} + +/// Returns the or of two bools, but it evaluates both arguments. +/// +/// It's the function equivalent of the `||` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// or(True, True) +/// // -> True +/// ``` +/// +/// ```gleam +/// or(False, True) +/// // -> True +/// ``` +/// +/// ```gleam +/// False |> or(True) +/// // -> True +/// ``` +/// +pub fn or(a: Bool, b: Bool) -> Bool { + a || b +} + +/// Returns the opposite bool value. +/// +/// This is the same as the `!` or `not` operators in some other languages. +/// +/// ## Examples +/// +/// ```gleam +/// negate(True) +/// // -> False +/// ``` +/// +/// ```gleam +/// negate(False) +/// // -> True +/// ``` +/// +pub fn negate(bool: Bool) -> Bool { + !bool +} + +/// Returns the nor of two bools. +/// +/// ## Examples +/// +/// ```gleam +/// nor(False, False) +/// // -> True +/// ``` +/// +/// ```gleam +/// nor(False, True) +/// // -> False +/// ``` +/// +/// ```gleam +/// nor(True, False) +/// // -> False +/// ``` +/// +/// ```gleam +/// nor(True, True) +/// // -> False +/// ``` +/// +pub fn nor(a: Bool, b: Bool) -> Bool { + !{ a || b } +} + +/// Returns the nand of two bools. +/// +/// ## Examples +/// +/// ```gleam +/// nand(False, False) +/// // -> True +/// ``` +/// +/// ```gleam +/// nand(False, True) +/// // -> True +/// ``` +/// +/// ```gleam +/// nand(True, False) +/// // -> True +/// ``` +/// +/// ```gleam +/// nand(True, True) +/// // -> False +/// ``` +/// +pub fn nand(a: Bool, b: Bool) -> Bool { + !{ a && b } +} + +/// Returns the exclusive or of two bools. +/// +/// ## Examples +/// +/// ```gleam +/// exclusive_or(False, False) +/// // -> False +/// ``` +/// +/// ```gleam +/// exclusive_or(False, True) +/// // -> True +/// ``` +/// +/// ```gleam +/// exclusive_or(True, False) +/// // -> True +/// ``` +/// +/// ```gleam +/// exclusive_or(True, True) +/// // -> False +/// ``` +/// +pub fn exclusive_or(a: Bool, b: Bool) -> Bool { + a != b +} + +/// Returns the exclusive nor of two bools. +/// +/// ## Examples +/// +/// ```gleam +/// exclusive_nor(False, False) +/// // -> True +/// ``` +/// +/// ```gleam +/// exclusive_nor(False, True) +/// // -> False +/// ``` +/// +/// ```gleam +/// exclusive_nor(True, False) +/// // -> False +/// ``` +/// +/// ```gleam +/// exclusive_nor(True, True) +/// // -> True +/// ``` +/// +pub fn exclusive_nor(a: Bool, b: Bool) -> Bool { + a == b +} + +/// Returns a string representation of the given bool. +/// +/// ## Examples +/// +/// ```gleam +/// to_string(True) +/// // -> "True" +/// ``` +/// +/// ```gleam +/// to_string(False) +/// // -> "False" +/// ``` +/// +pub fn to_string(bool: Bool) -> String { + case bool { + False -> "False" + True -> "True" + } +} + +/// Run a callback function if the given bool is `False`, otherwise return a +/// default value. +/// +/// With a `use` expression this function can simulate the early-return pattern +/// found in some other programming languages. +/// +/// In a procedural language: +/// +/// ```js +/// if (predicate) return value; +/// // ... +/// ``` +/// +/// In Gleam with a `use` expression: +/// +/// ```gleam +/// use <- guard(when: predicate, return: value) +/// // ... +/// ``` +/// +/// Like everything in Gleam `use` is an expression, so it short circuits the +/// current block, not the entire function. As a result you can assign the value +/// to a variable: +/// +/// ```gleam +/// let x = { +/// use <- guard(when: predicate, return: value) +/// // ... +/// } +/// ``` +/// +/// Note that unlike in procedural languages the `return` value is evaluated +/// even when the predicate is `False`, so it is advisable not to perform +/// expensive computation nor side-effects there. +/// +/// +/// ## Examples +/// +/// ```gleam +/// let name = "" +/// use <- guard(when: name == "", return: "Welcome!") +/// "Hello, " <> name +/// // -> "Welcome!" +/// ``` +/// +/// ```gleam +/// let name = "Kamaka" +/// use <- guard(when: name == "", return: "Welcome!") +/// "Hello, " <> name +/// // -> "Hello, Kamaka" +/// ``` +/// +pub fn guard( + when requirement: Bool, + return consequence: a, + otherwise alternative: fn() -> a, +) -> a { + case requirement { + True -> consequence + False -> alternative() + } +} + +/// Runs a callback function if the given bool is `True`, otherwise runs an +/// alternative callback function. +/// +/// Useful when further computation should be delayed regardless of the given +/// bool's value. +/// +/// See [`guard`](#guard) for more info. +/// +/// ## Examples +/// +/// ```gleam +/// let name = "Kamaka" +/// let inquiry = fn() { "How may we address you?" } +/// use <- lazy_guard(when: name == "", return: inquiry) +/// "Hello, " <> name +/// // -> "Hello, Kamaka" +/// ``` +/// +/// ```gleam +/// import gleam/int +/// +/// let name = "" +/// let greeting = fn() { "Hello, " <> name } +/// use <- lazy_guard(when: name == "", otherwise: greeting) +/// let number = int.random(99) +/// let name = "User " <> int.to_string(number) +/// "Welcome, " <> name +/// // -> "Welcome, User 54" +/// ``` +/// +pub fn lazy_guard( + when requirement: Bool, + return consequence: fn() -> a, + otherwise alternative: fn() -> a, +) -> a { + case requirement { + True -> consequence() + False -> alternative() + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam b/build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam new file mode 100644 index 0000000..0418644 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam @@ -0,0 +1,190 @@ +//// `BytesTree` is a type used for efficiently building binary content to be +//// written to a file or a socket. Internally it is represented as tree so to +//// append or prepend to a bytes tree is a constant time operation that +//// allocates a new node in the tree without copying any of the content. When +//// writing to an output stream the tree is traversed and the content is sent +//// directly rather than copying it into a single buffer beforehand. +//// +//// If we append one bit array to another the bit arrays must be copied to a +//// new location in memory so that they can sit together. This behaviour +//// enables efficient reading of the data but copying can be expensive, +//// especially if we want to join many bit arrays together. +//// +//// BytesTree is different in that it can be joined together in constant +//// time using minimal memory, and then can be efficiently converted to a +//// bit array using the `to_bit_array` function. +//// +//// Byte trees are always byte aligned, so that a number of bits that is not +//// divisible by 8 will be padded with 0s. +//// +//// On Erlang this type is compatible with Erlang's iolists. + +import gleam/bit_array +import gleam/list +import gleam/string_tree.{type StringTree} + +pub opaque type BytesTree { + Bytes(BitArray) + Text(StringTree) + Many(List(BytesTree)) +} + +/// Create an empty `BytesTree`. Useful as the start of a pipe chaining many +/// trees together. +/// +pub fn new() -> BytesTree { + concat([]) +} + +/// Prepends a bit array to the start of a bytes tree. +/// +/// Runs in constant time. +/// +pub fn prepend(to second: BytesTree, prefix first: BitArray) -> BytesTree { + append_tree(from_bit_array(first), second) +} + +/// Appends a bit array to the end of a bytes tree. +/// +/// Runs in constant time. +/// +pub fn append(to first: BytesTree, suffix second: BitArray) -> BytesTree { + append_tree(first, from_bit_array(second)) +} + +/// Prepends a bytes tree onto the start of another. +/// +/// Runs in constant time. +/// +pub fn prepend_tree(to second: BytesTree, prefix first: BytesTree) -> BytesTree { + append_tree(first, second) +} + +/// Appends a bytes tree onto the end of another. +/// +/// Runs in constant time. +/// +@external(erlang, "gleam_stdlib", "iodata_append") +pub fn append_tree(to first: BytesTree, suffix second: BytesTree) -> BytesTree { + case second { + Many(trees) -> Many([first, ..trees]) + Text(_) | Bytes(_) -> Many([first, second]) + } +} + +/// Prepends a string onto the start of a bytes tree. +/// +/// Runs in constant time when running on Erlang. +/// Runs in linear time with the length of the string otherwise. +/// +pub fn prepend_string(to second: BytesTree, prefix first: String) -> BytesTree { + append_tree(from_string(first), second) +} + +/// Appends a string onto the end of a bytes tree. +/// +/// Runs in constant time when running on Erlang. +/// Runs in linear time with the length of the string otherwise. +/// +pub fn append_string(to first: BytesTree, suffix second: String) -> BytesTree { + append_tree(first, from_string(second)) +} + +/// Joins a list of bytes trees into a single one. +/// +/// Runs in constant time. +/// +@external(erlang, "gleam_stdlib", "identity") +pub fn concat(trees: List(BytesTree)) -> BytesTree { + Many(trees) +} + +/// Joins a list of bit arrays into a single bytes tree. +/// +/// Runs in constant time. +/// +pub fn concat_bit_arrays(bits: List(BitArray)) -> BytesTree { + bits + |> list.map(fn(b) { from_bit_array(b) }) + |> concat() +} + +/// Creates a new bytes tree from a string. +/// +/// Runs in constant time when running on Erlang. +/// Runs in linear time otherwise. +/// +@external(erlang, "gleam_stdlib", "wrap_list") +pub fn from_string(string: String) -> BytesTree { + Text(string_tree.from_string(string)) +} + +/// Creates a new bytes tree from a string tree. +/// +/// Runs in constant time when running on Erlang. +/// Runs in linear time otherwise. +/// +@external(erlang, "gleam_stdlib", "wrap_list") +pub fn from_string_tree(tree: string_tree.StringTree) -> BytesTree { + Text(tree) +} + +/// Creates a new bytes tree from a bit array. +/// +/// Runs in constant time. +/// +pub fn from_bit_array(bits: BitArray) -> BytesTree { + bits + |> bit_array.pad_to_bytes + |> wrap_list +} + +@external(erlang, "gleam_stdlib", "wrap_list") +fn wrap_list(bits: BitArray) -> BytesTree { + Bytes(bits) +} + +/// Turns a bytes tree into a bit array. +/// +/// Runs in linear time. +/// +/// When running on Erlang this function is implemented natively by the +/// virtual machine and is highly optimised. +/// +@external(erlang, "erlang", "list_to_bitstring") +pub fn to_bit_array(tree: BytesTree) -> BitArray { + [[tree]] + |> to_list([]) + |> list.reverse + |> bit_array.concat +} + +fn to_list(stack: List(List(BytesTree)), acc: List(BitArray)) -> List(BitArray) { + case stack { + [] -> acc + + [[], ..remaining_stack] -> to_list(remaining_stack, acc) + + [[Bytes(bits), ..rest], ..remaining_stack] -> + to_list([rest, ..remaining_stack], [bits, ..acc]) + + [[Text(tree), ..rest], ..remaining_stack] -> { + let bits = bit_array.from_string(string_tree.to_string(tree)) + to_list([rest, ..remaining_stack], [bits, ..acc]) + } + + [[Many(trees), ..rest], ..remaining_stack] -> + to_list([trees, rest, ..remaining_stack], acc) + } +} + +/// Returns the size of the bytes tree's content in bytes. +/// +/// Runs in linear time. +/// +@external(erlang, "erlang", "iolist_size") +pub fn byte_size(tree: BytesTree) -> Int { + [[tree]] + |> to_list([]) + |> list.fold(0, fn(acc, bits) { bit_array.byte_size(bits) + acc }) +} diff --git a/build/packages/gleam_stdlib/src/gleam/dict.gleam b/build/packages/gleam_stdlib/src/gleam/dict.gleam new file mode 100644 index 0000000..2942727 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/dict.gleam @@ -0,0 +1,548 @@ +import gleam/option.{type Option} + +/// A dictionary of keys and values. +/// +/// Any type can be used for the keys and values of a dict, but all the keys +/// must be of the same type and all the values must be of the same type. +/// +/// Each key can only be present in a dict once. +/// +/// Dicts are not ordered in any way, and any unintentional ordering is not to +/// be relied upon in your code as it may change in future versions of Erlang +/// or Gleam. +/// +/// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more +/// information. +/// +pub type Dict(key, value) + +/// Determines the number of key-value pairs in the dict. +/// This function runs in constant time and does not need to iterate the dict. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> size +/// // -> 0 +/// ``` +/// +/// ```gleam +/// new() |> insert("key", "value") |> size +/// // -> 1 +/// ``` +/// +@external(erlang, "maps", "size") +@external(javascript, "../gleam_stdlib.mjs", "map_size") +pub fn size(dict: Dict(k, v)) -> Int + +/// Determines whether or not the dict is empty. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> is_empty +/// // -> True +/// ``` +/// +/// ```gleam +/// new() |> insert("b", 1) |> is_empty +/// // -> False +/// ``` +/// +pub fn is_empty(dict: Dict(k, v)) -> Bool { + size(dict) == 0 +} + +/// Converts the dict to a list of 2-element tuples `#(key, value)`, one for +/// each key-value pair in the dict. +/// +/// The tuples in the list have no specific order. +/// +/// ## Examples +/// +/// Calling `to_list` on an empty `dict` returns an empty list. +/// +/// ```gleam +/// new() |> to_list +/// // -> [] +/// ``` +/// +/// The ordering of elements in the resulting list is an implementation detail +/// that should not be relied upon. +/// +/// ```gleam +/// new() |> insert("b", 1) |> insert("a", 0) |> insert("c", 2) |> to_list +/// // -> [#("a", 0), #("b", 1), #("c", 2)] +/// ``` +/// +@external(erlang, "maps", "to_list") +@external(javascript, "../gleam_stdlib.mjs", "map_to_list") +pub fn to_list(dict: Dict(k, v)) -> List(#(k, v)) + +/// Converts a list of 2-element tuples `#(key, value)` to a dict. +/// +/// If two tuples have the same key the last one in the list will be the one +/// that is present in the dict. +/// +@external(erlang, "maps", "from_list") +pub fn from_list(list: List(#(k, v))) -> Dict(k, v) { + from_list_loop(list, new()) +} + +fn from_list_loop( + over list: List(#(k, v)), + from initial: Dict(k, v), +) -> Dict(k, v) { + case list { + [] -> initial + [#(key, value), ..rest] -> from_list_loop(rest, insert(initial, key, value)) + } +} + +/// Determines whether or not a value present in the dict for a given key. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> insert("a", 0) |> has_key("a") +/// // -> True +/// ``` +/// +/// ```gleam +/// new() |> insert("a", 0) |> has_key("b") +/// // -> False +/// ``` +/// +pub fn has_key(dict: Dict(k, v), key: k) -> Bool { + do_has_key(key, dict) +} + +@external(erlang, "maps", "is_key") +fn do_has_key(key: k, dict: Dict(k, v)) -> Bool { + get(dict, key) != Error(Nil) +} + +/// Creates a fresh dict that contains no values. +/// +@external(erlang, "maps", "new") +@external(javascript, "../gleam_stdlib.mjs", "new_map") +pub fn new() -> Dict(k, v) + +/// Fetches a value from a dict for a given key. +/// +/// The dict may not have a value for the key, so the value is wrapped in a +/// `Result`. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> insert("a", 0) |> get("a") +/// // -> Ok(0) +/// ``` +/// +/// ```gleam +/// new() |> insert("a", 0) |> get("b") +/// // -> Error(Nil) +/// ``` +/// +@external(erlang, "gleam_stdlib", "map_get") +@external(javascript, "../gleam_stdlib.mjs", "map_get") +pub fn get(from: Dict(k, v), get: k) -> Result(v, Nil) + +/// Inserts a value into the dict with the given key. +/// +/// If the dict already has a value for the given key then the value is +/// replaced with the new value. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> insert("a", 0) +/// // -> from_list([#("a", 0)]) +/// ``` +/// +/// ```gleam +/// new() |> insert("a", 0) |> insert("a", 5) +/// // -> from_list([#("a", 5)]) +/// ``` +/// +pub fn insert(into dict: Dict(k, v), for key: k, insert value: v) -> Dict(k, v) { + do_insert(key, value, dict) +} + +@external(erlang, "maps", "put") +@external(javascript, "../gleam_stdlib.mjs", "map_insert") +fn do_insert(key: k, value: v, dict: Dict(k, v)) -> Dict(k, v) + +/// Updates all values in a given dict by calling a given function on each key +/// and value. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#(3, 3), #(2, 4)]) +/// |> map_values(fn(key, value) { key * value }) +/// // -> from_list([#(3, 9), #(2, 8)]) +/// ``` +/// +pub fn map_values(in dict: Dict(k, v), with fun: fn(k, v) -> a) -> Dict(k, a) { + do_map_values(fun, dict) +} + +@external(erlang, "maps", "map") +fn do_map_values(f: fn(k, v) -> a, dict: Dict(k, v)) -> Dict(k, a) { + let f = fn(dict, k, v) { insert(dict, k, f(k, v)) } + fold(dict, from: new(), with: f) +} + +/// Gets a list of all keys in a given dict. +/// +/// Dicts are not ordered so the keys are not returned in any specific order. Do +/// not write code that relies on the order keys are returned by this function +/// as it may change in later versions of Gleam or Erlang. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> keys +/// // -> ["a", "b"] +/// ``` +/// +@external(erlang, "maps", "keys") +pub fn keys(dict: Dict(k, v)) -> List(k) { + do_keys_loop(to_list(dict), []) +} + +fn do_keys_loop(list: List(#(k, v)), acc: List(k)) -> List(k) { + case list { + [] -> reverse_and_concat(acc, []) + [#(key, _value), ..rest] -> do_keys_loop(rest, [key, ..acc]) + } +} + +fn reverse_and_concat(remaining: List(a), accumulator: List(a)) -> List(a) { + case remaining { + [] -> accumulator + [first, ..rest] -> reverse_and_concat(rest, [first, ..accumulator]) + } +} + +/// Gets a list of all values in a given dict. +/// +/// Dicts are not ordered so the values are not returned in any specific order. Do +/// not write code that relies on the order values are returned by this function +/// as it may change in later versions of Gleam or Erlang. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> values +/// // -> [0, 1] +/// ``` +/// +@external(erlang, "maps", "values") +pub fn values(dict: Dict(k, v)) -> List(v) { + let list_of_pairs = to_list(dict) + do_values_loop(list_of_pairs, []) +} + +fn do_values_loop(list: List(#(k, v)), acc: List(v)) -> List(v) { + case list { + [] -> reverse_and_concat(acc, []) + [#(_key, value), ..rest] -> do_values_loop(rest, [value, ..acc]) + } +} + +/// Creates a new dict from a given dict, minus any entries that a given function +/// returns `False` for. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) +/// |> filter(fn(key, value) { value != 0 }) +/// // -> from_list([#("b", 1)]) +/// ``` +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) +/// |> filter(fn(key, value) { True }) +/// // -> from_list([#("a", 0), #("b", 1)]) +/// ``` +/// +pub fn filter( + in dict: Dict(k, v), + keeping predicate: fn(k, v) -> Bool, +) -> Dict(k, v) { + do_filter(predicate, dict) +} + +@external(erlang, "maps", "filter") +fn do_filter(f: fn(k, v) -> Bool, dict: Dict(k, v)) -> Dict(k, v) { + let insert = fn(dict, k, v) { + case f(k, v) { + True -> insert(dict, k, v) + False -> dict + } + } + + fold(dict, from: new(), with: insert) +} + +/// Creates a new dict from a given dict, only including any entries for which the +/// keys are in a given list. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) +/// |> take(["b"]) +/// // -> from_list([#("b", 1)]) +/// ``` +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) +/// |> take(["a", "b", "c"]) +/// // -> from_list([#("a", 0), #("b", 1)]) +/// ``` +/// +pub fn take(from dict: Dict(k, v), keeping desired_keys: List(k)) -> Dict(k, v) { + do_take(desired_keys, dict) +} + +@external(erlang, "maps", "with") +fn do_take(desired_keys: List(k), dict: Dict(k, v)) -> Dict(k, v) { + do_take_loop(dict, desired_keys, new()) +} + +fn do_take_loop( + dict: Dict(k, v), + desired_keys: List(k), + acc: Dict(k, v), +) -> Dict(k, v) { + let insert = fn(taken, key) { + case get(dict, key) { + Ok(value) -> insert(taken, key, value) + Error(_) -> taken + } + } + case desired_keys { + [] -> acc + [first, ..rest] -> do_take_loop(dict, rest, insert(acc, first)) + } +} + +/// Creates a new dict from a pair of given dicts by combining their entries. +/// +/// If there are entries with the same keys in both dicts the entry from the +/// second dict takes precedence. +/// +/// ## Examples +/// +/// ```gleam +/// let a = from_list([#("a", 0), #("b", 1)]) +/// let b = from_list([#("b", 2), #("c", 3)]) +/// merge(a, b) +/// // -> from_list([#("a", 0), #("b", 2), #("c", 3)]) +/// ``` +/// +@external(erlang, "maps", "merge") +pub fn merge(into dict: Dict(k, v), from new_entries: Dict(k, v)) -> Dict(k, v) { + new_entries + |> to_list + |> fold_inserts(dict) +} + +fn fold_inserts(new_entries: List(#(k, v)), dict: Dict(k, v)) -> Dict(k, v) { + case new_entries { + [] -> dict + [first, ..rest] -> fold_inserts(rest, insert_pair(dict, first)) + } +} + +fn insert_pair(dict: Dict(k, v), pair: #(k, v)) -> Dict(k, v) { + insert(dict, pair.0, pair.1) +} + +/// Creates a new dict from a given dict with all the same entries except for the +/// one with a given key, if it exists. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> delete("a") +/// // -> from_list([#("b", 1)]) +/// ``` +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> delete("c") +/// // -> from_list([#("a", 0), #("b", 1)]) +/// ``` +/// +pub fn delete(from dict: Dict(k, v), delete key: k) -> Dict(k, v) { + do_delete(key, dict) +} + +@external(erlang, "maps", "remove") +@external(javascript, "../gleam_stdlib.mjs", "map_remove") +fn do_delete(a: k, b: Dict(k, v)) -> Dict(k, v) + +/// Creates a new dict from a given dict with all the same entries except any with +/// keys found in a given list. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> drop(["a"]) +/// // -> from_list([#("b", 1)]) +/// ``` +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> drop(["c"]) +/// // -> from_list([#("a", 0), #("b", 1)]) +/// ``` +/// +/// ```gleam +/// from_list([#("a", 0), #("b", 1)]) |> drop(["a", "b", "c"]) +/// // -> from_list([]) +/// ``` +/// +pub fn drop(from dict: Dict(k, v), drop disallowed_keys: List(k)) -> Dict(k, v) { + case disallowed_keys { + [] -> dict + [first, ..rest] -> drop(delete(dict, first), rest) + } +} + +/// Creates a new dict with one entry inserted or updated using a given function. +/// +/// If there was not an entry in the dict for the given key then the function +/// gets `None` as its argument, otherwise it gets `Some(value)`. +/// +/// ## Example +/// +/// ```gleam +/// let dict = from_list([#("a", 0)]) +/// let increment = fn(x) { +/// case x { +/// Some(i) -> i + 1 +/// None -> 0 +/// } +/// } +/// +/// upsert(dict, "a", increment) +/// // -> from_list([#("a", 1)]) +/// +/// upsert(dict, "b", increment) +/// // -> from_list([#("a", 0), #("b", 0)]) +/// ``` +/// +pub fn upsert( + in dict: Dict(k, v), + update key: k, + with fun: fn(Option(v)) -> v, +) -> Dict(k, v) { + case get(dict, key) { + Ok(value) -> insert(dict, key, fun(option.Some(value))) + Error(_) -> insert(dict, key, fun(option.None)) + } +} + +/// Combines all entries into a single value by calling a given function on each +/// one. +/// +/// Dicts are not ordered so the values are not returned in any specific order. Do +/// not write code that relies on the order entries are used by this function +/// as it may change in later versions of Gleam or Erlang. +/// +/// # Examples +/// +/// ```gleam +/// let dict = from_list([#("a", 1), #("b", 3), #("c", 9)]) +/// fold(dict, 0, fn(accumulator, key, value) { accumulator + value }) +/// // -> 13 +/// ``` +/// +/// ```gleam +/// import gleam/string +/// +/// let dict = from_list([#("a", 1), #("b", 3), #("c", 9)]) +/// fold(dict, "", fn(accumulator, key, value) { +/// string.append(accumulator, key) +/// }) +/// // -> "abc" +/// ``` +/// +pub fn fold( + over dict: Dict(k, v), + from initial: acc, + with fun: fn(acc, k, v) -> acc, +) -> acc { + fold_loop(to_list(dict), initial, fun) +} + +fn fold_loop( + list: List(#(k, v)), + initial: acc, + fun: fn(acc, k, v) -> acc, +) -> acc { + case list { + [] -> initial + [#(k, v), ..rest] -> fold_loop(rest, fun(initial, k, v), fun) + } +} + +/// Calls a function for each key and value in a dict, discarding the return +/// value. +/// +/// Useful for producing a side effect for every item of a dict. +/// +/// ```gleam +/// import gleam/io +/// +/// let dict = from_list([#("a", "apple"), #("b", "banana"), #("c", "cherry")]) +/// +/// each(dict, fn(k, v) { +/// io.println(key <> " => " <> value) +/// }) +/// // -> Nil +/// // a => apple +/// // b => banana +/// // c => cherry +/// ``` +/// +/// The order of elements in the iteration is an implementation detail that +/// should not be relied upon. +/// +pub fn each(dict: Dict(k, v), fun: fn(k, v) -> a) -> Nil { + fold(dict, Nil, fn(nil, k, v) { + fun(k, v) + nil + }) +} + +/// Creates a new dict from a pair of given dicts by combining their entries. +/// +/// If there are entries with the same keys in both dicts the given function is +/// used to determine the new value to use in the resulting dict. +/// +/// ## Examples +/// +/// ```gleam +/// let a = from_list([#("a", 0), #("b", 1)]) +/// let b = from_list([#("a", 2), #("c", 3)]) +/// combine(a, b, fn(one, other) { one + other }) +/// // -> from_list([#("a", 2), #("b", 1), #("c", 3)]) +/// ``` +/// +pub fn combine( + dict: Dict(k, v), + other: Dict(k, v), + with fun: fn(v, v) -> v, +) -> Dict(k, v) { + use acc, key, value <- fold(over: dict, from: other) + case get(acc, key) { + Ok(other_value) -> insert(acc, key, fun(value, other_value)) + Error(_) -> insert(acc, key, value) + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/dynamic.gleam b/build/packages/gleam_stdlib/src/gleam/dynamic.gleam new file mode 100644 index 0000000..9939d56 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/dynamic.gleam @@ -0,0 +1,100 @@ +import gleam/dict + +/// `Dynamic` data is data that we don't know the type of yet. +/// We likely get data like this from interop with Erlang, or from +/// IO with the outside world. +/// +/// This module contains code for forming dynamic data, and the +/// `gleam/dynamic/decode` module contains code for turning dynamic data back +/// into Gleam data with known types. You will likely mostly use the other +/// module in your projects. +/// +/// The exact runtime representation of dynamic values will depend on the +/// compilation target used. +/// +pub type Dynamic + +/// Return a string indicating the type of the dynamic value. +/// +/// This function may be useful for constructing error messages or logs. If you +/// want to turn dynamic data into well typed data then you want the +/// `gleam/dynamic/decode` module. +/// +/// ```gleam +/// classify(from("Hello")) +/// // -> "String" +/// ``` +/// +@external(erlang, "gleam_stdlib", "classify_dynamic") +@external(javascript, "../gleam_stdlib.mjs", "classify_dynamic") +pub fn classify(data: Dynamic) -> String + +/// Create a dynamic value from a bool. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn bool(a: Bool) -> Dynamic + +/// Create a dynamic value from a string. +/// +/// On Erlang this will be a binary string rather than a character list. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn string(a: String) -> Dynamic + +/// Create a dynamic value from a float. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn float(a: Float) -> Dynamic + +/// Create a dynamic value from an int. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn int(a: Int) -> Dynamic + +/// Create a dynamic value from a bit array. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn bit_array(a: BitArray) -> Dynamic + +/// Create a dynamic value from a list. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn list(a: List(Dynamic)) -> Dynamic + +/// Create a dynamic value from a list, converting it to a sequential runtime +/// format rather than the regular list format. +/// +/// On Erlang this will be a tuple, on JavaScript this will be an array. +/// +@external(erlang, "erlang", "list_to_tuple") +@external(javascript, "../gleam_stdlib.mjs", "list_to_array") +pub fn array(a: List(Dynamic)) -> Dynamic + +/// Create a dynamic value made an unordered series of keys and values, where +/// the keys are unique. +/// +/// On Erlang this will be a map, on JavaScript this will be a Gleam dict +/// object. +/// +pub fn properties(entries: List(#(Dynamic, Dynamic))) -> Dynamic { + cast(dict.from_list(entries)) +} + +/// A dynamic value representing nothing. +/// +/// On Erlang this will be the atom `nil`, on JavaScript this will be +/// `undefined`. +/// +pub fn nil() -> Dynamic { + cast(Nil) +} + +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +fn cast(a: anything) -> Dynamic diff --git a/build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam b/build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam new file mode 100644 index 0000000..7618331 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam @@ -0,0 +1,1057 @@ +//// The `Dynamic` type is used to represent dynamically typed data. That is, data +//// that we don't know the precise type of yet, so we need to introspect the data to +//// see if it is of the desired type before we can use it. Typically data like this +//// would come from user input or from untyped languages such as Erlang or JavaScript. +//// +//// This module provides the `Decoder` type and associated functions, which provides +//// a type-safe and composable way to convert dynamic data into some desired type, +//// or into errors if the data doesn't have the desired structure. +//// +//// The `Decoder` type is generic and has 1 type parameter, which is the type that +//// it attempts to decode. A `Decoder(String)` can be used to decode strings, and a +//// `Decoder(Option(Int))` can be used to decode `Option(Int)`s +//// +//// Decoders work using _runtime reflection_ and the data structures of the target +//// platform. Differences between Erlang and JavaScript data structures may impact +//// your decoders, so it is important to test your decoders on all supported +//// platforms. +//// +//// The decoding technique used by this module was inspired by Juraj Petráš' +//// [Toy](https://github.com/Hackder/toy), Go's `encoding/json`, and Elm's +//// `Json.Decode`. Thank you to them! +//// +//// # Examples +//// +//// Dynamic data may come from various sources and so many different syntaxes could +//// be used to describe or construct them. In these examples a pseudocode +//// syntax is used to describe the data. +//// +//// ## Simple types +//// +//// This module defines decoders for simple data types such as [`string`](#string), +//// [`int`](#int), [`float`](#float), [`bit_array`](#bit_array), and [`bool`](#bool). +//// +//// ```gleam +//// // Data: +//// // "Hello, Joe!" +//// +//// let result = decode.run(data, decode.string) +//// assert result == Ok("Hello, Joe!") +//// ``` +//// +//// ## Lists +//// +//// The [`list`](#list) decoder decodes `List`s. To use it you must construct it by +//// passing in another decoder into the `list` function, which is the decoder that +//// is to be used for the elements of the list, type checking both the list and its +//// elements. +//// +//// ```gleam +//// // Data: +//// // [1, 2, 3, 4] +//// +//// let result = decode.run(data, decode.list(decode.int)) +//// assert result == Ok([1, 2, 3, 4]) +//// ``` +//// +//// On Erlang this decoder can decode from lists, and on JavaScript it can +//// decode from lists as well as JavaScript arrays. +//// +//// ## Options +//// +//// The [`optional`](#optional) decoder is used to decode values that may or may not +//// be present. In other environment these might be called "nullable" values. +//// +//// Like the `list` decoder, the `optional` decoder takes another decoder, +//// which is used to decode the value if it is present. +//// +//// ```gleam +//// // Data: +//// // 12.45 +//// +//// let result = decode.run(data, decode.optional(decode.float)) +//// assert result == Ok(option.Some(12.45)) +//// ``` +//// ```gleam +//// // Data: +//// // null +//// +//// let result = decode.run(data, decode.optional(decode.int)) +//// assert result == Ok(option.None) +//// ``` +//// +//// This decoder knows how to handle multiple different runtime representations of +//// absent values, including `Nil`, `None`, `null`, and `undefined`. +//// +//// ## Dicts +//// +//// The [`dict`](#dict) decoder decodes `Dicts` and contains two other decoders, one +//// for the keys, one for the values. +//// +//// ```gleam +//// // Data: +//// // { "Lucy" -> 10, "Nubi" -> 20 } +//// +//// let result = decode.run(data, decode.dict(decode.string, decode.int)) +//// assert result == Ok(dict.from_list([ +//// #("Lucy", 10), +//// #("Nubi", 20), +//// ])) +//// ``` +//// +//// ## Indexing objects +//// +//// The [`at`](#at) decoder can be used to decode a value that is nested within +//// key-value containers such as Gleam dicts, Erlang maps, or JavaScript objects. +//// +//// ```gleam +//// // Data: +//// // { "one" -> { "two" -> 123 } } +//// +//// let result = decode.run(data, decode.at(["one", "two"], decode.int)) +//// assert result == Ok(123) +//// ``` +//// +//// ## Indexing arrays +//// +//// If you use ints as keys then the [`at`](#at) decoder can be used to index into +//// array-like containers such as Gleam or Erlang tuples, or JavaScript arrays. +//// +//// ```gleam +//// // Data: +//// // ["one", "two", "three"] +//// +//// let result = decode.run(data, decode.at([1], decode.string)) +//// assert result == Ok("two") +//// ``` +//// +//// ## Records +//// +//// Decoding records from dynamic data is more complex and requires combining a +//// decoder for each field and a special constructor that builds your records with +//// the decoded field values. +//// +//// ```gleam +//// // Data: +//// // { +//// // "score" -> 180, +//// // "name" -> "Mel Smith", +//// // "is-admin" -> false, +//// // "enrolled" -> true, +//// // "colour" -> "Red", +//// // } +//// +//// let decoder = { +//// use name <- decode.field("name", decode.string) +//// use score <- decode.field("score", decode.int) +//// use colour <- decode.field("colour", decode.string) +//// use enrolled <- decode.field("enrolled", decode.bool) +//// decode.success(Player(name:, score:, colour:, enrolled:)) +//// } +//// +//// let result = decode.run(data, decoder) +//// assert result == Ok(Player("Mel Smith", 180, "Red", True)) +//// ``` +//// +//// ## Enum variants +//// +//// Imagine you have a custom type where all the variants do not contain any values. +//// +//// ```gleam +//// pub type PocketMonsterType { +//// Fire +//// Water +//// Grass +//// Electric +//// } +//// ``` +//// +//// You might choose to encode these variants as strings, `"fire"` for `Fire`, +//// `"water"` for `Water`, and so on. To decode them you'll need to decode the dynamic +//// data as a string, but then you'll need to decode it further still as not all +//// strings are valid values for the enum. This can be done with the `then` +//// function, which enables running a second decoder after the first one +//// succeeds. +//// +//// ```gleam +//// let decoder = { +//// use decoded_string <- decode.then(decode.string) +//// case decoded_string { +//// // Return succeeding decoders for valid strings +//// "fire" -> decode.success(Fire) +//// "water" -> decode.success(Water) +//// "grass" -> decode.success(Grass) +//// "electric" -> decode.success(Electric) +//// // Return a failing decoder for any other strings +//// _ -> decode.failure(Fire, "PocketMonsterType") +//// } +//// } +//// +//// let result = decode.run(dynamic.from("water"), decoder) +//// assert result == Ok(Water) +//// +//// let result = decode.run(dynamic.from("wobble"), decoder) +//// assert result == Error([DecodeError("PocketMonsterType", "String", [])]) +//// ``` +//// +//// ## Record variants +//// +//// Decoding type variants that contain other values is done by combining the +//// techniques from the "enum variants" and "records" examples. Imagine you have +//// this custom type that you want to decode: +//// +//// ```gleam +//// pub type PocketMonsterPerson { +//// Trainer(name: String, badge_count: Int) +//// GymLeader(name: String, speciality: PocketMonsterType) +//// } +//// ``` +//// And you would like to be able to decode these from dynamic data like this: +//// ```erlang +//// { +//// "type" -> "trainer", +//// "name" -> "Ash", +//// "badge-count" -> 1, +//// } +//// ``` +//// ```erlang +//// { +//// "type" -> "gym-leader", +//// "name" -> "Misty", +//// "speciality" -> "water", +//// } +//// ``` +//// +//// Notice how both documents have a `"type"` field, which is used to indicate which +//// variant the data is for. +//// +//// First, define decoders for each of the variants: +//// +//// ```gleam +//// let trainer_decoder = { +//// use name <- decode.field("name", decode.string) +//// use badge_count <- decode.field("badge-count", decode.int) +//// decode.success(Trainer(name, badge_count)) +//// } +//// +//// let gym_leader_decoder = { +//// use name <- decode.field("name", decode.string) +//// use speciality <- decode.field("speciality", pocket_monster_type_decoder) +//// decode.success(GymLeader(name, speciality)) +//// } +//// ``` +//// +//// A third decoder can be used to extract and decode the `"type"` field, and the +//// expression can evaluate to whichever decoder is suitable for the document. +//// +//// ```gleam +//// // Data: +//// // { +//// // "type" -> "gym-leader", +//// // "name" -> "Misty", +//// // "speciality" -> "water", +//// // } +//// +//// let decoder = { +//// use tag <- decode.field("type", decode.string) +//// case tag { +//// "gym-leader" -> gym_leader_decoder +//// _ -> trainer_decoder +//// } +//// } +//// +//// let result = decode.run(data, decoder) +//// assert result == Ok(GymLeader("Misty", Water)) +//// ``` + +import gleam/bit_array +import gleam/dict.{type Dict} +import gleam/dynamic +import gleam/int +import gleam/list +import gleam/option.{type Option, None, Some} + +/// `Dynamic` data is data that we don't know the type of yet, originating from +/// external untyped systems. +/// +/// You should never be converting your well typed data to dynamic data. +/// +pub type Dynamic = + dynamic.Dynamic + +/// Error returned when unexpected data is encountered +/// +pub type DecodeError { + DecodeError(expected: String, found: String, path: List(String)) +} + +/// A decoder is a value that can be used to turn dynamically typed `Dynamic` +/// data into typed data using the `run` function. +/// +/// Several smaller decoders can be combined to make larger decoders using +/// functions such as `list` and `field`. +/// +pub opaque type Decoder(t) { + Decoder(function: fn(Dynamic) -> #(t, List(DecodeError))) +} + +/// The same as [`field`](#field), except taking a path to the value rather +/// than a field name. +/// +/// This function will index into dictionaries with any key type, and if the key is +/// an int then it'll also index into Erlang tuples and JavaScript arrays, and +/// the first eight elements of Gleam lists. +/// +/// # Examples +/// +/// ```gleam +/// let data = dynamic.from(dict.from_list([ +/// #("data", dict.from_list([ +/// #("email", "lucy@example.com"), +/// #("name", "Lucy"), +/// ])) +/// ])) +/// +/// let decoder = { +/// use name <- decode.subfield(["data", "name"], decode.string) +/// use email <- decode.subfield(["data", "email"], decode.string) +/// decode.success(SignUp(name: name, email: email)) +/// } +/// let result = decode.run(data, decoder) +/// assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com")) +/// ``` +/// +pub fn subfield( + field_path: List(name), + field_decoder: Decoder(t), + next: fn(t) -> Decoder(final), +) -> Decoder(final) { + Decoder(function: fn(data) { + let #(out, errors1) = + index(field_path, [], field_decoder.function, data, fn(data, position) { + let #(default, _) = field_decoder.function(data) + #(default, [DecodeError("Field", "Nothing", [])]) + |> push_path(list.reverse(position)) + }) + let #(out, errors2) = next(out).function(data) + #(out, list.append(errors1, errors2)) + }) +} + +/// Run a decoder on a `Dynamic` value, decoding the value if it is of the +/// desired type, or returning errors. +/// +/// # Examples +/// +/// ```gleam +/// let decoder = { +/// use name <- decode.field("email", decode.string) +/// use email <- decode.field("password", decode.string) +/// decode.success(SignUp(name: name, email: email)) +/// } +/// +/// decode.run(data, decoder) +/// ``` +/// +pub fn run(data: Dynamic, decoder: Decoder(t)) -> Result(t, List(DecodeError)) { + let #(maybe_invalid_data, errors) = decoder.function(data) + case errors { + [] -> Ok(maybe_invalid_data) + [_, ..] -> Error(errors) + } +} + +/// A decoder that decodes a value that is nested within other values. For +/// example, decoding a value that is within some deeply nested JSON objects. +/// +/// This function will index into dictionaries with any key type, and if the key is +/// an int then it'll also index into Erlang tuples and JavaScript arrays, and +/// the first eight elements of Gleam lists. +/// +/// # Examples +/// +/// ```gleam +/// let decoder = decode.at(["one", "two"], decode.int) +/// +/// let data = dynamic.from(dict.from_list([ +/// #("one", dict.from_list([ +/// #("two", 1000), +/// ])), +/// ])) +/// +/// +/// decode.run(data, decoder) +/// // -> Ok(1000) +/// ``` +/// +/// ```gleam +/// dynamic.from(Nil) +/// |> decode.run(decode.optional(decode.int)) +/// // -> Ok(option.None) +/// ``` +/// +pub fn at(path: List(segment), inner: Decoder(a)) -> Decoder(a) { + Decoder(function: fn(data) { + index(path, [], inner.function, data, fn(data, position) { + let #(default, _) = inner.function(data) + #(default, [DecodeError("Field", "Nothing", [])]) + |> push_path(list.reverse(position)) + }) + }) +} + +fn index( + path: List(a), + position: List(a), + inner: fn(Dynamic) -> #(b, List(DecodeError)), + data: Dynamic, + handle_miss: fn(Dynamic, List(a)) -> #(b, List(DecodeError)), +) -> #(b, List(DecodeError)) { + case path { + [] -> { + inner(data) + |> push_path(list.reverse(position)) + } + + [key, ..path] -> { + case bare_index(data, key) { + Ok(Some(data)) -> { + index(path, [key, ..position], inner, data, handle_miss) + } + Ok(None) -> { + handle_miss(data, [key, ..position]) + } + Error(kind) -> { + let #(default, _) = inner(data) + #(default, [DecodeError(kind, dynamic.classify(data), [])]) + |> push_path(list.reverse(position)) + } + } + } + } +} + +@external(erlang, "gleam_stdlib", "index") +@external(javascript, "../../gleam_stdlib.mjs", "index") +fn bare_index(data: Dynamic, key: anything) -> Result(Option(Dynamic), String) + +fn push_path( + layer: #(t, List(DecodeError)), + path: List(key), +) -> #(t, List(DecodeError)) { + let decoder = one_of(string, [int |> map(int.to_string)]) + let path = + list.map(path, fn(key) { + let key = cast(key) + case run(key, decoder) { + Ok(key) -> key + Error(_) -> "<" <> dynamic.classify(key) <> ">" + } + }) + let errors = + list.map(layer.1, fn(error) { + DecodeError(..error, path: list.append(path, error.path)) + }) + #(layer.0, errors) +} + +/// Finalise a decoder having successfully extracted a value. +/// +/// # Examples +/// +/// ```gleam +/// let data = dynamic.from(dict.from_list([ +/// #("email", "lucy@example.com"), +/// #("name", "Lucy"), +/// ])) +/// +/// let decoder = { +/// use name <- decode.field("name", string) +/// use email <- decode.field("email", string) +/// decode.success(SignUp(name: name, email: email)) +/// } +/// +/// let result = decode.run(data, decoder) +/// assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com")) +/// ``` +/// +pub fn success(data: t) -> Decoder(t) { + Decoder(function: fn(_) { #(data, []) }) +} + +/// Construct a decode error for some unexpected dynamic data. +/// +pub fn decode_error( + expected expected: String, + found found: Dynamic, +) -> List(DecodeError) { + [DecodeError(expected: expected, found: dynamic.classify(found), path: [])] +} + +/// Run a decoder on a field of a `Dynamic` value, decoding the value if it is +/// of the desired type, or returning errors. An error is returned if there is +/// no field for the specified key. +/// +/// This function will index into dictionaries with any key type, and if the key is +/// an int then it'll also index into Erlang tuples and JavaScript arrays, and +/// the first eight elements of Gleam lists. +/// +/// # Examples +/// +/// ```gleam +/// let data = dynamic.from(dict.from_list([ +/// #("email", "lucy@example.com"), +/// #("name", "Lucy"), +/// ])) +/// +/// let decoder = { +/// use name <- decode.field("name", string) +/// use email <- decode.field("email", string) +/// decode.success(SignUp(name: name, email: email)) +/// } +/// +/// let result = decode.run(data, decoder) +/// assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com")) +/// ``` +/// +/// If you wish to decode a value that is more deeply nested within the dynamic +/// data, see [`subfield`](#subfield) and [`at`](#at). +/// +/// If you wish to return a default in the event that a field is not present, +/// see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at). +/// +pub fn field( + field_name: name, + field_decoder: Decoder(t), + next: fn(t) -> Decoder(final), +) -> Decoder(final) { + subfield([field_name], field_decoder, next) +} + +/// Run a decoder on a field of a `Dynamic` value, decoding the value if it is +/// of the desired type, or returning errors. The given default value is +/// returned if there is no field for the specified key. +/// +/// This function will index into dictionaries with any key type, and if the key is +/// an int then it'll also index into Erlang tuples and JavaScript arrays, and +/// the first eight elements of Gleam lists. +/// +/// # Examples +/// +/// ```gleam +/// let data = dynamic.from(dict.from_list([ +/// #("name", "Lucy"), +/// ])) +/// +/// let decoder = { +/// use name <- decode.field("name", string) +/// use email <- decode.optional_field("email", "n/a", string) +/// decode.success(SignUp(name: name, email: email)) +/// } +/// +/// let result = decode.run(data, decoder) +/// assert result == Ok(SignUp(name: "Lucy", email: "n/a")) +/// ``` +/// +pub fn optional_field( + key: name, + default: t, + field_decoder: Decoder(t), + next: fn(t) -> Decoder(final), +) -> Decoder(final) { + Decoder(function: fn(data) { + let #(out, errors1) = + case bare_index(data, key) { + Ok(Some(data)) -> field_decoder.function(data) + Ok(None) -> #(default, []) + Error(kind) -> #(default, [ + DecodeError(kind, dynamic.classify(data), []), + ]) + } + |> push_path([key]) + let #(out, errors2) = next(out).function(data) + #(out, list.append(errors1, errors2)) + }) +} + +/// A decoder that decodes a value that is nested within other values. For +/// example, decoding a value that is within some deeply nested JSON objects. +/// +/// This function will index into dictionaries with any key type, and if the key is +/// an int then it'll also index into Erlang tuples and JavaScript arrays, and +/// the first eight elements of Gleam lists. +/// +/// # Examples +/// +/// ```gleam +/// let decoder = decode.optionally_at(["one", "two"], 100, decode.int) +/// +/// let data = dynamic.from(dict.from_list([ +/// #("one", dict.from_list([])), +/// ])) +/// +/// +/// decode.run(data, decoder) +/// // -> Ok(100) +/// ``` +/// +pub fn optionally_at( + path: List(segment), + default: a, + inner: Decoder(a), +) -> Decoder(a) { + Decoder(function: fn(data) { + index(path, [], inner.function, data, fn(_, _) { #(default, []) }) + }) +} + +fn run_dynamic_function( + data: Dynamic, + name: String, + f: fn(Dynamic) -> Result(t, t), +) -> #(t, List(DecodeError)) { + case f(data) { + Ok(data) -> #(data, []) + Error(zero) -> #(zero, [DecodeError(name, dynamic.classify(data), [])]) + } +} + +/// A decoder that decodes `String` values. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from("Hello!"), decode.string) +/// assert result == Ok("Hello!") +/// ``` +/// +pub const string: Decoder(String) = Decoder(decode_string) + +fn decode_string(data: Dynamic) -> #(String, List(DecodeError)) { + run_dynamic_function(data, "String", dynamic_string) +} + +@external(javascript, "../../gleam_stdlib.mjs", "string") +fn dynamic_string(from data: Dynamic) -> Result(String, String) { + case dynamic_bit_array(data) { + Ok(data) -> + case bit_array.to_string(data) { + Ok(string) -> Ok(string) + Error(_) -> Error("") + } + Error(_) -> Error("") + } +} + +/// A decoder that decodes `Bool` values. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from(True), decode.bool) +/// assert result == Ok(True) +/// ``` +/// +pub const bool: Decoder(Bool) = Decoder(decode_bool) + +fn decode_bool(data: Dynamic) -> #(Bool, List(DecodeError)) { + case cast(True) == data { + True -> #(True, []) + False -> + case cast(False) == data { + True -> #(False, []) + False -> #(False, decode_error("Bool", data)) + } + } +} + +/// A decoder that decodes `Int` values. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from(147), decode.int) +/// assert result == Ok(147) +/// ``` +/// +pub const int: Decoder(Int) = Decoder(decode_int) + +fn decode_int(data: Dynamic) -> #(Int, List(DecodeError)) { + run_dynamic_function(data, "Int", dynamic_int) +} + +@external(erlang, "gleam_stdlib", "int") +@external(javascript, "../../gleam_stdlib.mjs", "int") +fn dynamic_int(data: Dynamic) -> Result(Int, Int) + +/// A decoder that decodes `Float` values. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from(3.14), decode.float) +/// assert result == Ok(3.14) +/// ``` +/// +pub const float: Decoder(Float) = Decoder(decode_float) + +fn decode_float(data: Dynamic) -> #(Float, List(DecodeError)) { + run_dynamic_function(data, "Float", dynamic_float) +} + +@external(erlang, "gleam_stdlib", "float") +@external(javascript, "../../gleam_stdlib.mjs", "float") +fn dynamic_float(data: Dynamic) -> Result(Float, Float) + +/// A decoder that decodes `Dynamic` values. This decoder never returns an error. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from(3.14), decode.dynamic) +/// assert result == Ok(dynamic.from(3.14)) +/// ``` +/// +pub const dynamic: Decoder(Dynamic) = Decoder(decode_dynamic) + +fn decode_dynamic(data: Dynamic) -> #(Dynamic, List(DecodeError)) { + #(data, []) +} + +/// A decoder that decodes `BitArray` values. This decoder never returns an error. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from(<<5, 7>>), decode.bit_array) +/// assert result == Ok(<<5, 7>>) +/// ``` +/// +pub const bit_array: Decoder(BitArray) = Decoder(decode_bit_array) + +fn decode_bit_array(data: Dynamic) -> #(BitArray, List(DecodeError)) { + run_dynamic_function(data, "BitArray", dynamic_bit_array) +} + +@external(erlang, "gleam_stdlib", "bit_array") +@external(javascript, "../../gleam_stdlib.mjs", "bit_array") +fn dynamic_bit_array(data: Dynamic) -> Result(BitArray, BitArray) + +/// A decoder that decodes lists where all elements are decoded with a given +/// decoder. +/// +/// # Examples +/// +/// ```gleam +/// let result = +/// decode.run(dynamic.from([1, 2, 3]), decode.list(of: decode.int)) +/// assert result == Ok([1, 2, 3]) +/// ``` +/// +pub fn list(of inner: Decoder(a)) -> Decoder(List(a)) { + Decoder(fn(data) { + decode_list(data, inner.function, fn(p, k) { push_path(p, [k]) }, 0, []) + }) +} + +@external(erlang, "gleam_stdlib", "list") +@external(javascript, "../../gleam_stdlib.mjs", "list") +fn decode_list( + data: Dynamic, + item: fn(Dynamic) -> #(t, List(DecodeError)), + push_path: fn(#(t, List(DecodeError)), key) -> #(t, List(DecodeError)), + index: Int, + acc: List(t), +) -> #(List(t), List(DecodeError)) + +/// A decoder that decodes dicts where all keys and vales are decoded with +/// given decoders. +/// +/// # Examples +/// +/// ```gleam +/// let values = dict.from_list([ +/// #("one", 1), +/// #("two", 2), +/// ]) +/// +/// let result = +/// decode.run(dynamic.from(values), decode.dict(decode.string, decode.int)) +/// assert result == Ok(values) +/// ``` +/// +pub fn dict( + key: Decoder(key), + value: Decoder(value), +) -> Decoder(Dict(key, value)) { + Decoder(fn(data) { + case decode_dict(data) { + Error(_) -> #(dict.new(), decode_error("Dict", data)) + Ok(dict) -> + dict.fold(dict, #(dict.new(), []), fn(a, k, v) { + // If there are any errors from previous key-value pairs then we + // don't need to run the decoders, instead return the existing acc. + case a.1 { + [] -> fold_dict(a, k, v, key.function, value.function) + [_, ..] -> a + } + }) + } + }) +} + +fn fold_dict( + acc: #(Dict(k, v), List(DecodeError)), + key: Dynamic, + value: Dynamic, + key_decoder: fn(Dynamic) -> #(k, List(DecodeError)), + value_decoder: fn(Dynamic) -> #(v, List(DecodeError)), +) -> #(Dict(k, v), List(DecodeError)) { + // First we decode the key. + case key_decoder(key) { + #(key, []) -> + // Then we decode the value. + case value_decoder(value) { + #(value, []) -> { + // It worked! Insert the new key-value pair so we can move onto the next. + let dict = dict.insert(acc.0, key, value) + #(dict, acc.1) + } + #(_, errors) -> push_path(#(dict.new(), errors), ["values"]) + } + #(_, errors) -> push_path(#(dict.new(), errors), ["keys"]) + } +} + +@external(erlang, "gleam_stdlib", "dict") +@external(javascript, "../../gleam_stdlib.mjs", "dict") +fn decode_dict(data: Dynamic) -> Result(Dict(Dynamic, Dynamic), Nil) + +/// A decoder that decodes nullable values of a type decoded by with a given +/// decoder. +/// +/// This function can handle common representations of null on all runtimes, such as +/// `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on +/// JavaScript. +/// +/// # Examples +/// +/// ```gleam +/// let result = decode.run(dynamic.from(100), decode.optional(decode.int)) +/// assert result == Ok(option.Some(100)) +/// ``` +/// +/// ```gleam +/// let result = decode.run(dynamic.from(Nil), decode.optional(decode.int)) +/// assert result == Ok(option.None) +/// ``` +/// +pub fn optional(inner: Decoder(a)) -> Decoder(Option(a)) { + Decoder(function: fn(data) { + case is_null(data) { + True -> #(option.None, []) + False -> { + let #(data, errors) = inner.function(data) + #(option.Some(data), errors) + } + } + }) +} + +/// Apply a transformation function to any value decoded by the decoder. +/// +/// # Examples +/// +/// ```gleam +/// let decoder = decode.int |> decode.map(int.to_string) +/// let result = decode.run(dynamic.from(1000), decoder) +/// assert result == Ok("1000") +/// ``` +/// +pub fn map(decoder: Decoder(a), transformer: fn(a) -> b) -> Decoder(b) { + Decoder(function: fn(d) { + let #(data, errors) = decoder.function(d) + #(transformer(data), errors) + }) +} + +/// Apply a transformation function to any errors returned by the decoder. +/// +pub fn map_errors( + decoder: Decoder(a), + transformer: fn(List(DecodeError)) -> List(DecodeError), +) -> Decoder(a) { + Decoder(function: fn(d) { + let #(data, errors) = decoder.function(d) + #(data, transformer(errors)) + }) +} + +/// Replace all errors produced by a decoder with one single error for a named +/// expected type. +/// +/// This function may be useful if you wish to simplify errors before +/// presenting them to a user, particularly when using the `one_of` function. +/// +/// # Examples +/// +/// ```gleam +/// let decoder = decode.string |> decode.collapse_errors("MyThing") +/// let result = decode.run(dynamic.from(1000), decoder) +/// assert result == Error([DecodeError("MyThing", "Int", [])]) +/// ``` +/// +pub fn collapse_errors(decoder: Decoder(a), name: String) -> Decoder(a) { + Decoder(function: fn(dynamic_data) { + let #(data, errors) as layer = decoder.function(dynamic_data) + case errors { + [] -> layer + [_, ..] -> #(data, decode_error(name, dynamic_data)) + } + }) +} + +/// Create a new decoder based upon the value of a previous decoder. +/// +/// This may be useful to run one previous decoder to use in further decoding. +/// +pub fn then(decoder: Decoder(a), next: fn(a) -> Decoder(b)) -> Decoder(b) { + Decoder(function: fn(dynamic_data) { + let #(data, errors) = decoder.function(dynamic_data) + let decoder = next(data) + let #(data, _) as layer = decoder.function(dynamic_data) + case errors { + [] -> layer + [_, ..] -> #(data, errors) + } + }) +} + +/// Create a new decoder from several other decoders. Each of the inner +/// decoders is run in turn, and the value from the first to succeed is used. +/// +/// If no decoder succeeds then the errors from the first decoder is used. +/// If you wish for different errors then you may wish to use the +/// `collapse_errors` or `map_errors` functions. +/// +/// # Examples +/// +/// ```gleam +/// let decoder = decode.one_of(decode.string, or: [ +/// decode.int |> decode.map(int.to_string), +/// decode.float |> decode.map(float.to_string), +/// ]) +/// decode.run(dynamic.from(1000), decoder) +/// // -> Ok("1000") +/// ``` +/// +pub fn one_of( + first: Decoder(a), + or alternatives: List(Decoder(a)), +) -> Decoder(a) { + Decoder(function: fn(dynamic_data) { + let #(_, errors) as layer = first.function(dynamic_data) + case errors { + [] -> layer + [_, ..] -> run_decoders(dynamic_data, layer, alternatives) + } + }) +} + +fn run_decoders( + data: Dynamic, + failure: #(a, List(DecodeError)), + decoders: List(Decoder(a)), +) -> #(a, List(DecodeError)) { + case decoders { + [] -> failure + + [decoder, ..decoders] -> { + let #(_, errors) as layer = decoder.function(data) + case errors { + [] -> layer + [_, ..] -> run_decoders(data, failure, decoders) + } + } + } +} + +/// Define a decoder that always fails. The parameter for this function is the +/// name of the type that has failed to decode. +/// +pub fn failure(zero: a, expected: String) -> Decoder(a) { + Decoder(function: fn(d) { #(zero, decode_error(expected, d)) }) +} + +/// Create a decoder for a new data type from a decoding function. +/// +/// This function is used for new primitive types. For example, you might +/// define a decoder for Erlang's pid type. +/// +/// A default "zero" value is also required to make a decoder. When this +/// decoder is used as part of a larger decoder this zero value used as +/// a placeholder so that the rest of the decoder can continue to run and +/// collect all decoding errors. +/// +/// If you were to make a decoder for the `String` type (rather than using the +/// build-in `string` decoder) you would define it like so: +/// +/// ```gleam +/// pub fn string_decoder() -> decode.Decoder(String) { +/// let default = "" +/// decode.new_primitive_decoder("String", fn(data) { +/// case dynamic.string(data) { +/// Ok(x) -> Ok(x) +/// Error(_) -> Error(default) +/// } +/// }) +/// } +/// ``` +/// +pub fn new_primitive_decoder( + name: String, + decoding_function: fn(Dynamic) -> Result(t, t), +) -> Decoder(t) { + Decoder(function: fn(d) { + case decoding_function(d) { + Ok(t) -> #(t, []) + Error(zero) -> #(zero, [DecodeError(name, dynamic.classify(d), [])]) + } + }) +} + +/// Create a decoder that can refer to itself, useful for decoding deeply +/// nested data. +/// +/// Attempting to create a recursive decoder without this function could result +/// in an infinite loop. If you are using `field` or other `use`able functions +/// then you may not need to use this function. +/// +/// ```gleam +/// type Nested { +/// Nested(List(Nested)) +/// Value(String) +/// } +/// +/// fn nested_decoder() -> decode.Decoder(Nested) { +/// use <- decode.recursive +/// decode.one_of(decode.string |> decode.map(Value), [ +/// decode.list(nested_decoder()) |> decode.map(Nested), +/// ]) +/// } +/// ``` +/// +pub fn recursive(inner: fn() -> Decoder(a)) -> Decoder(a) { + Decoder(function: fn(data) { + let decoder = inner() + decoder.function(data) + }) +} + +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../../gleam_stdlib.mjs", "identity") +fn cast(a: anything) -> Dynamic + +@external(erlang, "gleam_stdlib", "is_null") +@external(javascript, "../../gleam_stdlib.mjs", "is_null") +fn is_null(a: Dynamic) -> Bool diff --git a/build/packages/gleam_stdlib/src/gleam/float.gleam b/build/packages/gleam_stdlib/src/gleam/float.gleam new file mode 100644 index 0000000..83bfa6e --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/float.gleam @@ -0,0 +1,661 @@ +//// Functions for working with floats. +//// +//// ## Float representation +//// +//// Floats are represented as 64 bit floating point numbers on both the Erlang +//// and JavaScript runtimes. The floating point behaviour is native to their +//// respective runtimes, so their exact behaviour will be slightly different on +//// the two runtimes. +//// +//// ### Infinity and NaN +//// +//// Under the JavaScript runtime, exceeding the maximum (or minimum) +//// representable value for a floating point value will result in Infinity (or +//// -Infinity). Should you try to divide two infinities you will get NaN as a +//// result. +//// +//// When running on BEAM, exceeding the maximum (or minimum) representable +//// value for a floating point value will raise an error. +//// +//// ## Division by zero +//// +//// Gleam runs on the Erlang virtual machine, which does not follow the IEEE +//// 754 standard for floating point arithmetic and does not have an `Infinity` +//// value. In Erlang division by zero results in a crash, however Gleam does +//// not have partial functions and operators in core so instead division by zero +//// returns zero, a behaviour taken from Pony, Coq, and Lean. +//// +//// This may seem unexpected at first, but it is no less mathematically valid +//// than crashing or returning a special value. Division by zero is undefined +//// in mathematics. + +import gleam/order.{type Order} + +/// Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was +/// not possible. +/// +/// ## Examples +/// +/// ```gleam +/// parse("2.3") +/// // -> Ok(2.3) +/// ``` +/// +/// ```gleam +/// parse("ABC") +/// // -> Error(Nil) +/// ``` +/// +@external(erlang, "gleam_stdlib", "parse_float") +@external(javascript, "../gleam_stdlib.mjs", "parse_float") +pub fn parse(string: String) -> Result(Float, Nil) + +/// Returns the string representation of the provided `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// to_string(2.3) +/// // -> "2.3" +/// ``` +/// +@external(erlang, "gleam_stdlib", "float_to_string") +@external(javascript, "../gleam_stdlib.mjs", "float_to_string") +pub fn to_string(x: Float) -> String + +/// Restricts a `Float` between a lower and upper bound. +/// +/// ## Examples +/// +/// ```gleam +/// clamp(1.2, min: 1.4, max: 1.6) +/// // -> 1.4 +/// ``` +/// +pub fn clamp(x: Float, min min_bound: Float, max max_bound: Float) -> Float { + x + |> min(max_bound) + |> max(min_bound) +} + +/// Compares two `Float`s, returning an `Order`: +/// `Lt` for lower than, `Eq` for equals, or `Gt` for greater than. +/// +/// ## Examples +/// +/// ```gleam +/// compare(2.0, 2.3) +/// // -> Lt +/// ``` +/// +/// To handle +/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) +/// you may use [`loosely_compare`](#loosely_compare) instead. +/// +pub fn compare(a: Float, with b: Float) -> Order { + case a == b { + True -> order.Eq + False -> + case a <. b { + True -> order.Lt + False -> order.Gt + } + } +} + +/// Compares two `Float`s within a tolerance, returning an `Order`: +/// `Lt` for lower than, `Eq` for equals, or `Gt` for greater than. +/// +/// This function allows Float comparison while handling +/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems). +/// +/// Notice: For `Float`s the tolerance won't be exact: +/// `5.3 - 5.0` is not exactly `0.3`. +/// +/// ## Examples +/// +/// ```gleam +/// loosely_compare(5.0, with: 5.3, tolerating: 0.5) +/// // -> Eq +/// ``` +/// +/// If you want to check only for equality you may use +/// [`loosely_equals`](#loosely_equals) instead. +/// +pub fn loosely_compare( + a: Float, + with b: Float, + tolerating tolerance: Float, +) -> Order { + let difference = absolute_value(a -. b) + case difference <=. tolerance { + True -> order.Eq + False -> compare(a, b) + } +} + +/// Checks for equality of two `Float`s within a tolerance, +/// returning an `Bool`. +/// +/// This function allows Float comparison while handling +/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems). +/// +/// Notice: For `Float`s the tolerance won't be exact: +/// `5.3 - 5.0` is not exactly `0.3`. +/// +/// ## Examples +/// +/// ```gleam +/// loosely_equals(5.0, with: 5.3, tolerating: 0.5) +/// // -> True +/// ``` +/// +/// ```gleam +/// loosely_equals(5.0, with: 5.1, tolerating: 0.1) +/// // -> False +/// ``` +/// +pub fn loosely_equals( + a: Float, + with b: Float, + tolerating tolerance: Float, +) -> Bool { + let difference = absolute_value(a -. b) + difference <=. tolerance +} + +/// Compares two `Float`s, returning the smaller of the two. +/// +/// ## Examples +/// +/// ```gleam +/// min(2.0, 2.3) +/// // -> 2.0 +/// ``` +/// +pub fn min(a: Float, b: Float) -> Float { + case a <. b { + True -> a + False -> b + } +} + +/// Compares two `Float`s, returning the larger of the two. +/// +/// ## Examples +/// +/// ```gleam +/// max(2.0, 2.3) +/// // -> 2.3 +/// ``` +/// +pub fn max(a: Float, b: Float) -> Float { + case a >. b { + True -> a + False -> b + } +} + +/// Rounds the value to the next highest whole number as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// ceiling(2.3) +/// // -> 3.0 +/// ``` +/// +@external(erlang, "math", "ceil") +@external(javascript, "../gleam_stdlib.mjs", "ceiling") +pub fn ceiling(x: Float) -> Float + +/// Rounds the value to the next lowest whole number as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// floor(2.3) +/// // -> 2.0 +/// ``` +/// +@external(erlang, "math", "floor") +@external(javascript, "../gleam_stdlib.mjs", "floor") +pub fn floor(x: Float) -> Float + +/// Rounds the value to the nearest whole number as an `Int`. +/// +/// ## Examples +/// +/// ```gleam +/// round(2.3) +/// // -> 2 +/// ``` +/// +/// ```gleam +/// round(2.5) +/// // -> 3 +/// ``` +/// +@external(erlang, "erlang", "round") +pub fn round(x: Float) -> Int { + case x >=. 0.0 { + True -> js_round(x) + False -> 0 - js_round(negate(x)) + } +} + +@external(javascript, "../gleam_stdlib.mjs", "round") +fn js_round(a: Float) -> Int + +/// Returns the value as an `Int`, truncating all decimal digits. +/// +/// ## Examples +/// +/// ```gleam +/// truncate(2.4343434847383438) +/// // -> 2 +/// ``` +/// +@external(erlang, "erlang", "trunc") +@external(javascript, "../gleam_stdlib.mjs", "truncate") +pub fn truncate(x: Float) -> Int + +/// Converts the value to a given precision as a `Float`. +/// The precision is the number of allowed decimal places. +/// Negative precisions are allowed and force rounding +/// to the nearest tenth, hundredth, thousandth etc. +/// +/// ## Examples +/// +/// ```gleam +/// to_precision(2.43434348473, precision: 2) +/// // -> 2.43 +/// ``` +/// +/// ```gleam +/// to_precision(547890.453444, precision: -3) +/// // -> 548000.0 +/// ``` +/// +pub fn to_precision(x: Float, precision: Int) -> Float { + case precision <= 0 { + True -> { + let factor = do_power(10.0, do_to_float(-precision)) + do_to_float(round(x /. factor)) *. factor + } + False -> { + let factor = do_power(10.0, do_to_float(precision)) + do_to_float(round(x *. factor)) /. factor + } + } +} + +@external(erlang, "erlang", "float") +@external(javascript, "../gleam_stdlib.mjs", "identity") +fn do_to_float(a: Int) -> Float + +/// Returns the absolute value of the input as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// absolute_value(-12.5) +/// // -> 12.5 +/// ``` +/// +/// ```gleam +/// absolute_value(10.2) +/// // -> 10.2 +/// ``` +/// +pub fn absolute_value(x: Float) -> Float { + case x >=. 0.0 { + True -> x + False -> 0.0 -. x + } +} + +/// Returns the results of the base being raised to the power of the +/// exponent, as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// power(2.0, -1.0) +/// // -> Ok(0.5) +/// ``` +/// +/// ```gleam +/// power(2.0, 2.0) +/// // -> Ok(4.0) +/// ``` +/// +/// ```gleam +/// power(8.0, 1.5) +/// // -> Ok(22.627416997969522) +/// ``` +/// +/// ```gleam +/// 4.0 |> power(of: 2.0) +/// // -> Ok(16.0) +/// ``` +/// +/// ```gleam +/// power(-1.0, 0.5) +/// // -> Error(Nil) +/// ``` +/// +pub fn power(base: Float, of exponent: Float) -> Result(Float, Nil) { + let fractional: Bool = ceiling(exponent) -. exponent >. 0.0 + // In the following check: + // 1. If the base is negative and the exponent is fractional then + // return an error as it will otherwise be an imaginary number + // 2. If the base is 0 and the exponent is negative then the expression + // is equivalent to the exponent divided by 0 and an error should be + // returned + case base <. 0.0 && fractional || base == 0.0 && exponent <. 0.0 { + True -> Error(Nil) + False -> Ok(do_power(base, exponent)) + } +} + +@external(erlang, "math", "pow") +@external(javascript, "../gleam_stdlib.mjs", "power") +fn do_power(a: Float, b: Float) -> Float + +/// Returns the square root of the input as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// square_root(4.0) +/// // -> Ok(2.0) +/// ``` +/// +/// ```gleam +/// square_root(-16.0) +/// // -> Error(Nil) +/// ``` +/// +pub fn square_root(x: Float) -> Result(Float, Nil) { + power(x, 0.5) +} + +/// Returns the negative of the value provided. +/// +/// ## Examples +/// +/// ```gleam +/// negate(1.0) +/// // -> -1.0 +/// ``` +/// +pub fn negate(x: Float) -> Float { + -1.0 *. x +} + +/// Sums a list of `Float`s. +/// +/// ## Example +/// +/// ```gleam +/// sum([1.0, 2.2, 3.3]) +/// // -> 6.5 +/// ``` +/// +pub fn sum(numbers: List(Float)) -> Float { + sum_loop(numbers, 0.0) +} + +fn sum_loop(numbers: List(Float), initial: Float) -> Float { + case numbers { + [first, ..rest] -> sum_loop(rest, first +. initial) + [] -> initial + } +} + +/// Multiplies a list of `Float`s and returns the product. +/// +/// ## Example +/// +/// ```gleam +/// product([2.5, 3.2, 4.2]) +/// // -> 33.6 +/// ``` +/// +pub fn product(numbers: List(Float)) -> Float { + product_loop(numbers, 1.0) +} + +fn product_loop(numbers: List(Float), initial: Float) -> Float { + case numbers { + [first, ..rest] -> product_loop(rest, first *. initial) + [] -> initial + } +} + +/// Generates a random float between the given zero (inclusive) and one +/// (exclusive). +/// +/// On Erlang this updates the random state in the process dictionary. +/// See: +/// +/// ## Examples +/// +/// ```gleam +/// random() +/// // -> 0.646355926896028 +/// ``` +/// +@external(erlang, "rand", "uniform") +@external(javascript, "../gleam_stdlib.mjs", "random_uniform") +pub fn random() -> Float + +/// Computes the modulo of an float division of inputs as a `Result`. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// modulo(13.3, by: 3.3) +/// // -> Ok(0.1) +/// ``` +/// +/// ```gleam +/// modulo(-13.3, by: 3.3) +/// // -> Ok(3.2) +/// ``` +/// +/// ```gleam +/// modulo(13.3, by: -3.3) +/// // -> Ok(-3.2) +/// ``` +/// +/// ```gleam +/// modulo(-13.3, by: -3.3) +/// // -> Ok(-0.1) +/// ``` +/// +pub fn modulo(dividend: Float, by divisor: Float) -> Result(Float, Nil) { + case divisor { + 0.0 -> Error(Nil) + _ -> Ok(dividend -. floor(dividend /. divisor) *. divisor) + } +} + +/// Returns division of the inputs as a `Result`. +/// +/// ## Examples +/// +/// ```gleam +/// divide(0.0, 1.0) +/// // -> Ok(0.0) +/// ``` +/// +/// ```gleam +/// divide(1.0, 0.0) +/// // -> Error(Nil) +/// ``` +/// +pub fn divide(a: Float, by b: Float) -> Result(Float, Nil) { + case b { + 0.0 -> Error(Nil) + b -> Ok(a /. b) + } +} + +/// Adds two floats together. +/// +/// It's the function equivalent of the `+.` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// add(1.0, 2.0) +/// // -> 3.0 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// +/// list.fold([1.0, 2.0, 3.0], 0.0, add) +/// // -> 6.0 +/// ``` +/// +/// ```gleam +/// 3.0 |> add(2.0) +/// // -> 5.0 +/// ``` +/// +pub fn add(a: Float, b: Float) -> Float { + a +. b +} + +/// Multiplies two floats together. +/// +/// It's the function equivalent of the `*.` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// multiply(2.0, 4.0) +/// // -> 8.0 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// +/// list.fold([2.0, 3.0, 4.0], 1.0, multiply) +/// // -> 24.0 +/// ``` +/// +/// ```gleam +/// 3.0 |> multiply(2.0) +/// // -> 6.0 +/// ``` +/// +pub fn multiply(a: Float, b: Float) -> Float { + a *. b +} + +/// Subtracts one float from another. +/// +/// It's the function equivalent of the `-.` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// subtract(3.0, 1.0) +/// // -> 2.0 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// +/// list.fold([1.0, 2.0, 3.0], 10.0, subtract) +/// // -> 4.0 +/// ``` +/// +/// ```gleam +/// 3.0 |> subtract(_, 2.0) +/// // -> 1.0 +/// ``` +/// +/// ```gleam +/// 3.0 |> subtract(2.0, _) +/// // -> -1.0 +/// ``` +/// +pub fn subtract(a: Float, b: Float) -> Float { + a -. b +} + +/// Returns the natural logarithm (base e) of the given as a `Result`. If the +/// input is less than or equal to 0, returns `Error(Nil)`. +/// +/// ## Examples +/// +/// ```gleam +/// logarithm(1.0) +/// // -> Ok(0.0) +/// ``` +/// +/// ```gleam +/// logarithm(2.718281828459045) // e +/// // -> Ok(1.0) +/// ``` +/// +/// ```gleam +/// logarithm(0.0) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// logarithm(-1.0) +/// // -> Error(Nil) +/// ``` +/// +pub fn logarithm(x: Float) -> Result(Float, Nil) { + // In the following check: + // 1. If x is negative then return an error as the natural logarithm + // of a negative number is undefined (would be a complex number) + // 2. If x is 0 then return an error as the natural logarithm of 0 + // approaches negative infinity + case x <=. 0.0 { + True -> Error(Nil) + False -> Ok(do_log(x)) + } +} + +@external(erlang, "math", "log") +@external(javascript, "../gleam_stdlib.mjs", "log") +fn do_log(x: Float) -> Float + +/// Returns e (Euler's number) raised to the power of the given exponent, as +/// a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// exponential(0.0) +/// // -> Ok(1.0) +/// ``` +/// +/// ```gleam +/// exponential(1.0) +/// // -> Ok(2.718281828459045) +/// ``` +/// +/// ```gleam +/// exponential(-1.0) +/// // -> Ok(0.36787944117144233) +/// ``` +/// +@external(erlang, "math", "exp") +@external(javascript, "../gleam_stdlib.mjs", "exp") +pub fn exponential(x: Float) -> Float diff --git a/build/packages/gleam_stdlib/src/gleam/function.gleam b/build/packages/gleam_stdlib/src/gleam/function.gleam new file mode 100644 index 0000000..6ae3a62 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/function.gleam @@ -0,0 +1,15 @@ +/// Takes a single argument and always returns its input value. +/// +pub fn identity(x: a) -> a { + x +} + +/// Takes an argument and a single function, calls that function with that +/// argument and returns that argument instead of the function return value. +/// +/// Useful for running synchronous side effects in a pipeline. +/// +pub fn tap(arg: a, effect: fn(a) -> b) -> a { + effect(arg) + arg +} diff --git a/build/packages/gleam_stdlib/src/gleam/int.gleam b/build/packages/gleam_stdlib/src/gleam/int.gleam new file mode 100644 index 0000000..060ea89 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/int.gleam @@ -0,0 +1,826 @@ +//// Functions for working with integers. +//// +//// ## Division by zero +//// +//// In Erlang division by zero results in a crash, however Gleam does not have +//// partial functions and operators in core so instead division by zero returns +//// zero, a behaviour taken from Pony, Coq, and Lean. +//// +//// This may seem unexpected at first, but it is no less mathematically valid +//// than crashing or returning a special value. Division by zero is undefined +//// in mathematics. + +import gleam/float +import gleam/order.{type Order} + +/// Returns the absolute value of the input. +/// +/// ## Examples +/// +/// ```gleam +/// absolute_value(-12) +/// // -> 12 +/// ``` +/// +/// ```gleam +/// absolute_value(10) +/// // -> 10 +/// ``` +/// +pub fn absolute_value(x: Int) -> Int { + case x >= 0 { + True -> x + False -> x * -1 + } +} + +/// Returns the results of the base being raised to the power of the +/// exponent, as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// power(2, -1.0) +/// // -> Ok(0.5) +/// ``` +/// +/// ```gleam +/// power(2, 2.0) +/// // -> Ok(4.0) +/// ``` +/// +/// ```gleam +/// power(8, 1.5) +/// // -> Ok(22.627416997969522) +/// ``` +/// +/// ```gleam +/// 4 |> power(of: 2.0) +/// // -> Ok(16.0) +/// ``` +/// +/// ```gleam +/// power(-1, 0.5) +/// // -> Error(Nil) +/// ``` +/// +pub fn power(base: Int, of exponent: Float) -> Result(Float, Nil) { + to_float(base) + |> float.power(exponent) +} + +/// Returns the square root of the input as a `Float`. +/// +/// ## Examples +/// +/// ```gleam +/// square_root(4) +/// // -> Ok(2.0) +/// ``` +/// +/// ```gleam +/// square_root(-16) +/// // -> Error(Nil) +/// ``` +/// +pub fn square_root(x: Int) -> Result(Float, Nil) { + to_float(x) + |> float.square_root() +} + +/// Parses a given string as an int if possible. +/// +/// ## Examples +/// +/// ```gleam +/// parse("2") +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// parse("ABC") +/// // -> Error(Nil) +/// ``` +/// +@external(erlang, "gleam_stdlib", "parse_int") +@external(javascript, "../gleam_stdlib.mjs", "parse_int") +pub fn parse(string: String) -> Result(Int, Nil) + +/// Parses a given string as an int in a given base if possible. +/// Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`. +/// +/// ## Examples +/// +/// ```gleam +/// base_parse("10", 2) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// base_parse("30", 16) +/// // -> Ok(48) +/// ``` +/// +/// ```gleam +/// base_parse("1C", 36) +/// // -> Ok(48) +/// ``` +/// +/// ```gleam +/// base_parse("48", 1) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// base_parse("48", 37) +/// // -> Error(Nil) +/// ``` +/// +pub fn base_parse(string: String, base: Int) -> Result(Int, Nil) { + case base >= 2 && base <= 36 { + True -> do_base_parse(string, base) + False -> Error(Nil) + } +} + +@external(erlang, "gleam_stdlib", "int_from_base_string") +@external(javascript, "../gleam_stdlib.mjs", "int_from_base_string") +fn do_base_parse(a: String, b: Int) -> Result(Int, Nil) + +/// Prints a given int to a string. +/// +/// ## Examples +/// +/// ```gleam +/// to_string(2) +/// // -> "2" +/// ``` +/// +@external(erlang, "erlang", "integer_to_binary") +@external(javascript, "../gleam_stdlib.mjs", "to_string") +pub fn to_string(x: Int) -> String + +/// Prints a given int to a string using the base number provided. +/// Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`. +/// For common bases (2, 8, 16, 36), use the `to_baseN` functions. +/// +/// ## Examples +/// +/// ```gleam +/// to_base_string(2, 2) +/// // -> Ok("10") +/// ``` +/// +/// ```gleam +/// to_base_string(48, 16) +/// // -> Ok("30") +/// ``` +/// +/// ```gleam +/// to_base_string(48, 36) +/// // -> Ok("1C") +/// ``` +/// +/// ```gleam +/// to_base_string(48, 1) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// to_base_string(48, 37) +/// // -> Error(Nil) +/// ``` +/// +pub fn to_base_string(x: Int, base: Int) -> Result(String, Nil) { + case base >= 2 && base <= 36 { + True -> Ok(do_to_base_string(x, base)) + False -> Error(Nil) + } +} + +@external(erlang, "erlang", "integer_to_binary") +@external(javascript, "../gleam_stdlib.mjs", "int_to_base_string") +fn do_to_base_string(a: Int, b: Int) -> String + +/// Prints a given int to a string using base-2. +/// +/// ## Examples +/// +/// ```gleam +/// to_base2(2) +/// // -> "10" +/// ``` +/// +pub fn to_base2(x: Int) -> String { + do_to_base_string(x, 2) +} + +/// Prints a given int to a string using base-8. +/// +/// ## Examples +/// +/// ```gleam +/// to_base8(15) +/// // -> "17" +/// ``` +/// +pub fn to_base8(x: Int) -> String { + do_to_base_string(x, 8) +} + +/// Prints a given int to a string using base-16. +/// +/// ## Examples +/// +/// ```gleam +/// to_base16(48) +/// // -> "30" +/// ``` +/// +pub fn to_base16(x: Int) -> String { + do_to_base_string(x, 16) +} + +/// Prints a given int to a string using base-36. +/// +/// ## Examples +/// +/// ```gleam +/// to_base36(48) +/// // -> "1C" +/// ``` +/// +pub fn to_base36(x: Int) -> String { + do_to_base_string(x, 36) +} + +/// Takes an int and returns its value as a float. +/// +/// ## Examples +/// +/// ```gleam +/// to_float(5) +/// // -> 5.0 +/// ``` +/// +/// ```gleam +/// to_float(0) +/// // -> 0.0 +/// ``` +/// +/// ```gleam +/// to_float(-3) +/// // -> -3.0 +/// ``` +/// +@external(erlang, "erlang", "float") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn to_float(x: Int) -> Float + +/// Restricts an int between a lower and upper bound. +/// +/// ## Examples +/// +/// ```gleam +/// clamp(40, min: 50, max: 60) +/// // -> 50 +/// ``` +/// +pub fn clamp(x: Int, min min_bound: Int, max max_bound: Int) -> Int { + x + |> min(max_bound) + |> max(min_bound) +} + +/// Compares two ints, returning an order. +/// +/// ## Examples +/// +/// ```gleam +/// compare(2, 3) +/// // -> Lt +/// ``` +/// +/// ```gleam +/// compare(4, 3) +/// // -> Gt +/// ``` +/// +/// ```gleam +/// compare(3, 3) +/// // -> Eq +/// ``` +/// +pub fn compare(a: Int, with b: Int) -> Order { + case a == b { + True -> order.Eq + False -> + case a < b { + True -> order.Lt + False -> order.Gt + } + } +} + +/// Compares two ints, returning the smaller of the two. +/// +/// ## Examples +/// +/// ```gleam +/// min(2, 3) +/// // -> 2 +/// ``` +/// +pub fn min(a: Int, b: Int) -> Int { + case a < b { + True -> a + False -> b + } +} + +/// Compares two ints, returning the larger of the two. +/// +/// ## Examples +/// +/// ```gleam +/// max(2, 3) +/// // -> 3 +/// ``` +/// +pub fn max(a: Int, b: Int) -> Int { + case a > b { + True -> a + False -> b + } +} + +/// Returns whether the value provided is even. +/// +/// ## Examples +/// +/// ```gleam +/// is_even(2) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_even(3) +/// // -> False +/// ``` +/// +pub fn is_even(x: Int) -> Bool { + x % 2 == 0 +} + +/// Returns whether the value provided is odd. +/// +/// ## Examples +/// +/// ```gleam +/// is_odd(3) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_odd(2) +/// // -> False +/// ``` +/// +pub fn is_odd(x: Int) -> Bool { + x % 2 != 0 +} + +/// Returns the negative of the value provided. +/// +/// ## Examples +/// +/// ```gleam +/// negate(1) +/// // -> -1 +/// ``` +/// +pub fn negate(x: Int) -> Int { + -1 * x +} + +/// Sums a list of ints. +/// +/// ## Example +/// +/// ```gleam +/// sum([1, 2, 3]) +/// // -> 6 +/// ``` +/// +pub fn sum(numbers: List(Int)) -> Int { + sum_loop(numbers, 0) +} + +fn sum_loop(numbers: List(Int), initial: Int) -> Int { + case numbers { + [first, ..rest] -> sum_loop(rest, first + initial) + [] -> initial + } +} + +/// Multiplies a list of ints and returns the product. +/// +/// ## Example +/// +/// ```gleam +/// product([2, 3, 4]) +/// // -> 24 +/// ``` +/// +pub fn product(numbers: List(Int)) -> Int { + product_loop(numbers, 1) +} + +fn product_loop(numbers: List(Int), initial: Int) -> Int { + case numbers { + [first, ..rest] -> product_loop(rest, first * initial) + [] -> initial + } +} + +@deprecated("Vendor this function into your codebase") +pub fn digits(x: Int, base: Int) -> Result(List(Int), Nil) { + case base < 2 { + True -> Error(Nil) + False -> Ok(digits_loop(x, base, [])) + } +} + +fn digits_loop(x: Int, base: Int, acc: List(Int)) -> List(Int) { + case absolute_value(x) < base { + True -> [x, ..acc] + False -> digits_loop(x / base, base, [x % base, ..acc]) + } +} + +@deprecated("Vendor this function into your codebase") +pub fn undigits(numbers: List(Int), base: Int) -> Result(Int, Nil) { + case base < 2 { + True -> Error(Nil) + False -> undigits_loop(numbers, base, 0) + } +} + +fn undigits_loop(numbers: List(Int), base: Int, acc: Int) -> Result(Int, Nil) { + case numbers { + [] -> Ok(acc) + [digit, ..] if digit >= base -> Error(Nil) + [digit, ..rest] -> undigits_loop(rest, base, acc * base + digit) + } +} + +/// Generates a random int between zero and the given maximum. +/// +/// The lower number is inclusive, the upper number is exclusive. +/// +/// ## Examples +/// +/// ```gleam +/// random(10) +/// // -> 4 +/// ``` +/// +/// ```gleam +/// random(1) +/// // -> 0 +/// ``` +/// +/// ```gleam +/// random(-1) +/// // -> -1 +/// ``` +/// +pub fn random(max: Int) -> Int { + { float.random() *. to_float(max) } + |> float.floor + |> float.round +} + +/// Performs a truncated integer division. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// divide(0, 1) +/// // -> Ok(0) +/// ``` +/// +/// ```gleam +/// divide(1, 0) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// divide(5, 2) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// divide(-99, 2) +/// // -> Ok(-49) +/// ``` +/// +pub fn divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> Ok(dividend / divisor) + } +} + +/// Computes the remainder of an integer division of inputs as a `Result`. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// Most the time you will want to use the `%` operator instead of this +/// function. +/// +/// ## Examples +/// +/// ```gleam +/// remainder(3, 2) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// remainder(1, 0) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// remainder(10, -1) +/// // -> Ok(0) +/// ``` +/// +/// ```gleam +/// remainder(13, by: 3) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// remainder(-13, by: 3) +/// // -> Ok(-1) +/// ``` +/// +/// ```gleam +/// remainder(13, by: -3) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// remainder(-13, by: -3) +/// // -> Ok(-1) +/// ``` +/// +pub fn remainder(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> Ok(dividend % divisor) + } +} + +/// Computes the modulo of an integer division of inputs as a `Result`. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// Most the time you will want to use the `%` operator instead of this +/// function. +/// +/// ## Examples +/// +/// ```gleam +/// modulo(3, 2) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// modulo(1, 0) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// modulo(10, -1) +/// // -> Ok(0) +/// ``` +/// +/// ```gleam +/// modulo(13, by: 3) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// modulo(-13, by: 3) +/// // -> Ok(2) +/// ``` +/// +pub fn modulo(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + _ -> { + let remainder = dividend % divisor + case remainder * divisor < 0 { + True -> Ok(remainder + divisor) + False -> Ok(remainder) + } + } + } +} + +/// Performs a *floored* integer division, which means that the result will +/// always be rounded towards negative infinity. +/// +/// If you want to perform truncated integer division (rounding towards zero), +/// use `int.divide()` or the `/` operator instead. +/// +/// Returns division of the inputs as a `Result`: If the given divisor equals +/// `0`, this function returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// floor_divide(1, 0) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// floor_divide(5, 2) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// floor_divide(6, -4) +/// // -> Ok(-2) +/// ``` +/// +/// ```gleam +/// floor_divide(-99, 2) +/// // -> Ok(-50) +/// ``` +/// +pub fn floor_divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { + case divisor { + 0 -> Error(Nil) + divisor -> + case dividend * divisor < 0 && dividend % divisor != 0 { + True -> Ok(dividend / divisor - 1) + False -> Ok(dividend / divisor) + } + } +} + +/// Adds two integers together. +/// +/// It's the function equivalent of the `+` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// add(1, 2) +/// // -> 3 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// list.fold([1, 2, 3], 0, add) +/// // -> 6 +/// ``` +/// +/// ```gleam +/// 3 |> add(2) +/// // -> 5 +/// ``` +/// +pub fn add(a: Int, b: Int) -> Int { + a + b +} + +/// Multiplies two integers together. +/// +/// It's the function equivalent of the `*` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// multiply(2, 4) +/// // -> 8 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// +/// list.fold([2, 3, 4], 1, multiply) +/// // -> 24 +/// ``` +/// +/// ```gleam +/// 3 |> multiply(2) +/// // -> 6 +/// ``` +/// +pub fn multiply(a: Int, b: Int) -> Int { + a * b +} + +/// Subtracts one int from another. +/// +/// It's the function equivalent of the `-` operator. +/// This function is useful in higher order functions or pipes. +/// +/// ## Examples +/// +/// ```gleam +/// subtract(3, 1) +/// // -> 2 +/// ``` +/// +/// ```gleam +/// import gleam/list +/// +/// list.fold([1, 2, 3], 10, subtract) +/// // -> 4 +/// ``` +/// +/// ```gleam +/// 3 |> subtract(2) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// 3 |> subtract(2, _) +/// // -> -1 +/// ``` +/// +pub fn subtract(a: Int, b: Int) -> Int { + a - b +} + +/// Calculates the bitwise AND of its arguments. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "band") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_and") +pub fn bitwise_and(x: Int, y: Int) -> Int + +/// Calculates the bitwise NOT of its argument. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bnot") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_not") +pub fn bitwise_not(x: Int) -> Int + +/// Calculates the bitwise OR of its arguments. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bor") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_or") +pub fn bitwise_or(x: Int, y: Int) -> Int + +/// Calculates the bitwise XOR of its arguments. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bxor") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_exclusive_or") +pub fn bitwise_exclusive_or(x: Int, y: Int) -> Int + +/// Calculates the result of an arithmetic left bitshift. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bsl") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_left") +pub fn bitwise_shift_left(x: Int, y: Int) -> Int + +/// Calculates the result of an arithmetic right bitshift. +/// +/// The exact behaviour of this function depends on the target platform. +/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it +/// is equivalent to bitwise operations on big-ints. +/// +@external(erlang, "erlang", "bsr") +@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_right") +pub fn bitwise_shift_right(x: Int, y: Int) -> Int diff --git a/build/packages/gleam_stdlib/src/gleam/io.gleam b/build/packages/gleam_stdlib/src/gleam/io.gleam new file mode 100644 index 0000000..67088eb --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/io.gleam @@ -0,0 +1,59 @@ +/// Writes a string to standard output (stdout). +/// +/// If you want your output to be printed on its own line see `println`. +/// +/// ## Example +/// +/// ```gleam +/// io.print("Hi mum") +/// // -> Nil +/// // Hi mum +/// ``` +/// +@external(erlang, "gleam_stdlib", "print") +@external(javascript, "../gleam_stdlib.mjs", "print") +pub fn print(string: String) -> Nil + +/// Writes a string to standard error (stderr). +/// +/// If you want your output to be printed on its own line see `println_error`. +/// +/// ## Example +/// +/// ``` +/// io.print_error("Hi pop") +/// // -> Nil +/// // Hi pop +/// ``` +/// +@external(erlang, "gleam_stdlib", "print_error") +@external(javascript, "../gleam_stdlib.mjs", "print_error") +pub fn print_error(string: String) -> Nil + +/// Writes a string to standard output (stdout), appending a newline to the end. +/// +/// ## Example +/// +/// ```gleam +/// io.println("Hi mum") +/// // -> Nil +/// // Hi mum +/// ``` +/// +@external(erlang, "gleam_stdlib", "println") +@external(javascript, "../gleam_stdlib.mjs", "console_log") +pub fn println(string: String) -> Nil + +/// Writes a string to standard error (stderr), appending a newline to the end. +/// +/// ## Example +/// +/// ```gleam +/// io.println_error("Hi pop") +/// // -> Nil +/// // Hi pop +/// ``` +/// +@external(erlang, "gleam_stdlib", "println_error") +@external(javascript, "../gleam_stdlib.mjs", "console_error") +pub fn println_error(string: String) -> Nil diff --git a/build/packages/gleam_stdlib/src/gleam/list.gleam b/build/packages/gleam_stdlib/src/gleam/list.gleam new file mode 100644 index 0000000..551480b --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/list.gleam @@ -0,0 +1,2394 @@ +//// Lists are an ordered sequence of elements and are one of the most common +//// data types in Gleam. +//// +//// New elements can be added and removed from the front of a list in +//// constant time, while adding and removing from the end requires traversing +//// and copying the whole list, so keep this in mind when designing your +//// programs. +//// +//// There is a dedicated syntax for prefixing to a list: +//// +//// ```gleam +//// let new_list = [1, 2, ..existing_list] +//// ``` +//// +//// And a matching syntax for getting the first elements of a list: +//// +//// ```gleam +//// case list { +//// [first_element, ..rest] -> first_element +//// _ -> "this pattern matches when the list is empty" +//// } +//// ``` +//// + +import gleam/dict.{type Dict} +import gleam/float +import gleam/int +import gleam/order.{type Order} + +/// Counts the number of elements in a given list. +/// +/// This function has to traverse the list to determine the number of elements, +/// so it runs in linear time. +/// +/// This function is natively implemented by the virtual machine and is highly +/// optimised. +/// +/// ## Examples +/// +/// ```gleam +/// length([]) +/// // -> 0 +/// ``` +/// +/// ```gleam +/// length([1]) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// length([1, 2]) +/// // -> 2 +/// ``` +/// +@external(erlang, "erlang", "length") +pub fn length(of list: List(a)) -> Int { + length_loop(list, 0) +} + +fn length_loop(list: List(a), count: Int) -> Int { + case list { + [_, ..list] -> length_loop(list, count + 1) + [] -> count + } +} + +/// Counts the number of elements in a given list satisfying a given predicate. +/// +/// This function has to traverse the list to determine the number of elements, +/// so it runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// count([], fn(a) { a > 0 }) +/// // -> 0 +/// ``` +/// +/// ```gleam +/// count([1], fn(a) { a > 0 }) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// count([1, 2, 3], int.is_odd) +/// // -> 2 +/// ``` +/// +pub fn count(list: List(a), where predicate: fn(a) -> Bool) -> Int { + count_loop(list, predicate, 0) +} + +fn count_loop(list: List(a), predicate: fn(a) -> Bool, acc: Int) -> Int { + case list { + [] -> acc + [first, ..rest] -> + case predicate(first) { + True -> count_loop(rest, predicate, acc + 1) + False -> count_loop(rest, predicate, acc) + } + } +} + +/// Creates a new list from a given list containing the same elements but in the +/// opposite order. +/// +/// This function has to traverse the list to create the new reversed list, so +/// it runs in linear time. +/// +/// This function is natively implemented by the virtual machine and is highly +/// optimised. +/// +/// ## Examples +/// +/// ```gleam +/// reverse([]) +/// // -> [] +/// ``` +/// +/// ```gleam +/// reverse([1]) +/// // -> [1] +/// ``` +/// +/// ```gleam +/// reverse([1, 2]) +/// // -> [2, 1] +/// ``` +/// +@external(erlang, "lists", "reverse") +pub fn reverse(list: List(a)) -> List(a) { + reverse_and_prepend(list, []) +} + +/// Reverses a list and prepends it to another list. +/// This function runs in linear time, proportional to the length of the list +/// to prepend. +/// +fn reverse_and_prepend(list prefix: List(a), to suffix: List(a)) -> List(a) { + case prefix { + [] -> suffix + [first, ..rest] -> reverse_and_prepend(list: rest, to: [first, ..suffix]) + } +} + +/// Determines whether or not the list is empty. +/// +/// This function runs in constant time. +/// +/// ## Examples +/// +/// ```gleam +/// is_empty([]) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_empty([1]) +/// // -> False +/// ``` +/// +/// ```gleam +/// is_empty([1, 1]) +/// // -> False +/// ``` +/// +pub fn is_empty(list: List(a)) -> Bool { + list == [] +} + +/// Determines whether or not a given element exists within a given list. +/// +/// This function traverses the list to find the element, so it runs in linear +/// time. +/// +/// ## Examples +/// +/// ```gleam +/// [] |> contains(any: 0) +/// // -> False +/// ``` +/// +/// ```gleam +/// [0] |> contains(any: 0) +/// // -> True +/// ``` +/// +/// ```gleam +/// [1] |> contains(any: 0) +/// // -> False +/// ``` +/// +/// ```gleam +/// [1, 1] |> contains(any: 0) +/// // -> False +/// ``` +/// +/// ```gleam +/// [1, 0] |> contains(any: 0) +/// // -> True +/// ``` +/// +pub fn contains(list: List(a), any elem: a) -> Bool { + case list { + [] -> False + [first, ..] if first == elem -> True + [_, ..rest] -> contains(rest, elem) + } +} + +/// Gets the first element from the start of the list, if there is one. +/// +/// ## Examples +/// +/// ```gleam +/// first([]) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// first([0]) +/// // -> Ok(0) +/// ``` +/// +/// ```gleam +/// first([1, 2]) +/// // -> Ok(1) +/// ``` +/// +pub fn first(list: List(a)) -> Result(a, Nil) { + case list { + [] -> Error(Nil) + [first, ..] -> Ok(first) + } +} + +/// Returns the list minus the first element. If the list is empty, `Error(Nil)` is +/// returned. +/// +/// This function runs in constant time and does not make a copy of the list. +/// +/// ## Examples +/// +/// ```gleam +/// rest([]) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// rest([0]) +/// // -> Ok([]) +/// ``` +/// +/// ```gleam +/// rest([1, 2]) +/// // -> Ok([2]) +/// ``` +/// +pub fn rest(list: List(a)) -> Result(List(a), Nil) { + case list { + [] -> Error(Nil) + [_, ..rest] -> Ok(rest) + } +} + +/// Groups the elements from the given list by the given key function. +/// +/// Does not preserve the initial value order. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/dict +/// +/// [Ok(3), Error("Wrong"), Ok(200), Ok(73)] +/// |> group(by: fn(i) { +/// case i { +/// Ok(_) -> "Successful" +/// Error(_) -> "Failed" +/// } +/// }) +/// |> dict.to_list +/// // -> [ +/// // #("Failed", [Error("Wrong")]), +/// // #("Successful", [Ok(73), Ok(200), Ok(3)]) +/// // ] +/// ``` +/// +/// ```gleam +/// import gleam/dict +/// +/// group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 }) +/// |> dict.to_list +/// // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])] +/// ``` +/// +pub fn group(list: List(v), by key: fn(v) -> k) -> Dict(k, List(v)) { + group_loop(list, key, dict.new()) +} + +fn group_loop( + list: List(v), + to_key: fn(v) -> k, + groups: Dict(k, List(v)), +) -> Dict(k, List(v)) { + case list { + [] -> groups + [first, ..rest] -> { + let key = to_key(first) + let groups = case dict.get(groups, key) { + Error(_) -> dict.insert(groups, key, [first]) + Ok(existing) -> dict.insert(groups, key, [first, ..existing]) + } + group_loop(rest, to_key, groups) + } + } +} + +/// Returns a new list containing only the elements from the first list for +/// which the given functions returns `True`. +/// +/// ## Examples +/// +/// ```gleam +/// filter([2, 4, 6, 1], fn(x) { x > 2 }) +/// // -> [4, 6] +/// ``` +/// +/// ```gleam +/// filter([2, 4, 6, 1], fn(x) { x > 6 }) +/// // -> [] +/// ``` +/// +pub fn filter(list: List(a), keeping predicate: fn(a) -> Bool) -> List(a) { + filter_loop(list, predicate, []) +} + +fn filter_loop(list: List(a), fun: fn(a) -> Bool, acc: List(a)) -> List(a) { + case list { + [] -> reverse(acc) + [first, ..rest] -> { + let new_acc = case fun(first) { + True -> [first, ..acc] + False -> acc + } + filter_loop(rest, fun, new_acc) + } + } +} + +/// Returns a new list containing only the elements from the first list for +/// which the given functions returns `Ok(_)`. +/// +/// ## Examples +/// +/// ```gleam +/// filter_map([2, 4, 6, 1], Error) +/// // -> [] +/// ``` +/// +/// ```gleam +/// filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) }) +/// // -> [3, 5, 7, 2] +/// ``` +/// +pub fn filter_map(list: List(a), with fun: fn(a) -> Result(b, e)) -> List(b) { + filter_map_loop(list, fun, []) +} + +fn filter_map_loop( + list: List(a), + fun: fn(a) -> Result(b, e), + acc: List(b), +) -> List(b) { + case list { + [] -> reverse(acc) + [first, ..rest] -> { + let new_acc = case fun(first) { + Ok(first) -> [first, ..acc] + Error(_) -> acc + } + filter_map_loop(rest, fun, new_acc) + } + } +} + +/// Returns a new list containing only the elements of the first list after the +/// function has been applied to each one. +/// +/// ## Examples +/// +/// ```gleam +/// map([2, 4, 6], fn(x) { x * 2 }) +/// // -> [4, 8, 12] +/// ``` +/// +pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { + map_loop(list, fun, []) +} + +fn map_loop(list: List(a), fun: fn(a) -> b, acc: List(b)) -> List(b) { + case list { + [] -> reverse(acc) + [first, ..rest] -> map_loop(rest, fun, [fun(first), ..acc]) + } +} + +/// Combines two lists into a single list using the given function. +/// +/// If a list is longer than the other the extra elements are dropped. +/// +/// ## Examples +/// +/// ```gleam +/// map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y }) +/// // -> [5, 7, 9] +/// ``` +/// +/// ```gleam +/// map2([1, 2], ["a", "b", "c"], fn(i, x) { #(i, x) }) +/// // -> [#(1, "a"), #(2, "b")] +/// ``` +/// +pub fn map2(list1: List(a), list2: List(b), with fun: fn(a, b) -> c) -> List(c) { + map2_loop(list1, list2, fun, []) +} + +fn map2_loop( + list1: List(a), + list2: List(b), + fun: fn(a, b) -> c, + acc: List(c), +) -> List(c) { + case list1, list2 { + [], _ | _, [] -> reverse(acc) + [a, ..as_], [b, ..bs] -> map2_loop(as_, bs, fun, [fun(a, b), ..acc]) + } +} + +/// Similar to `map` but also lets you pass around an accumulated value. +/// +/// ## Examples +/// +/// ```gleam +/// map_fold( +/// over: [1, 2, 3], +/// from: 100, +/// with: fn(memo, i) { #(memo + i, i * 2) } +/// ) +/// // -> #(106, [2, 4, 6]) +/// ``` +/// +pub fn map_fold( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> #(acc, b), +) -> #(acc, List(b)) { + map_fold_loop(list, fun, initial, []) +} + +fn map_fold_loop( + list: List(a), + fun: fn(acc, a) -> #(acc, b), + acc: acc, + list_acc: List(b), +) -> #(acc, List(b)) { + case list { + [] -> #(acc, reverse(list_acc)) + [first, ..rest] -> { + let #(acc, first) = fun(acc, first) + map_fold_loop(rest, fun, acc, [first, ..list_acc]) + } + } +} + +/// Returns a new list containing only the elements of the first list after the +/// function has been applied to each one and their index. +/// +/// The index starts at 0, so the first element is 0, the second is 1, and so +/// on. +/// +/// ## Examples +/// +/// ```gleam +/// index_map(["a", "b"], fn(x, i) { #(i, x) }) +/// // -> [#(0, "a"), #(1, "b")] +/// ``` +/// +pub fn index_map(list: List(a), with fun: fn(a, Int) -> b) -> List(b) { + index_map_loop(list, fun, 0, []) +} + +fn index_map_loop( + list: List(a), + fun: fn(a, Int) -> b, + index: Int, + acc: List(b), +) -> List(b) { + case list { + [] -> reverse(acc) + [first, ..rest] -> { + let acc = [fun(first, index), ..acc] + index_map_loop(rest, fun, index + 1, acc) + } + } +} + +/// Takes a function that returns a `Result` and applies it to each element in a +/// given list in turn. +/// +/// If the function returns `Ok(new_value)` for all elements in the list then a +/// list of the new values is returned. +/// +/// If the function returns `Error(reason)` for any of the elements then it is +/// returned immediately. None of the elements in the list are processed after +/// one returns an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// try_map([1, 2, 3], fn(x) { Ok(x + 2) }) +/// // -> Ok([3, 4, 5]) +/// ``` +/// +/// ```gleam +/// try_map([1, 2, 3], fn(_) { Error(0) }) +/// // -> Error(0) +/// ``` +/// +/// ```gleam +/// try_map([[1], [2, 3]], first) +/// // -> Ok([1, 2]) +/// ``` +/// +/// ```gleam +/// try_map([[1], [], [2]], first) +/// // -> Error(Nil) +/// ``` +/// +pub fn try_map( + over list: List(a), + with fun: fn(a) -> Result(b, e), +) -> Result(List(b), e) { + try_map_loop(list, fun, []) +} + +fn try_map_loop( + list: List(a), + fun: fn(a) -> Result(b, e), + acc: List(b), +) -> Result(List(b), e) { + case list { + [] -> Ok(reverse(acc)) + [first, ..rest] -> + case fun(first) { + Ok(first) -> try_map_loop(rest, fun, [first, ..acc]) + Error(error) -> Error(error) + } + } +} + +/// Returns a list that is the given list with up to the given number of +/// elements removed from the front of the list. +/// +/// If the element has less than the number of elements an empty list is +/// returned. +/// +/// This function runs in linear time but does not copy the list. +/// +/// ## Examples +/// +/// ```gleam +/// drop([1, 2, 3, 4], 2) +/// // -> [3, 4] +/// ``` +/// +/// ```gleam +/// drop([1, 2, 3, 4], 9) +/// // -> [] +/// ``` +/// +pub fn drop(from list: List(a), up_to n: Int) -> List(a) { + case n <= 0 { + True -> list + False -> + case list { + [] -> [] + [_, ..rest] -> drop(rest, n - 1) + } + } +} + +/// Returns a list containing the first given number of elements from the given +/// list. +/// +/// If the element has less than the number of elements then the full list is +/// returned. +/// +/// This function runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// take([1, 2, 3, 4], 2) +/// // -> [1, 2] +/// ``` +/// +/// ```gleam +/// take([1, 2, 3, 4], 9) +/// // -> [1, 2, 3, 4] +/// ``` +/// +pub fn take(from list: List(a), up_to n: Int) -> List(a) { + take_loop(list, n, []) +} + +fn take_loop(list: List(a), n: Int, acc: List(a)) -> List(a) { + case n <= 0 { + True -> reverse(acc) + False -> + case list { + [] -> reverse(acc) + [first, ..rest] -> take_loop(rest, n - 1, [first, ..acc]) + } + } +} + +/// Returns a new empty list. +/// +/// ## Examples +/// +/// ```gleam +/// new() +/// // -> [] +/// ``` +/// +pub fn new() -> List(a) { + [] +} + +/// Returns the given item wrapped in a list. +/// +/// ## Examples +/// +/// ```gleam +/// wrap(1) +/// // -> [1] +/// +/// wrap(["a", "b", "c"]) +/// // -> [["a", "b", "c"]] +/// +/// wrap([[]]) +/// // -> [[[]]] +/// ``` +/// +/// +pub fn wrap(item: a) -> List(a) { + [item] +} + +/// Joins one list onto the end of another. +/// +/// This function runs in linear time, and it traverses and copies the first +/// list. +/// +/// ## Examples +/// +/// ```gleam +/// append([1, 2], [3]) +/// // -> [1, 2, 3] +/// ``` +/// +@external(erlang, "lists", "append") +pub fn append(first: List(a), second: List(a)) -> List(a) { + append_loop(reverse(first), second) +} + +fn append_loop(first: List(a), second: List(a)) -> List(a) { + case first { + [] -> second + [first, ..rest] -> append_loop(rest, [first, ..second]) + } +} + +/// Prefixes an item to a list. This can also be done using the dedicated +/// syntax instead +/// +/// ```gleam +/// let existing_list = [2, 3, 4] +/// +/// [1, ..existing_list] +/// // -> [1, 2, 3, 4] +/// +/// prepend(to: existing_list, this: 1) +/// // -> [1, 2, 3, 4] +/// ``` +/// +pub fn prepend(to list: List(a), this item: a) -> List(a) { + [item, ..list] +} + +/// Joins a list of lists into a single list. +/// +/// This function traverses all elements twice on the JavaScript target. +/// This function traverses all elements once on the Erlang target. +/// +/// ## Examples +/// +/// ```gleam +/// flatten([[1], [2, 3], []]) +/// // -> [1, 2, 3] +/// ``` +/// +@external(erlang, "lists", "append") +pub fn flatten(lists: List(List(a))) -> List(a) { + flatten_loop(lists, []) +} + +fn flatten_loop(lists: List(List(a)), acc: List(a)) -> List(a) { + case lists { + [] -> reverse(acc) + [list, ..further_lists] -> + flatten_loop(further_lists, reverse_and_prepend(list, to: acc)) + } +} + +/// Maps the list with the given function into a list of lists, and then flattens it. +/// +/// ## Examples +/// +/// ```gleam +/// flat_map([2, 4, 6], fn(x) { [x, x + 1] }) +/// // -> [2, 3, 4, 5, 6, 7] +/// ``` +/// +pub fn flat_map(over list: List(a), with fun: fn(a) -> List(b)) -> List(b) { + flatten(map(list, fun)) +} + +/// Reduces a list of elements into a single value by calling a given function +/// on each element, going from left to right. +/// +/// `fold([1, 2, 3], 0, add)` is the equivalent of +/// `add(add(add(0, 1), 2), 3)`. +/// +/// This function runs in linear time. +/// +pub fn fold( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> acc, +) -> acc { + case list { + [] -> initial + [first, ..rest] -> fold(rest, fun(initial, first), fun) + } +} + +/// Reduces a list of elements into a single value by calling a given function +/// on each element, going from right to left. +/// +/// `fold_right([1, 2, 3], 0, add)` is the equivalent of +/// `add(add(add(0, 3), 2), 1)`. +/// +/// This function runs in linear time. +/// +/// Unlike `fold` this function is not tail recursive. Where possible use +/// `fold` instead as it will use less memory. +/// +pub fn fold_right( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> acc, +) -> acc { + case list { + [] -> initial + [first, ..rest] -> fun(fold_right(rest, initial, fun), first) + } +} + +/// Like fold but the folding function also receives the index of the current element. +/// +/// ## Examples +/// +/// ```gleam +/// ["a", "b", "c"] +/// |> index_fold([], fn(acc, item, index) { ... }) +/// ``` +/// +pub fn index_fold( + over list: List(a), + from initial: acc, + with fun: fn(acc, a, Int) -> acc, +) -> acc { + index_fold_loop(list, initial, fun, 0) +} + +fn index_fold_loop( + over: List(a), + acc: acc, + with: fn(acc, a, Int) -> acc, + index: Int, +) -> acc { + case over { + [] -> acc + [first, ..rest] -> + index_fold_loop(rest, with(acc, first, index), with, index + 1) + } +} + +/// A variant of fold that might fail. +/// +/// The folding function should return `Result(accumulator, error)`. +/// If the returned value is `Ok(accumulator)` try_fold will try the next value in the list. +/// If the returned value is `Error(error)` try_fold will stop and return that error. +/// +/// ## Examples +/// +/// ```gleam +/// [1, 2, 3, 4] +/// |> try_fold(0, fn(acc, i) { +/// case i < 3 { +/// True -> Ok(acc + i) +/// False -> Error(Nil) +/// } +/// }) +/// // -> Error(Nil) +/// ``` +/// +pub fn try_fold( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> Result(acc, e), +) -> Result(acc, e) { + case list { + [] -> Ok(initial) + [first, ..rest] -> + case fun(initial, first) { + Ok(result) -> try_fold(rest, result, fun) + Error(_) as error -> error + } + } +} + +pub type ContinueOrStop(a) { + Continue(a) + Stop(a) +} + +/// A variant of fold that allows to stop folding earlier. +/// +/// The folding function should return `ContinueOrStop(accumulator)`. +/// If the returned value is `Continue(accumulator)` fold_until will try the next value in the list. +/// If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator. +/// +/// ## Examples +/// +/// ```gleam +/// [1, 2, 3, 4] +/// |> fold_until(0, fn(acc, i) { +/// case i < 3 { +/// True -> Continue(acc + i) +/// False -> Stop(acc) +/// } +/// }) +/// // -> 3 +/// ``` +/// +pub fn fold_until( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> ContinueOrStop(acc), +) -> acc { + case list { + [] -> initial + [first, ..rest] -> + case fun(initial, first) { + Continue(next_accumulator) -> fold_until(rest, next_accumulator, fun) + Stop(b) -> b + } + } +} + +/// Finds the first element in a given list for which the given function returns +/// `True`. +/// +/// Returns `Error(Nil)` if no such element is found. +/// +/// ## Examples +/// +/// ```gleam +/// find([1, 2, 3], fn(x) { x > 2 }) +/// // -> Ok(3) +/// ``` +/// +/// ```gleam +/// find([1, 2, 3], fn(x) { x > 4 }) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// find([], fn(_) { True }) +/// // -> Error(Nil) +/// ``` +/// +pub fn find( + in list: List(a), + one_that is_desired: fn(a) -> Bool, +) -> Result(a, Nil) { + case list { + [] -> Error(Nil) + [first, ..rest] -> + case is_desired(first) { + True -> Ok(first) + False -> find(in: rest, one_that: is_desired) + } + } +} + +/// Finds the first element in a given list for which the given function returns +/// `Ok(new_value)`, then returns the wrapped `new_value`. +/// +/// Returns `Error(Nil)` if no such element is found. +/// +/// ## Examples +/// +/// ```gleam +/// find_map([[], [2], [3]], first) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// find_map([[], []], first) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// find_map([], first) +/// // -> Error(Nil) +/// ``` +/// +pub fn find_map( + in list: List(a), + with fun: fn(a) -> Result(b, c), +) -> Result(b, Nil) { + case list { + [] -> Error(Nil) + [first, ..rest] -> + case fun(first) { + Ok(first) -> Ok(first) + Error(_) -> find_map(in: rest, with: fun) + } + } +} + +/// Returns `True` if the given function returns `True` for all the elements in +/// the given list. If the function returns `False` for any of the elements it +/// immediately returns `False` without checking the rest of the list. +/// +/// ## Examples +/// +/// ```gleam +/// all([], fn(x) { x > 3 }) +/// // -> True +/// ``` +/// +/// ```gleam +/// all([4, 5], fn(x) { x > 3 }) +/// // -> True +/// ``` +/// +/// ```gleam +/// all([4, 3], fn(x) { x > 3 }) +/// // -> False +/// ``` +/// +pub fn all(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool { + case list { + [] -> True + [first, ..rest] -> + case predicate(first) { + True -> all(rest, predicate) + False -> False + } + } +} + +/// Returns `True` if the given function returns `True` for any the elements in +/// the given list. If the function returns `True` for any of the elements it +/// immediately returns `True` without checking the rest of the list. +/// +/// ## Examples +/// +/// ```gleam +/// any([], fn(x) { x > 3 }) +/// // -> False +/// ``` +/// +/// ```gleam +/// any([4, 5], fn(x) { x > 3 }) +/// // -> True +/// ``` +/// +/// ```gleam +/// any([4, 3], fn(x) { x > 4 }) +/// // -> False +/// ``` +/// +/// ```gleam +/// any([3, 4], fn(x) { x > 3 }) +/// // -> True +/// ``` +/// +pub fn any(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool { + case list { + [] -> False + [first, ..rest] -> + case predicate(first) { + True -> True + False -> any(rest, predicate) + } + } +} + +/// Takes two lists and returns a single list of 2-element tuples. +/// +/// If one of the lists is longer than the other, the remaining elements from +/// the longer list are not used. +/// +/// ## Examples +/// +/// ```gleam +/// zip([], []) +/// // -> [] +/// ``` +/// +/// ```gleam +/// zip([1, 2], [3]) +/// // -> [#(1, 3)] +/// ``` +/// +/// ```gleam +/// zip([1], [3, 4]) +/// // -> [#(1, 3)] +/// ``` +/// +/// ```gleam +/// zip([1, 2], [3, 4]) +/// // -> [#(1, 3), #(2, 4)] +/// ``` +/// +pub fn zip(list: List(a), with other: List(b)) -> List(#(a, b)) { + zip_loop(list, other, []) +} + +fn zip_loop(one: List(a), other: List(b), acc: List(#(a, b))) -> List(#(a, b)) { + case one, other { + [first_one, ..rest_one], [first_other, ..rest_other] -> + zip_loop(rest_one, rest_other, [#(first_one, first_other), ..acc]) + _, _ -> reverse(acc) + } +} + +/// Takes two lists and returns a single list of 2-element tuples. +/// +/// If one of the lists is longer than the other, an `Error` is returned. +/// +/// ## Examples +/// +/// ```gleam +/// strict_zip([], []) +/// // -> Ok([]) +/// ``` +/// +/// ```gleam +/// strict_zip([1, 2], [3]) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// strict_zip([1], [3, 4]) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// strict_zip([1, 2], [3, 4]) +/// // -> Ok([#(1, 3), #(2, 4)]) +/// ``` +/// +pub fn strict_zip( + list: List(a), + with other: List(b), +) -> Result(List(#(a, b)), Nil) { + strict_zip_loop(list, other, []) +} + +fn strict_zip_loop( + one: List(a), + other: List(b), + acc: List(#(a, b)), +) -> Result(List(#(a, b)), Nil) { + case one, other { + [], [] -> Ok(reverse(acc)) + [], _ | _, [] -> Error(Nil) + [first_one, ..rest_one], [first_other, ..rest_other] -> + strict_zip_loop(rest_one, rest_other, [#(first_one, first_other), ..acc]) + } +} + +/// Takes a single list of 2-element tuples and returns two lists. +/// +/// ## Examples +/// +/// ```gleam +/// unzip([#(1, 2), #(3, 4)]) +/// // -> #([1, 3], [2, 4]) +/// ``` +/// +/// ```gleam +/// unzip([]) +/// // -> #([], []) +/// ``` +/// +pub fn unzip(input: List(#(a, b))) -> #(List(a), List(b)) { + unzip_loop(input, [], []) +} + +fn unzip_loop( + input: List(#(a, b)), + one: List(a), + other: List(b), +) -> #(List(a), List(b)) { + case input { + [] -> #(reverse(one), reverse(other)) + [#(first_one, first_other), ..rest] -> + unzip_loop(rest, [first_one, ..one], [first_other, ..other]) + } +} + +/// Inserts a given value between each existing element in a given list. +/// +/// This function runs in linear time and copies the list. +/// +/// ## Examples +/// +/// ```gleam +/// intersperse([1, 1, 1], 2) +/// // -> [1, 2, 1, 2, 1] +/// ``` +/// +/// ```gleam +/// intersperse([], 2) +/// // -> [] +/// ``` +/// +pub fn intersperse(list: List(a), with elem: a) -> List(a) { + case list { + [] | [_] -> list + [first, ..rest] -> intersperse_loop(rest, elem, [first]) + } +} + +fn intersperse_loop(list: List(a), separator: a, acc: List(a)) -> List(a) { + case list { + [] -> reverse(acc) + [first, ..rest] -> + intersperse_loop(rest, separator, [first, separator, ..acc]) + } +} + +/// Removes any duplicate elements from a given list. +/// +/// This function returns in loglinear time. +/// +/// ## Examples +/// +/// ```gleam +/// unique([1, 1, 1, 4, 7, 3, 3, 4]) +/// // -> [1, 4, 7, 3] +/// ``` +/// +pub fn unique(list: List(a)) -> List(a) { + unique_loop(list, dict.new(), []) +} + +fn unique_loop(list: List(a), seen: Dict(a, Nil), acc: List(a)) -> List(a) { + case list { + [] -> reverse(acc) + [first, ..rest] -> + case dict.has_key(seen, first) { + True -> unique_loop(rest, seen, acc) + False -> + unique_loop(rest, dict.insert(seen, first, Nil), [first, ..acc]) + } + } +} + +/// Sorts from smallest to largest based upon the ordering specified by a given +/// function. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// +/// sort([4, 3, 6, 5, 4, 1, 2], by: int.compare) +/// // -> [1, 2, 3, 4, 4, 5, 6] +/// ``` +/// +pub fn sort(list: List(a), by compare: fn(a, a) -> Order) -> List(a) { + // This is a natural, tail recursive, stable merge sort: + // - natural: it is very efficient if you call it on a list that is already + // (pre)sorted because it works on slices of the original list. + // - tail recursive: the stack won't grow linearly with the size of the list. + // - stable: if two items are considered to be equal then their original + // relative order is preserved. + case list { + // If the list has zero/one item then it's already sorted. + [] -> [] + [x] -> [x] + + // Otherwise the algorithm works as follow: we split the list in sequences + // of already sorted values as they appear in the list and then we merge + // those together two by two using `merge_all`. + [x, y, ..rest] -> { + // We need to compare the first two items to properly call `sequences` + // with the correct initial values. If the second item is <= than the + // first, then we know we'll start by growing a descending sequence + // (and an ascending one in the opposite case). + let direction = case compare(x, y) { + order.Lt | order.Eq -> Ascending + order.Gt -> Descending + } + + // `sequences` produces sequences in ascending order so we call the + // `merge_all` function saying it to expect all sequences to be sorted + // that way. + let sequences = sequences(rest, compare, [x], direction, y, []) + merge_all(sequences, Ascending, compare) + } + } +} + +type Sorting { + Ascending + Descending +} + +/// Given a list it returns slices of it that are locally sorted in ascending +/// order. +/// +/// Imagine you have this list: +/// +/// ``` +/// [1, 2, 3, 2, 1, 0] +/// ^^^^^^^ ^^^^^^^ This is a slice in descending order +/// | +/// | This is a slice that is sorted in ascending order +/// ``` +/// +/// So the produced result will contain these two slices, each one sorted in +/// ascending order: `[[1, 2, 3], [0, 1, 2]]`. +/// +/// - `growing` is an accumulator with the current slice being grown +/// - `direction` is the growing direction of the slice being grown, it could +/// either be ascending or strictly descending +/// - `prev` is the previous element that needs to be added to the growing slice +/// it is carried around to check whether we have to keep growing the current +/// slice or not +/// - `acc` is the accumulator containing the slices sorted in ascending order +/// +fn sequences( + list: List(a), + compare: fn(a, a) -> Order, + growing: List(a), + direction: Sorting, + prev: a, + acc: List(List(a)), +) -> List(List(a)) { + // First of all we must not forget to add the previous element to the + // currently growing slice. + let growing = [prev, ..growing] + + case list { + [] -> + case direction { + // Notice how we have to reverse the accumulator we're growing: since + // we always add items to the head, `growing` is built in the opposite + // sorting order of what it actually is in the original list. + Ascending -> [reverse(growing), ..acc] + Descending -> [growing, ..acc] + } + + [new, ..rest] -> + case compare(prev, new), direction { + // In case the new element respects the ordering of the growing + // sequence, then we just keep growing it. + // Notice how a growing sequence is weakly growing (that is it can have + // consecutive equal items) while a decreasing sequence is strictly + // decreasing (no consecutive equal items), this is needed to make the + // algorithm stable! + order.Gt, Descending | order.Lt, Ascending | order.Eq, Ascending -> + sequences(rest, compare, growing, direction, new, acc) + + // We were growing an ascending (descending) sequence and the new item + // is smaller (bigger) than the previous one, this means we have to stop + // growing this sequence and start with a new one whose first item will + // be the one we just found. + order.Gt, Ascending | order.Lt, Descending | order.Eq, Descending -> { + let acc = case direction { + Ascending -> [reverse(growing), ..acc] + Descending -> [growing, ..acc] + } + case rest { + // The list is over so we just create a sequence containing the last + // item we saw and add it to the accumulator before returning it. + [] -> [[new], ..acc] + + // If the list is not over we have a peek at the next item to decide + // in which direction is growing the new sequence and make the + // recursive call with the appropriate arguments. + [next, ..rest] -> { + let direction = case compare(new, next) { + order.Lt | order.Eq -> Ascending + order.Gt -> Descending + } + sequences(rest, compare, [new], direction, next, acc) + } + } + } + } + } +} + +/// Given some some sorted sequences (assumed to be sorted in `direction`) it +/// merges them all together until we're left with just a list sorted in +/// ascending order. +/// +fn merge_all( + sequences: List(List(a)), + direction: Sorting, + compare: fn(a, a) -> Order, +) -> List(a) { + case sequences, direction { + [], _ -> [] + + // If we have a single list in ascending order then we're done. + [sequence], Ascending -> sequence + + // If we have a single list in descending order, we reverse it to make sure + // it's in ascending order and we're done. + [sequence], Descending -> reverse(sequence) + + // Merging together sequences that are in ascending (descending) order + // reverses their order, so the recursive call will assume to be merging + // lists sorted in the opposite order! + _, Ascending -> { + let sequences = merge_ascending_pairs(sequences, compare, []) + merge_all(sequences, Descending, compare) + } + + _, Descending -> { + let sequences = merge_descending_pairs(sequences, compare, []) + merge_all(sequences, Ascending, compare) + } + } +} + +/// Given a list of ascending lists, it merges adjacent pairs into a single +/// descending list, halving their number. +/// It returns a list of the remaining descending lists. +/// +fn merge_ascending_pairs( + sequences: List(List(a)), + compare: fn(a, a) -> Order, + acc: List(List(a)), +) { + case sequences { + [] -> reverse(acc) + + // Beware, if we have just one item left we must reverse it: we take + // ascending lists as input and have to return descending ones. + // If we returned it like it is it would be sorted in ascending order. + [sequence] -> reverse([reverse(sequence), ..acc]) + + [ascending1, ascending2, ..rest] -> { + let descending = merge_ascendings(ascending1, ascending2, compare, []) + merge_ascending_pairs(rest, compare, [descending, ..acc]) + } + } +} + +/// This is the same as merge_ascending_pairs but flipped for descending lists. +/// +fn merge_descending_pairs( + sequences: List(List(a)), + compare: fn(a, a) -> Order, + acc: List(List(a)), +) { + case sequences { + [] -> reverse(acc) + + [sequence] -> reverse([reverse(sequence), ..acc]) + + [descending1, descending2, ..rest] -> { + let ascending = merge_descendings(descending1, descending2, compare, []) + merge_descending_pairs(rest, compare, [ascending, ..acc]) + } + } +} + +/// Merges two lists sorted in ascending order into a single list sorted in +/// descending order according to the given comparator function. +/// +/// This reversing of the sort order is not avoidable if we want to implement +/// merge as a tail recursive function. We could reverse the accumulator before +/// returning it but that would end up being less efficient; so the merging +/// algorithm has to play around this. +/// +fn merge_ascendings( + list1: List(a), + list2: List(a), + compare: fn(a, a) -> Order, + acc: List(a), +) -> List(a) { + case list1, list2 { + [], list | list, [] -> reverse_and_prepend(list, acc) + + [first1, ..rest1], [first2, ..rest2] -> + case compare(first1, first2) { + order.Lt -> merge_ascendings(rest1, list2, compare, [first1, ..acc]) + order.Gt | order.Eq -> + merge_ascendings(list1, rest2, compare, [first2, ..acc]) + } + } +} + +/// This is exactly the same as merge_ascendings but mirrored: it merges two +/// lists sorted in descending order into a single list sorted in ascending +/// order according to the given comparator function. +/// +/// This reversing of the sort order is not avoidable if we want to implement +/// merge as a tail recursive function. We could reverse the accumulator before +/// returning it but that would end up being less efficient; so the merging +/// algorithm has to play around this. +/// +fn merge_descendings( + list1: List(a), + list2: List(a), + compare: fn(a, a) -> Order, + acc: List(a), +) -> List(a) { + case list1, list2 { + [], list | list, [] -> reverse_and_prepend(list, acc) + [first1, ..rest1], [first2, ..rest2] -> + case compare(first1, first2) { + order.Lt -> merge_descendings(list1, rest2, compare, [first2, ..acc]) + order.Gt | order.Eq -> + merge_descendings(rest1, list2, compare, [first1, ..acc]) + } + } +} + +/// Creates a list of ints ranging from a given start and finish. +/// +/// ## Examples +/// +/// ```gleam +/// range(0, 0) +/// // -> [0] +/// ``` +/// +/// ```gleam +/// range(0, 5) +/// // -> [0, 1, 2, 3, 4, 5] +/// ``` +/// +/// ```gleam +/// range(1, -5) +/// // -> [1, 0, -1, -2, -3, -4, -5] +/// ``` +/// +pub fn range(from start: Int, to stop: Int) -> List(Int) { + range_loop(start, stop, []) +} + +fn range_loop(start: Int, stop: Int, acc: List(Int)) -> List(Int) { + case int.compare(start, stop) { + order.Eq -> [stop, ..acc] + order.Gt -> range_loop(start, stop + 1, [stop, ..acc]) + order.Lt -> range_loop(start, stop - 1, [stop, ..acc]) + } +} + +/// Builds a list of a given value a given number of times. +/// +/// ## Examples +/// +/// ```gleam +/// repeat("a", times: 0) +/// // -> [] +/// ``` +/// +/// ```gleam +/// repeat("a", times: 5) +/// // -> ["a", "a", "a", "a", "a"] +/// ``` +/// +pub fn repeat(item a: a, times times: Int) -> List(a) { + repeat_loop(a, times, []) +} + +fn repeat_loop(item: a, times: Int, acc: List(a)) -> List(a) { + case times <= 0 { + True -> acc + False -> repeat_loop(item, times - 1, [item, ..acc]) + } +} + +/// Splits a list in two before the given index. +/// +/// If the list is not long enough to have the given index the before list will +/// be the input list, and the after list will be empty. +/// +/// ## Examples +/// +/// ```gleam +/// split([6, 7, 8, 9], 0) +/// // -> #([], [6, 7, 8, 9]) +/// ``` +/// +/// ```gleam +/// split([6, 7, 8, 9], 2) +/// // -> #([6, 7], [8, 9]) +/// ``` +/// +/// ```gleam +/// split([6, 7, 8, 9], 4) +/// // -> #([6, 7, 8, 9], []) +/// ``` +/// +pub fn split(list list: List(a), at index: Int) -> #(List(a), List(a)) { + split_loop(list, index, []) +} + +fn split_loop(list: List(a), n: Int, taken: List(a)) -> #(List(a), List(a)) { + case n <= 0 { + True -> #(reverse(taken), list) + False -> + case list { + [] -> #(reverse(taken), []) + [first, ..rest] -> split_loop(rest, n - 1, [first, ..taken]) + } + } +} + +/// Splits a list in two before the first element that a given function returns +/// `False` for. +/// +/// If the function returns `True` for all elements the first list will be the +/// input list, and the second list will be empty. +/// +/// ## Examples +/// +/// ```gleam +/// split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 }) +/// // -> #([1, 2, 3], [4, 5]) +/// ``` +/// +/// ```gleam +/// split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 }) +/// // -> #([1, 2, 3, 4, 5], []) +/// ``` +/// +pub fn split_while( + list list: List(a), + satisfying predicate: fn(a) -> Bool, +) -> #(List(a), List(a)) { + split_while_loop(list, predicate, []) +} + +fn split_while_loop( + list: List(a), + f: fn(a) -> Bool, + acc: List(a), +) -> #(List(a), List(a)) { + case list { + [] -> #(reverse(acc), []) + [first, ..rest] -> + case f(first) { + True -> split_while_loop(rest, f, [first, ..acc]) + False -> #(reverse(acc), list) + } + } +} + +/// Given a list of 2-element tuples, finds the first tuple that has a given +/// key as the first element and returns the second element. +/// +/// If no tuple is found with the given key then `Error(Nil)` is returned. +/// +/// This function may be useful for interacting with Erlang code where lists of +/// tuples are common. +/// +/// ## Examples +/// +/// ```gleam +/// key_find([#("a", 0), #("b", 1)], "a") +/// // -> Ok(0) +/// ``` +/// +/// ```gleam +/// key_find([#("a", 0), #("b", 1)], "b") +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// key_find([#("a", 0), #("b", 1)], "c") +/// // -> Error(Nil) +/// ``` +/// +pub fn key_find( + in keyword_list: List(#(k, v)), + find desired_key: k, +) -> Result(v, Nil) { + find_map(keyword_list, fn(keyword) { + let #(key, value) = keyword + case key == desired_key { + True -> Ok(value) + False -> Error(Nil) + } + }) +} + +/// Given a list of 2-element tuples, finds all tuples that have a given +/// key as the first element and returns the second element. +/// +/// This function may be useful for interacting with Erlang code where lists of +/// tuples are common. +/// +/// ## Examples +/// +/// ```gleam +/// key_filter([#("a", 0), #("b", 1), #("a", 2)], "a") +/// // -> [0, 2] +/// ``` +/// +/// ```gleam +/// key_filter([#("a", 0), #("b", 1)], "c") +/// // -> [] +/// ``` +/// +pub fn key_filter( + in keyword_list: List(#(k, v)), + find desired_key: k, +) -> List(v) { + filter_map(keyword_list, fn(keyword) { + let #(key, value) = keyword + case key == desired_key { + True -> Ok(value) + False -> Error(Nil) + } + }) +} + +/// Given a list of 2-element tuples, finds the first tuple that has a given +/// key as the first element. This function will return the second element +/// of the found tuple and list with tuple removed. +/// +/// If no tuple is found with the given key then `Error(Nil)` is returned. +/// +/// ## Examples +/// +/// ```gleam +/// key_pop([#("a", 0), #("b", 1)], "a") +/// // -> Ok(#(0, [#("b", 1)])) +/// ``` +/// +/// ```gleam +/// key_pop([#("a", 0), #("b", 1)], "b") +/// // -> Ok(#(1, [#("a", 0)])) +/// ``` +/// +/// ```gleam +/// key_pop([#("a", 0), #("b", 1)], "c") +/// // -> Error(Nil) +/// ``` +/// +pub fn key_pop(list: List(#(k, v)), key: k) -> Result(#(v, List(#(k, v))), Nil) { + key_pop_loop(list, key, []) +} + +fn key_pop_loop( + list: List(#(k, v)), + key: k, + checked: List(#(k, v)), +) -> Result(#(v, List(#(k, v))), Nil) { + case list { + [] -> Error(Nil) + [#(k, v), ..rest] if k == key -> + Ok(#(v, reverse_and_prepend(checked, rest))) + [first, ..rest] -> key_pop_loop(rest, key, [first, ..checked]) + } +} + +/// Given a list of 2-element tuples, inserts a key and value into the list. +/// +/// If there was already a tuple with the key then it is replaced, otherwise it +/// is added to the end of the list. +/// +/// ## Examples +/// +/// ```gleam +/// key_set([#(5, 0), #(4, 1)], 4, 100) +/// // -> [#(5, 0), #(4, 100)] +/// ``` +/// +/// ```gleam +/// key_set([#(5, 0), #(4, 1)], 1, 100) +/// // -> [#(5, 0), #(4, 1), #(1, 100)] +/// ``` +/// +pub fn key_set(list: List(#(k, v)), key: k, value: v) -> List(#(k, v)) { + key_set_loop(list, key, value, []) +} + +fn key_set_loop( + list: List(#(k, v)), + key: k, + value: v, + inspected: List(#(k, v)), +) -> List(#(k, v)) { + case list { + [#(k, _), ..rest] if k == key -> + reverse_and_prepend(inspected, [#(k, value), ..rest]) + [first, ..rest] -> key_set_loop(rest, key, value, [first, ..inspected]) + [] -> reverse([#(key, value), ..inspected]) + } +} + +/// Calls a function for each element in a list, discarding the return value. +/// +/// Useful for calling a side effect for every item of a list. +/// +/// ```gleam +/// import gleam/io +/// +/// each(["1", "2", "3"], io.println) +/// // -> Nil +/// // 1 +/// // 2 +/// // 3 +/// ``` +/// +pub fn each(list: List(a), f: fn(a) -> b) -> Nil { + case list { + [] -> Nil + [first, ..rest] -> { + f(first) + each(rest, f) + } + } +} + +/// Calls a `Result` returning function for each element in a list, discarding +/// the return value. If the function returns `Error` then the iteration is +/// stopped and the error is returned. +/// +/// Useful for calling a side effect for every item of a list. +/// +/// ## Examples +/// +/// ```gleam +/// try_each( +/// over: [1, 2, 3], +/// with: function_that_might_fail, +/// ) +/// // -> Ok(Nil) +/// ``` +/// +pub fn try_each( + over list: List(a), + with fun: fn(a) -> Result(b, e), +) -> Result(Nil, e) { + case list { + [] -> Ok(Nil) + [first, ..rest] -> + case fun(first) { + Ok(_) -> try_each(over: rest, with: fun) + Error(e) -> Error(e) + } + } +} + +/// Partitions a list into a tuple/pair of lists +/// by a given categorisation function. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// +/// [1, 2, 3, 4, 5] |> partition(int.is_odd) +/// // -> #([1, 3, 5], [2, 4]) +/// ``` +/// +pub fn partition( + list: List(a), + with categorise: fn(a) -> Bool, +) -> #(List(a), List(a)) { + partition_loop(list, categorise, [], []) +} + +fn partition_loop(list, categorise, trues, falses) { + case list { + [] -> #(reverse(trues), reverse(falses)) + [first, ..rest] -> + case categorise(first) { + True -> partition_loop(rest, categorise, [first, ..trues], falses) + False -> partition_loop(rest, categorise, trues, [first, ..falses]) + } + } +} + +/// Returns all the permutations of a list. +/// +/// ## Examples +/// +/// ```gleam +/// permutations([1, 2]) +/// // -> [[1, 2], [2, 1]] +/// ``` +/// +pub fn permutations(list: List(a)) -> List(List(a)) { + case list { + [] -> [[]] + [_, ..] -> + index_map(list, fn(i, i_idx) { + index_fold(list, [], fn(acc, j, j_idx) { + case i_idx == j_idx { + True -> acc + False -> [j, ..acc] + } + }) + |> reverse + |> permutations + |> map(fn(permutation) { [i, ..permutation] }) + }) + |> flatten + } +} + +/// Returns a list of sliding windows. +/// +/// ## Examples +/// +/// ```gleam +/// window([1,2,3,4,5], 3) +/// // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]] +/// ``` +/// +/// ```gleam +/// window([1, 2], 4) +/// // -> [] +/// ``` +/// +pub fn window(list: List(a), by n: Int) -> List(List(a)) { + case n <= 0 { + True -> [] + False -> window_loop([], list, n) + } +} + +fn window_loop(acc: List(List(a)), list: List(a), n: Int) -> List(List(a)) { + let window = take(list, n) + + case length(window) == n { + True -> window_loop([window, ..acc], drop(list, 1), n) + False -> reverse(acc) + } +} + +/// Returns a list of tuples containing two contiguous elements. +/// +/// ## Examples +/// +/// ```gleam +/// window_by_2([1,2,3,4]) +/// // -> [#(1, 2), #(2, 3), #(3, 4)] +/// ``` +/// +/// ```gleam +/// window_by_2([1]) +/// // -> [] +/// ``` +/// +pub fn window_by_2(list: List(a)) -> List(#(a, a)) { + zip(list, drop(list, 1)) +} + +/// Drops the first elements in a given list for which the predicate function returns `True`. +/// +/// ## Examples +/// +/// ```gleam +/// drop_while([1, 2, 3, 4], fn (x) { x < 3 }) +/// // -> [3, 4] +/// ``` +/// +pub fn drop_while( + in list: List(a), + satisfying predicate: fn(a) -> Bool, +) -> List(a) { + case list { + [] -> [] + [first, ..rest] -> + case predicate(first) { + True -> drop_while(rest, predicate) + False -> [first, ..rest] + } + } +} + +/// Takes the first elements in a given list for which the predicate function returns `True`. +/// +/// ## Examples +/// +/// ```gleam +/// take_while([1, 2, 3, 2, 4], fn (x) { x < 3 }) +/// // -> [1, 2] +/// ``` +/// +pub fn take_while( + in list: List(a), + satisfying predicate: fn(a) -> Bool, +) -> List(a) { + take_while_loop(list, predicate, []) +} + +fn take_while_loop( + list: List(a), + predicate: fn(a) -> Bool, + acc: List(a), +) -> List(a) { + case list { + [] -> reverse(acc) + [first, ..rest] -> + case predicate(first) { + True -> take_while_loop(rest, predicate, [first, ..acc]) + False -> reverse(acc) + } + } +} + +/// Returns a list of chunks in which +/// the return value of calling `f` on each element is the same. +/// +/// ## Examples +/// +/// ```gleam +/// [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 }) +/// // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]] +/// ``` +/// +pub fn chunk(in list: List(a), by f: fn(a) -> k) -> List(List(a)) { + case list { + [] -> [] + [first, ..rest] -> chunk_loop(rest, f, f(first), [first], []) + } +} + +fn chunk_loop( + list: List(a), + f: fn(a) -> k, + previous_key: k, + current_chunk: List(a), + acc: List(List(a)), +) -> List(List(a)) { + case list { + [first, ..rest] -> { + let key = f(first) + case key == previous_key { + True -> chunk_loop(rest, f, key, [first, ..current_chunk], acc) + False -> { + let new_acc = [reverse(current_chunk), ..acc] + chunk_loop(rest, f, key, [first], new_acc) + } + } + } + [] -> reverse([reverse(current_chunk), ..acc]) + } +} + +/// Returns a list of chunks containing `count` elements each. +/// +/// If the last chunk does not have `count` elements, it is instead +/// a partial chunk, with less than `count` elements. +/// +/// For any `count` less than 1 this function behaves as if it was set to 1. +/// +/// ## Examples +/// +/// ```gleam +/// [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2) +/// // -> [[1, 2], [3, 4], [5, 6]] +/// ``` +/// +/// ```gleam +/// [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3) +/// // -> [[1, 2, 3], [4, 5, 6], [7, 8]] +/// ``` +/// +pub fn sized_chunk(in list: List(a), into count: Int) -> List(List(a)) { + sized_chunk_loop(list, count, count, [], []) +} + +fn sized_chunk_loop( + list: List(a), + count: Int, + left: Int, + current_chunk: List(a), + acc: List(List(a)), +) -> List(List(a)) { + case list { + [] -> + case current_chunk { + [] -> reverse(acc) + remaining -> reverse([reverse(remaining), ..acc]) + } + [first, ..rest] -> { + let chunk = [first, ..current_chunk] + case left > 1 { + True -> sized_chunk_loop(rest, count, left - 1, chunk, acc) + False -> + sized_chunk_loop(rest, count, count, [], [reverse(chunk), ..acc]) + } + } + } +} + +/// This function acts similar to fold, but does not take an initial state. +/// Instead, it starts from the first element in the list +/// and combines it with each subsequent element in turn using the given +/// function. The function is called as `fun(accumulator, current_element)`. +/// +/// Returns `Ok` to indicate a successful run, and `Error` if called on an +/// empty list. +/// +/// ## Examples +/// +/// ```gleam +/// [] |> reduce(fn(acc, x) { acc + x }) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x }) +/// // -> Ok(15) +/// ``` +/// +pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) { + case list { + [] -> Error(Nil) + [first, ..rest] -> Ok(fold(rest, first, fun)) + } +} + +/// Similar to `fold`, but yields the state of the accumulator at each stage. +/// +/// ## Examples +/// +/// ```gleam +/// scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i }) +/// // -> [101, 103, 106] +/// ``` +/// +pub fn scan( + over list: List(a), + from initial: acc, + with fun: fn(acc, a) -> acc, +) -> List(acc) { + scan_loop(list, initial, [], fun) +} + +fn scan_loop( + list: List(a), + accumulator: acc, + accumulated: List(acc), + fun: fn(acc, a) -> acc, +) -> List(acc) { + case list { + [] -> reverse(accumulated) + [first, ..rest] -> { + let next = fun(accumulator, first) + scan_loop(rest, next, [next, ..accumulated], fun) + } + } +} + +/// Returns the last element in the given list. +/// +/// Returns `Error(Nil)` if the list is empty. +/// +/// This function runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// last([]) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// last([1, 2, 3, 4, 5]) +/// // -> Ok(5) +/// ``` +/// +pub fn last(list: List(a)) -> Result(a, Nil) { + case list { + [] -> Error(Nil) + [last] -> Ok(last) + [_, ..rest] -> last(rest) + } +} + +/// Return unique combinations of elements in the list. +/// +/// ## Examples +/// +/// ```gleam +/// combinations([1, 2, 3], 2) +/// // -> [[1, 2], [1, 3], [2, 3]] +/// ``` +/// +/// ```gleam +/// combinations([1, 2, 3, 4], 3) +/// // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] +/// ``` +/// +pub fn combinations(items: List(a), by n: Int) -> List(List(a)) { + case n, items { + 0, _ -> [[]] + _, [] -> [] + _, [first, ..rest] -> + combinations(rest, n - 1) + |> map(fn(combination) { [first, ..combination] }) + |> reverse + |> fold(combinations(rest, n), fn(acc, c) { [c, ..acc] }) + } +} + +/// Return unique pair combinations of elements in the list. +/// +/// ## Examples +/// +/// ```gleam +/// combination_pairs([1, 2, 3]) +/// // -> [#(1, 2), #(1, 3), #(2, 3)] +/// ``` +/// +pub fn combination_pairs(items: List(a)) -> List(#(a, a)) { + combination_pairs_loop(items, []) +} + +fn combination_pairs_loop(items: List(a), acc: List(#(a, a))) -> List(#(a, a)) { + case items { + [] -> reverse(acc) + [first, ..rest] -> { + let first_combinations = map(rest, with: fn(other) { #(first, other) }) + let acc = reverse_and_prepend(first_combinations, acc) + combination_pairs_loop(rest, acc) + } + } +} + +/// Make a list alternating the elements from the given lists +/// +/// ## Examples +/// +/// ```gleam +/// interleave([[1, 2], [101, 102], [201, 202]]) +/// // -> [1, 101, 201, 2, 102, 202] +/// ``` +/// +pub fn interleave(list: List(List(a))) -> List(a) { + transpose(list) + |> flatten +} + +/// Transpose rows and columns of the list of lists. +/// +/// Notice: This function is not tail recursive, +/// and thus may exceed stack size if called, +/// with large lists (on the JavaScript target). +/// +/// ## Examples +/// +/// ```gleam +/// transpose([[1, 2, 3], [101, 102, 103]]) +/// // -> [[1, 101], [2, 102], [3, 103]] +/// ``` +/// +pub fn transpose(list_of_lists: List(List(a))) -> List(List(a)) { + transpose_loop(list_of_lists, []) +} + +fn transpose_loop(rows: List(List(a)), columns: List(List(a))) -> List(List(a)) { + case rows { + [] -> reverse(columns) + _ -> { + let #(column, rest) = take_firsts(rows, [], []) + case column { + [_, ..] -> transpose_loop(rest, [column, ..columns]) + [] -> transpose_loop(rest, columns) + } + } + } +} + +fn take_firsts( + rows: List(List(a)), + column: List(a), + remaining_rows: List(List(a)), +) -> #(List(a), List(List(a))) { + case rows { + [] -> #(reverse(column), reverse(remaining_rows)) + [[], ..rest] -> take_firsts(rest, column, remaining_rows) + [[first, ..remaining_row], ..rest_rows] -> { + let remaining_rows = [remaining_row, ..remaining_rows] + take_firsts(rest_rows, [first, ..column], remaining_rows) + } + } +} + +/// Takes a list, randomly sorts all items and returns the shuffled list. +/// +/// This function uses `float.random` to decide the order of the elements. +/// +/// ## Example +/// +/// ```gleam +/// range(1, 10) |> shuffle() +/// // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5] +/// ``` +/// +pub fn shuffle(list: List(a)) -> List(a) { + list + |> fold(from: [], with: fn(acc, a) { [#(float.random(), a), ..acc] }) + |> do_shuffle_by_pair_indexes() + |> shuffle_pair_unwrap_loop([]) +} + +fn shuffle_pair_unwrap_loop(list: List(#(Float, a)), acc: List(a)) -> List(a) { + case list { + [] -> acc + [elem_pair, ..enumerable] -> + shuffle_pair_unwrap_loop(enumerable, [elem_pair.1, ..acc]) + } +} + +fn do_shuffle_by_pair_indexes( + list_of_pairs: List(#(Float, a)), +) -> List(#(Float, a)) { + sort(list_of_pairs, fn(a_pair: #(Float, a), b_pair: #(Float, a)) -> Order { + float.compare(a_pair.0, b_pair.0) + }) +} + +/// Takes a list and a comparator, and returns the maximum element in the list +/// +/// +/// ## Example +/// +/// ```gleam +/// range(1, 10) |> list.max(int.compare) +/// // -> Ok(10) +/// ``` +/// +/// ```gleam +/// ["a", "c", "b"] |> list.max(string.compare) +/// // -> Ok("c") +/// ``` +pub fn max( + over list: List(a), + with compare: fn(a, a) -> Order, +) -> Result(a, Nil) { + case list { + [] -> Error(Nil) + [first, ..rest] -> Ok(max_loop(rest, compare, first)) + } +} + +fn max_loop(list, compare, max) { + case list { + [] -> max + [first, ..rest] -> + case compare(first, max) { + order.Gt -> max_loop(rest, compare, first) + order.Lt | order.Eq -> max_loop(rest, compare, max) + } + } +} + +/// Returns a random sample of up to n elements from a list using reservoir +/// sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L). +/// Returns an empty list if the sample size is less than or equal to 0. +/// +/// Order is not random, only selection is. +/// +/// ## Examples +/// +/// ```gleam +/// reservoir_sample([1, 2, 3, 4, 5], 3) +/// // -> [2, 4, 5] // A random sample of 3 items +/// ``` +/// +pub fn sample(from list: List(a), up_to n: Int) -> List(a) { + let #(reservoir, rest) = build_reservoir(from: list, sized: n) + + case dict.is_empty(reservoir) { + // If the reservoire is empty that means we were asking to sample 0 or + // less items. That doesn't make much sense, so we just return an empty + // list. + True -> [] + + // Otherwise we keep looping over the remaining part of the list replacing + // random elements in the reservoir. + False -> { + let w = float.exponential(log_random() /. int.to_float(n)) + dict.values(sample_loop(rest, reservoir, n, w)) + } + } +} + +fn sample_loop( + list: List(a), + reservoir: Dict(Int, a), + n: Int, + w: Float, +) -> Dict(Int, a) { + let skip = { + let assert Ok(log) = float.logarithm(1.0 -. w) + float.round(float.floor(log_random() /. log)) + } + + case drop(list, skip) { + [] -> reservoir + [first, ..rest] -> { + let reservoir = dict.insert(reservoir, int.random(n), first) + let w = w *. float.exponential(log_random() /. int.to_float(n)) + sample_loop(rest, reservoir, n, w) + } + } +} + +const min_positive = 2.2250738585072014e-308 + +fn log_random() -> Float { + let assert Ok(random) = float.logarithm(float.random() +. min_positive) + random +} + +/// Builds the initial reservoir used by Algorithm L. +/// This is a dictionary with keys ranging from `0` up to `n - 1` where each +/// value is the corresponding element at that position in `list`. +/// +/// This also returns the remaining elements of `list` that didn't end up in +/// the reservoir. +/// +fn build_reservoir(from list: List(a), sized n: Int) -> #(Dict(Int, a), List(a)) { + build_reservoir_loop(list, n, dict.new()) +} + +fn build_reservoir_loop( + list: List(a), + size: Int, + reservoir: Dict(Int, a), +) -> #(Dict(Int, a), List(a)) { + let reservoir_size = dict.size(reservoir) + case reservoir_size >= size { + // The reservoir already has the size we wanted. + True -> #(reservoir, list) + + // Otherwise we add another element from the list to the reservoir + False -> + case list { + [] -> #(reservoir, []) + [first, ..rest] -> { + let reservoir = dict.insert(reservoir, reservoir_size, first) + build_reservoir_loop(rest, size, reservoir) + } + } + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/option.gleam b/build/packages/gleam_stdlib/src/gleam/option.gleam new file mode 100644 index 0000000..af5d864 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/option.gleam @@ -0,0 +1,358 @@ +/// `Option` represents a value that may be present or not. `Some` means the value is +/// present, `None` means the value is not. +/// +/// This is Gleam's alternative to having a value that could be Null, as is +/// possible in some other languages. +/// +/// ## `Option` and `Result` +/// +/// In other languages fallible functions may return either `Result` or +/// `Option` depending on whether there is more information to be given about the +/// failure. In Gleam all fallible functions return `Result`, and `Nil` is used +/// as the error if there is no extra detail to give. This consistency removes +/// the boilerplate that would otherwise be needed to convert between `Option` +/// and `Result` types, and makes APIs more predictable. +/// +/// The `Option` type should only be used for taking optional values as +/// function arguments, or for storing them in other data structures. +/// +pub type Option(a) { + Some(a) + None +} + +/// Combines a list of `Option`s into a single `Option`. +/// If all elements in the list are `Some` then returns a `Some` holding the list of values. +/// If any element is `None` then returns`None`. +/// +/// ## Examples +/// +/// ```gleam +/// all([Some(1), Some(2)]) +/// // -> Some([1, 2]) +/// ``` +/// +/// ```gleam +/// all([Some(1), None]) +/// // -> None +/// ``` +/// +pub fn all(list: List(Option(a))) -> Option(List(a)) { + all_loop(list, []) +} + +fn all_loop(list: List(Option(a)), acc: List(a)) -> Option(List(a)) { + case list { + [] -> Some(reverse(acc)) + [None, ..] -> None + [Some(first), ..rest] -> all_loop(rest, [first, ..acc]) + } +} + +// This is copied from the list module and not imported as importing it would +// result in a circular dependency! +@external(erlang, "lists", "reverse") +fn reverse(list: List(a)) -> List(a) { + reverse_and_prepend(list, []) +} + +fn reverse_and_prepend(list prefix: List(a), to suffix: List(a)) -> List(a) { + case prefix { + [] -> suffix + [first, ..rest] -> reverse_and_prepend(list: rest, to: [first, ..suffix]) + } +} + +/// Checks whether the `Option` is a `Some` value. +/// +/// ## Examples +/// +/// ```gleam +/// is_some(Some(1)) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_some(None) +/// // -> False +/// ``` +/// +pub fn is_some(option: Option(a)) -> Bool { + option != None +} + +/// Checks whether the `Option` is a `None` value. +/// +/// ## Examples +/// +/// ```gleam +/// is_none(Some(1)) +/// // -> False +/// ``` +/// +/// ```gleam +/// is_none(None) +/// // -> True +/// ``` +/// +pub fn is_none(option: Option(a)) -> Bool { + option == None +} + +/// Converts an `Option` type to a `Result` type. +/// +/// ## Examples +/// +/// ```gleam +/// to_result(Some(1), "some_error") +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// to_result(None, "some_error") +/// // -> Error("some_error") +/// ``` +/// +pub fn to_result(option: Option(a), e) -> Result(a, e) { + case option { + Some(a) -> Ok(a) + None -> Error(e) + } +} + +/// Converts a `Result` type to an `Option` type. +/// +/// ## Examples +/// +/// ```gleam +/// from_result(Ok(1)) +/// // -> Some(1) +/// ``` +/// +/// ```gleam +/// from_result(Error("some_error")) +/// // -> None +/// ``` +/// +pub fn from_result(result: Result(a, e)) -> Option(a) { + case result { + Ok(a) -> Some(a) + Error(_) -> None + } +} + +/// Extracts the value from an `Option`, returning a default value if there is none. +/// +/// ## Examples +/// +/// ```gleam +/// unwrap(Some(1), 0) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// unwrap(None, 0) +/// // -> 0 +/// ``` +/// +pub fn unwrap(option: Option(a), or default: a) -> a { + case option { + Some(x) -> x + None -> default + } +} + +/// Extracts the value from an `Option`, evaluating the default function if the option is `None`. +/// +/// ## Examples +/// +/// ```gleam +/// lazy_unwrap(Some(1), fn() { 0 }) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// lazy_unwrap(None, fn() { 0 }) +/// // -> 0 +/// ``` +/// +pub fn lazy_unwrap(option: Option(a), or default: fn() -> a) -> a { + case option { + Some(x) -> x + None -> default() + } +} + +/// Updates a value held within the `Some` of an `Option` by calling a given function +/// on it. +/// +/// If the `Option` is a `None` rather than `Some`, the function is not called and the +/// `Option` stays the same. +/// +/// ## Examples +/// +/// ```gleam +/// map(over: Some(1), with: fn(x) { x + 1 }) +/// // -> Some(2) +/// ``` +/// +/// ```gleam +/// map(over: None, with: fn(x) { x + 1 }) +/// // -> None +/// ``` +/// +pub fn map(over option: Option(a), with fun: fn(a) -> b) -> Option(b) { + case option { + Some(x) -> Some(fun(x)) + None -> None + } +} + +/// Merges a nested `Option` into a single layer. +/// +/// ## Examples +/// +/// ```gleam +/// flatten(Some(Some(1))) +/// // -> Some(1) +/// ``` +/// +/// ```gleam +/// flatten(Some(None)) +/// // -> None +/// ``` +/// +/// ```gleam +/// flatten(None) +/// // -> None +/// ``` +/// +pub fn flatten(option: Option(Option(a))) -> Option(a) { + case option { + Some(x) -> x + None -> None + } +} + +/// Updates a value held within the `Some` of an `Option` by calling a given function +/// on it, where the given function also returns an `Option`. The two options are +/// then merged together into one `Option`. +/// +/// If the `Option` is a `None` rather than `Some` the function is not called and the +/// option stays the same. +/// +/// This function is the equivalent of calling `map` followed by `flatten`, and +/// it is useful for chaining together multiple functions that return `Option`. +/// +/// ## Examples +/// +/// ```gleam +/// then(Some(1), fn(x) { Some(x + 1) }) +/// // -> Some(2) +/// ``` +/// +/// ```gleam +/// then(Some(1), fn(x) { Some(#("a", x)) }) +/// // -> Some(#("a", 1)) +/// ``` +/// +/// ```gleam +/// then(Some(1), fn(_) { None }) +/// // -> None +/// ``` +/// +/// ```gleam +/// then(None, fn(x) { Some(x + 1) }) +/// // -> None +/// ``` +/// +pub fn then(option: Option(a), apply fun: fn(a) -> Option(b)) -> Option(b) { + case option { + Some(x) -> fun(x) + None -> None + } +} + +/// Returns the first value if it is `Some`, otherwise returns the second value. +/// +/// ## Examples +/// +/// ```gleam +/// or(Some(1), Some(2)) +/// // -> Some(1) +/// ``` +/// +/// ```gleam +/// or(Some(1), None) +/// // -> Some(1) +/// ``` +/// +/// ```gleam +/// or(None, Some(2)) +/// // -> Some(2) +/// ``` +/// +/// ```gleam +/// or(None, None) +/// // -> None +/// ``` +/// +pub fn or(first: Option(a), second: Option(a)) -> Option(a) { + case first { + Some(_) -> first + None -> second + } +} + +/// Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value. +/// +/// ## Examples +/// +/// ```gleam +/// lazy_or(Some(1), fn() { Some(2) }) +/// // -> Some(1) +/// ``` +/// +/// ```gleam +/// lazy_or(Some(1), fn() { None }) +/// // -> Some(1) +/// ``` +/// +/// ```gleam +/// lazy_or(None, fn() { Some(2) }) +/// // -> Some(2) +/// ``` +/// +/// ```gleam +/// lazy_or(None, fn() { None }) +/// // -> None +/// ``` +/// +pub fn lazy_or(first: Option(a), second: fn() -> Option(a)) -> Option(a) { + case first { + Some(_) -> first + None -> second() + } +} + +/// Given a list of `Option`s, +/// returns only the values inside `Some`. +/// +/// ## Examples +/// +/// ```gleam +/// values([Some(1), None, Some(3)]) +/// // -> [1, 3] +/// ``` +/// +pub fn values(options: List(Option(a))) -> List(a) { + values_loop(options, []) +} + +fn values_loop(list: List(Option(a)), acc: List(a)) -> List(a) { + case list { + [] -> reverse(acc) + [None, ..rest] -> values_loop(rest, acc) + [Some(first), ..rest] -> values_loop(rest, [first, ..acc]) + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/order.gleam b/build/packages/gleam_stdlib/src/gleam/order.gleam new file mode 100644 index 0000000..be8b599 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/order.gleam @@ -0,0 +1,156 @@ +/// Represents the result of a single comparison to determine the precise +/// ordering of two values. +/// +pub type Order { + /// Less-than + Lt + + /// Equal + Eq + + /// Greater than + Gt +} + +/// Inverts an order, so less-than becomes greater-than and greater-than +/// becomes less-than. +/// +/// ## Examples +/// +/// ```gleam +/// negate(Lt) +/// // -> Gt +/// ``` +/// +/// ```gleam +/// negate(Eq) +/// // -> Eq +/// ``` +/// +/// ```gleam +/// negate(Gt) +/// // -> Lt +/// ``` +/// +pub fn negate(order: Order) -> Order { + case order { + Lt -> Gt + Eq -> Eq + Gt -> Lt + } +} + +/// Produces a numeric representation of the order. +/// +/// ## Examples +/// +/// ```gleam +/// to_int(Lt) +/// // -> -1 +/// ``` +/// +/// ```gleam +/// to_int(Eq) +/// // -> 0 +/// ``` +/// +/// ```gleam +/// to_int(Gt) +/// // -> 1 +/// ``` +/// +pub fn to_int(order: Order) -> Int { + case order { + Lt -> -1 + Eq -> 0 + Gt -> 1 + } +} + +/// Compares two `Order` values to one another, producing a new `Order`. +/// +/// ## Examples +/// +/// ```gleam +/// compare(Eq, with: Lt) +/// // -> Gt +/// ``` +/// +pub fn compare(a: Order, with b: Order) -> Order { + case a, b { + x, y if x == y -> Eq + Lt, _ | Eq, Gt -> Lt + _, _ -> Gt + } +} + +/// Inverts an ordering function, so less-than becomes greater-than and greater-than +/// becomes less-than. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// import gleam/list +/// +/// list.sort([1, 5, 4], by: reverse(int.compare)) +/// // -> [5, 4, 1] +/// ``` +/// +pub fn reverse(orderer: fn(a, a) -> Order) -> fn(a, a) -> Order { + fn(a, b) { orderer(b, a) } +} + +/// Return a fallback `Order` in case the first argument is `Eq`. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// +/// break_tie(in: int.compare(1, 1), with: Lt) +/// // -> Lt +/// ``` +/// +/// ```gleam +/// import gleam/int +/// +/// break_tie(in: int.compare(1, 0), with: Eq) +/// // -> Gt +/// ``` +/// +pub fn break_tie(in order: Order, with other: Order) -> Order { + case order { + Lt | Gt -> order + Eq -> other + } +} + +/// Invokes a fallback function returning an `Order` in case the first argument +/// is `Eq`. +/// +/// This can be useful when the fallback comparison might be expensive and it +/// needs to be delayed until strictly necessary. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// +/// lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt }) +/// // -> Lt +/// ``` +/// +/// ```gleam +/// import gleam/int +/// +/// lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq }) +/// // -> Gt +/// ``` +/// +pub fn lazy_break_tie(in order: Order, with comparison: fn() -> Order) -> Order { + case order { + Lt | Gt -> order + Eq -> comparison() + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/pair.gleam b/build/packages/gleam_stdlib/src/gleam/pair.gleam new file mode 100644 index 0000000..566fc9c --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/pair.gleam @@ -0,0 +1,85 @@ +/// Returns the first element in a pair. +/// +/// ## Examples +/// +/// ```gleam +/// first(#(1, 2)) +/// // -> 1 +/// ``` +/// +pub fn first(pair: #(a, b)) -> a { + let #(a, _) = pair + a +} + +/// Returns the second element in a pair. +/// +/// ## Examples +/// +/// ```gleam +/// second(#(1, 2)) +/// // -> 2 +/// ``` +/// +pub fn second(pair: #(a, b)) -> b { + let #(_, a) = pair + a +} + +/// Returns a new pair with the elements swapped. +/// +/// ## Examples +/// +/// ```gleam +/// swap(#(1, 2)) +/// // -> #(2, 1) +/// ``` +/// +pub fn swap(pair: #(a, b)) -> #(b, a) { + let #(a, b) = pair + #(b, a) +} + +/// Returns a new pair with the first element having had `with` applied to +/// it. +/// +/// ## Examples +/// +/// ```gleam +/// #(1, 2) |> map_first(fn(n) { n * 2 }) +/// // -> #(2, 2) +/// ``` +/// +pub fn map_first(of pair: #(a, b), with fun: fn(a) -> c) -> #(c, b) { + let #(a, b) = pair + #(fun(a), b) +} + +/// Returns a new pair with the second element having had `with` applied to +/// it. +/// +/// ## Examples +/// +/// ```gleam +/// #(1, 2) |> map_second(fn(n) { n * 2 }) +/// // -> #(1, 4) +/// ``` +/// +pub fn map_second(of pair: #(a, b), with fun: fn(b) -> c) -> #(a, c) { + let #(a, b) = pair + #(a, fun(b)) +} + +/// Returns a new pair with the given elements. This can also be done using the dedicated +/// syntax instead: `new(1, 2) == #(1, 2)`. +/// +/// ## Examples +/// +/// ```gleam +/// new(1, 2) +/// // -> #(1, 2) +/// ``` +/// +pub fn new(first: a, second: b) -> #(a, b) { + #(first, second) +} diff --git a/build/packages/gleam_stdlib/src/gleam/result.gleam b/build/packages/gleam_stdlib/src/gleam/result.gleam new file mode 100644 index 0000000..c44b800 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/result.gleam @@ -0,0 +1,467 @@ +//// Result represents the result of something that may succeed or not. +//// `Ok` means it was successful, `Error` means it was not successful. + +import gleam/list + +/// Checks whether the result is an `Ok` value. +/// +/// ## Examples +/// +/// ```gleam +/// is_ok(Ok(1)) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_ok(Error(Nil)) +/// // -> False +/// ``` +/// +pub fn is_ok(result: Result(a, e)) -> Bool { + case result { + Error(_) -> False + Ok(_) -> True + } +} + +/// Checks whether the result is an `Error` value. +/// +/// ## Examples +/// +/// ```gleam +/// is_error(Ok(1)) +/// // -> False +/// ``` +/// +/// ```gleam +/// is_error(Error(Nil)) +/// // -> True +/// ``` +/// +pub fn is_error(result: Result(a, e)) -> Bool { + case result { + Ok(_) -> False + Error(_) -> True + } +} + +/// Updates a value held within the `Ok` of a result by calling a given function +/// on it. +/// +/// If the result is an `Error` rather than `Ok` the function is not called and the +/// result stays the same. +/// +/// ## Examples +/// +/// ```gleam +/// map(over: Ok(1), with: fn(x) { x + 1 }) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// map(over: Error(1), with: fn(x) { x + 1 }) +/// // -> Error(1) +/// ``` +/// +pub fn map(over result: Result(a, e), with fun: fn(a) -> b) -> Result(b, e) { + case result { + Ok(x) -> Ok(fun(x)) + Error(e) -> Error(e) + } +} + +/// Updates a value held within the `Error` of a result by calling a given function +/// on it. +/// +/// If the result is `Ok` rather than `Error` the function is not called and the +/// result stays the same. +/// +/// ## Examples +/// +/// ```gleam +/// map_error(over: Error(1), with: fn(x) { x + 1 }) +/// // -> Error(2) +/// ``` +/// +/// ```gleam +/// map_error(over: Ok(1), with: fn(x) { x + 1 }) +/// // -> Ok(1) +/// ``` +/// +pub fn map_error( + over result: Result(a, e), + with fun: fn(e) -> f, +) -> Result(a, f) { + case result { + Ok(x) -> Ok(x) + Error(error) -> Error(fun(error)) + } +} + +/// Merges a nested `Result` into a single layer. +/// +/// ## Examples +/// +/// ```gleam +/// flatten(Ok(Ok(1))) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// flatten(Ok(Error(""))) +/// // -> Error("") +/// ``` +/// +/// ```gleam +/// flatten(Error(Nil)) +/// // -> Error(Nil) +/// ``` +/// +pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) { + case result { + Ok(x) -> x + Error(error) -> Error(error) + } +} + +/// "Updates" an `Ok` result by passing its value to a function that yields a result, +/// and returning the yielded result. (This may "replace" the `Ok` with an `Error`.) +/// +/// If the input is an `Error` rather than an `Ok`, the function is not called and +/// the original `Error` is returned. +/// +/// This function is the equivalent of calling `map` followed by `flatten`, and +/// it is useful for chaining together multiple functions that may fail. +/// +/// ## Examples +/// +/// ```gleam +/// try(Ok(1), fn(x) { Ok(x + 1) }) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// try(Ok(1), fn(x) { Ok(#("a", x)) }) +/// // -> Ok(#("a", 1)) +/// ``` +/// +/// ```gleam +/// try(Ok(1), fn(_) { Error("Oh no") }) +/// // -> Error("Oh no") +/// ``` +/// +/// ```gleam +/// try(Error(Nil), fn(x) { Ok(x + 1) }) +/// // -> Error(Nil) +/// ``` +/// +pub fn try( + result: Result(a, e), + apply fun: fn(a) -> Result(b, e), +) -> Result(b, e) { + case result { + Ok(x) -> fun(x) + Error(e) -> Error(e) + } +} + +@deprecated("This function is an alias of result.try, use that instead") +pub fn then( + result: Result(a, e), + apply fun: fn(a) -> Result(b, e), +) -> Result(b, e) { + try(result, fun) +} + +/// Extracts the `Ok` value from a result, returning a default value if the result +/// is an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// unwrap(Ok(1), 0) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// unwrap(Error(""), 0) +/// // -> 0 +/// ``` +/// +pub fn unwrap(result: Result(a, e), or default: a) -> a { + case result { + Ok(v) -> v + Error(_) -> default + } +} + +/// Extracts the `Ok` value from a result, evaluating the default function if the result +/// is an `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// lazy_unwrap(Ok(1), fn() { 0 }) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// lazy_unwrap(Error(""), fn() { 0 }) +/// // -> 0 +/// ``` +/// +pub fn lazy_unwrap(result: Result(a, e), or default: fn() -> a) -> a { + case result { + Ok(v) -> v + Error(_) -> default() + } +} + +/// Extracts the `Error` value from a result, returning a default value if the result +/// is an `Ok`. +/// +/// ## Examples +/// +/// ```gleam +/// unwrap_error(Error(1), 0) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// unwrap_error(Ok(""), 0) +/// // -> 0 +/// ``` +/// +pub fn unwrap_error(result: Result(a, e), or default: e) -> e { + case result { + Ok(_) -> default + Error(e) -> e + } +} + +/// Extracts the inner value from a result. Both the value and error must be of +/// the same type. +/// +/// ## Examples +/// +/// ```gleam +/// unwrap_both(Error(1)) +/// // -> 1 +/// ``` +/// +/// ```gleam +/// unwrap_both(Ok(2)) +/// // -> 2 +/// ``` +/// +pub fn unwrap_both(result: Result(a, a)) -> a { + case result { + Ok(a) -> a + Error(a) -> a + } +} + +/// Returns the first value if it is `Ok`, otherwise returns the second value. +/// +/// ## Examples +/// +/// ```gleam +/// or(Ok(1), Ok(2)) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// or(Ok(1), Error("Error 2")) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// or(Error("Error 1"), Ok(2)) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// or(Error("Error 1"), Error("Error 2")) +/// // -> Error("Error 2") +/// ``` +/// +pub fn or(first: Result(a, e), second: Result(a, e)) -> Result(a, e) { + case first { + Ok(_) -> first + Error(_) -> second + } +} + +/// Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value. +/// +/// If you need access to the initial error value, use `result.try_recover`. +/// +/// ## Examples +/// +/// ```gleam +/// lazy_or(Ok(1), fn() { Ok(2) }) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// lazy_or(Ok(1), fn() { Error("Error 2") }) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// lazy_or(Error("Error 1"), fn() { Ok(2) }) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// lazy_or(Error("Error 1"), fn() { Error("Error 2") }) +/// // -> Error("Error 2") +/// ``` +/// +pub fn lazy_or( + first: Result(a, e), + second: fn() -> Result(a, e), +) -> Result(a, e) { + case first { + Ok(_) -> first + Error(_) -> second() + } +} + +/// Combines a list of results into a single result. +/// If all elements in the list are `Ok` then returns an `Ok` holding the list of values. +/// If any element is `Error` then returns the first error. +/// +/// ## Examples +/// +/// ```gleam +/// all([Ok(1), Ok(2)]) +/// // -> Ok([1, 2]) +/// ``` +/// +/// ```gleam +/// all([Ok(1), Error("e")]) +/// // -> Error("e") +/// ``` +/// +pub fn all(results: List(Result(a, e))) -> Result(List(a), e) { + list.try_map(results, fn(result) { result }) +} + +/// Given a list of results, returns a pair where the first element is a list +/// of all the values inside `Ok` and the second element is a list with all the +/// values inside `Error`. The values in both lists appear in reverse order with +/// respect to their position in the original list of results. +/// +/// ## Examples +/// +/// ```gleam +/// partition([Ok(1), Error("a"), Error("b"), Ok(2)]) +/// // -> #([2, 1], ["b", "a"]) +/// ``` +/// +pub fn partition(results: List(Result(a, e))) -> #(List(a), List(e)) { + partition_loop(results, [], []) +} + +fn partition_loop(results: List(Result(a, e)), oks: List(a), errors: List(e)) { + case results { + [] -> #(oks, errors) + [Ok(a), ..rest] -> partition_loop(rest, [a, ..oks], errors) + [Error(e), ..rest] -> partition_loop(rest, oks, [e, ..errors]) + } +} + +/// Replace the value within a result +/// +/// ## Examples +/// +/// ```gleam +/// replace(Ok(1), Nil) +/// // -> Ok(Nil) +/// ``` +/// +/// ```gleam +/// replace(Error(1), Nil) +/// // -> Error(1) +/// ``` +/// +pub fn replace(result: Result(a, e), value: b) -> Result(b, e) { + case result { + Ok(_) -> Ok(value) + Error(error) -> Error(error) + } +} + +/// Replace the error within a result +/// +/// ## Examples +/// +/// ```gleam +/// replace_error(Error(1), Nil) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// replace_error(Ok(1), Nil) +/// // -> Ok(1) +/// ``` +/// +pub fn replace_error(result: Result(a, e), error: f) -> Result(a, f) { + case result { + Ok(x) -> Ok(x) + Error(_) -> Error(error) + } +} + +/// Given a list of results, returns only the values inside `Ok`. +/// +/// ## Examples +/// +/// ```gleam +/// values([Ok(1), Error("a"), Ok(3)]) +/// // -> [1, 3] +/// ``` +/// +pub fn values(results: List(Result(a, e))) -> List(a) { + list.filter_map(results, fn(result) { result }) +} + +/// Updates a value held within the `Error` of a result by calling a given function +/// on it, where the given function also returns a result. The two results are +/// then merged together into one result. +/// +/// If the result is an `Ok` rather than `Error` the function is not called and the +/// result stays the same. +/// +/// This function is useful for chaining together computations that may fail +/// and trying to recover from possible errors. +/// +/// If you do not need access to the initial error value, use `result.lazy_or`. +/// +/// ## Examples +/// +/// ```gleam +/// Ok(1) |> try_recover(with: fn(_) { Error("failed to recover") }) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// Error(1) |> try_recover(with: fn(error) { Ok(error + 1) }) +/// // -> Ok(2) +/// ``` +/// +/// ```gleam +/// Error(1) |> try_recover(with: fn(error) { Error("failed to recover") }) +/// // -> Error("failed to recover") +/// ``` +/// +pub fn try_recover( + result: Result(a, e), + with fun: fn(e) -> Result(a, f), +) -> Result(a, f) { + case result { + Ok(value) -> Ok(value) + Error(error) -> fun(error) + } +} diff --git a/build/packages/gleam_stdlib/src/gleam/set.gleam b/build/packages/gleam_stdlib/src/gleam/set.gleam new file mode 100644 index 0000000..6ae5e9e --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/set.gleam @@ -0,0 +1,407 @@ +import gleam/dict.{type Dict} +import gleam/list +import gleam/result + +// A list is used as the dict value as an empty list has the smallest +// representation in Erlang's binary format +@target(erlang) +type Token = + List(Nil) + +@target(erlang) +const token = [] + +@target(javascript) +type Token = + Nil + +@target(javascript) +const token = Nil + +/// A set is a collection of unique members of the same type. +/// +/// It is implemented using the `gleam/dict` module, so inserts and lookups have +/// logarithmic time complexity. +/// +pub opaque type Set(member) { + Set(dict: Dict(member, Token)) +} + +/// Creates a new empty set. +/// +pub fn new() -> Set(member) { + Set(dict.new()) +} + +/// Gets the number of members in a set. +/// +/// This function runs in constant time. +/// +/// ## Examples +/// +/// ```gleam +/// new() +/// |> insert(1) +/// |> insert(2) +/// |> size +/// // -> 2 +/// ``` +/// +pub fn size(set: Set(member)) -> Int { + dict.size(set.dict) +} + +/// Determines whether or not the set is empty. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> is_empty +/// // -> True +/// ``` +/// +/// ```gleam +/// new() |> insert(1) |> is_empty +/// // -> False +/// ``` +/// +pub fn is_empty(set: Set(member)) -> Bool { + set == new() +} + +/// Inserts an member into the set. +/// +/// This function runs in logarithmic time. +/// +/// ## Examples +/// +/// ```gleam +/// new() +/// |> insert(1) +/// |> insert(2) +/// |> size +/// // -> 2 +/// ``` +/// +pub fn insert(into set: Set(member), this member: member) -> Set(member) { + Set(dict: dict.insert(set.dict, member, token)) +} + +/// Checks whether a set contains a given member. +/// +/// This function runs in logarithmic time. +/// +/// ## Examples +/// +/// ```gleam +/// new() +/// |> insert(2) +/// |> contains(2) +/// // -> True +/// ``` +/// +/// ```gleam +/// new() +/// |> insert(2) +/// |> contains(1) +/// // -> False +/// ``` +/// +pub fn contains(in set: Set(member), this member: member) -> Bool { + set.dict + |> dict.get(member) + |> result.is_ok +} + +/// Removes a member from a set. If the set does not contain the member then +/// the set is returned unchanged. +/// +/// This function runs in logarithmic time. +/// +/// ## Examples +/// +/// ```gleam +/// new() +/// |> insert(2) +/// |> delete(2) +/// |> contains(1) +/// // -> False +/// ``` +/// +pub fn delete(from set: Set(member), this member: member) -> Set(member) { + Set(dict: dict.delete(set.dict, member)) +} + +/// Converts the set into a list of the contained members. +/// +/// The list has no specific ordering, any unintentional ordering may change in +/// future versions of Gleam or Erlang. +/// +/// This function runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// new() |> insert(2) |> to_list +/// // -> [2] +/// ``` +/// +pub fn to_list(set: Set(member)) -> List(member) { + dict.keys(set.dict) +} + +/// Creates a new set of the members in a given list. +/// +/// This function runs in loglinear time. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// import gleam/list +/// +/// [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort(by: int.compare) +/// // -> [1, 2, 3, 4] +/// ``` +/// +pub fn from_list(members: List(member)) -> Set(member) { + let dict = + list.fold(over: members, from: dict.new(), with: fn(m, k) { + dict.insert(m, k, token) + }) + Set(dict) +} + +/// Combines all entries into a single value by calling a given function on each +/// one. +/// +/// Sets are not ordered so the values are not returned in any specific order. +/// Do not write code that relies on the order entries are used by this +/// function as it may change in later versions of Gleam or Erlang. +/// +/// # Examples +/// +/// ```gleam +/// from_list([1, 3, 9]) +/// |> fold(0, fn(accumulator, member) { accumulator + member }) +/// // -> 13 +/// ``` +/// +pub fn fold( + over set: Set(member), + from initial: acc, + with reducer: fn(acc, member) -> acc, +) -> acc { + dict.fold(over: set.dict, from: initial, with: fn(a, k, _) { reducer(a, k) }) +} + +/// Creates a new set from an existing set, minus any members that a given +/// function returns `False` for. +/// +/// This function runs in loglinear time. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/int +/// +/// from_list([1, 4, 6, 3, 675, 44, 67]) +/// |> filter(keeping: int.is_even) +/// |> to_list +/// // -> [4, 6, 44] +/// ``` +/// +pub fn filter( + in set: Set(member), + keeping predicate: fn(member) -> Bool, +) -> Set(member) { + Set(dict.filter(in: set.dict, keeping: fn(m, _) { predicate(m) })) +} + +/// Creates a new set from a given set with the result of applying the given +/// function to each member. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([1, 2, 3, 4]) +/// |> map(with: fn(x) { x * 2 }) +/// |> to_list +/// // -> [2, 4, 6, 8] +/// ``` +pub fn map(set: Set(member), with fun: fn(member) -> mapped) -> Set(mapped) { + fold(over: set, from: new(), with: fn(acc, member) { + insert(acc, fun(member)) + }) +} + +/// Creates a new set from a given set with all the same entries except any +/// entry found on the given list. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([1, 2, 3, 4]) +/// |> drop([1, 3]) +/// |> to_list +/// // -> [2, 4] +/// ``` +pub fn drop(from set: Set(member), drop disallowed: List(member)) -> Set(member) { + list.fold(over: disallowed, from: set, with: delete) +} + +/// Creates a new set from a given set, only including any members which are in +/// a given list. +/// +/// This function runs in loglinear time. +/// +/// ## Examples +/// +/// ```gleam +/// from_list([1, 2, 3]) +/// |> take([1, 3, 5]) +/// |> to_list +/// // -> [1, 3] +/// ``` +/// +pub fn take(from set: Set(member), keeping desired: List(member)) -> Set(member) { + Set(dict.take(from: set.dict, keeping: desired)) +} + +/// Creates a new set that contains all members of both given sets. +/// +/// This function runs in loglinear time. +/// +/// ## Examples +/// +/// ```gleam +/// union(from_list([1, 2]), from_list([2, 3])) |> to_list +/// // -> [1, 2, 3] +/// ``` +/// +pub fn union(of first: Set(member), and second: Set(member)) -> Set(member) { + let #(larger, smaller) = order(first, second) + fold(over: smaller, from: larger, with: insert) +} + +fn order(first: Set(member), second: Set(member)) -> #(Set(member), Set(member)) { + case dict.size(first.dict) > dict.size(second.dict) { + True -> #(first, second) + False -> #(second, first) + } +} + +/// Creates a new set that contains members that are present in both given sets. +/// +/// This function runs in loglinear time. +/// +/// ## Examples +/// +/// ```gleam +/// intersection(from_list([1, 2]), from_list([2, 3])) |> to_list +/// // -> [2] +/// ``` +/// +pub fn intersection( + of first: Set(member), + and second: Set(member), +) -> Set(member) { + let #(larger, smaller) = order(first, second) + take(from: larger, keeping: to_list(smaller)) +} + +/// Creates a new set that contains members that are present in the first set +/// but not the second. +/// +/// ## Examples +/// +/// ```gleam +/// difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list +/// // -> [1] +/// ``` +/// +pub fn difference( + from first: Set(member), + minus second: Set(member), +) -> Set(member) { + drop(from: first, drop: to_list(second)) +} + +/// Determines if a set is fully contained by another. +/// +/// ## Examples +/// +/// ```gleam +/// is_subset(from_list([1]), from_list([1, 2])) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_subset(from_list([1, 2, 3]), from_list([3, 4, 5])) +/// // -> False +/// ``` +/// +pub fn is_subset(first: Set(member), of second: Set(member)) -> Bool { + intersection(of: first, and: second) == first +} + +/// Determines if two sets contain no common members +/// +/// ## Examples +/// +/// ```gleam +/// is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6])) +/// // -> True +/// ``` +/// +/// ```gleam +/// is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5])) +/// // -> False +/// ``` +/// +pub fn is_disjoint(first: Set(member), from second: Set(member)) -> Bool { + intersection(of: first, and: second) == new() +} + +/// Creates a new set that contains members that are present in either set, but +/// not both. +/// +/// ```gleam +/// symmetric_difference(from_list([1, 2, 3]), from_list([3, 4])) |> to_list +/// // -> [1, 2, 4] +/// ``` +/// +pub fn symmetric_difference( + of first: Set(member), + and second: Set(member), +) -> Set(member) { + difference( + from: union(of: first, and: second), + minus: intersection(of: first, and: second), + ) +} + +/// Calls a function for each member in a set, discarding the return +/// value. +/// +/// Useful for producing a side effect for every item of a set. +/// +/// ```gleam +/// let set = from_list(["apple", "banana", "cherry"]) +/// +/// each(set, io.println) +/// // -> Nil +/// // apple +/// // banana +/// // cherry +/// ``` +/// +/// The order of elements in the iteration is an implementation detail that +/// should not be relied upon. +/// +pub fn each(set: Set(member), fun: fn(member) -> a) -> Nil { + fold(set, Nil, fn(nil, member) { + fun(member) + nil + }) +} diff --git a/build/packages/gleam_stdlib/src/gleam/string.gleam b/build/packages/gleam_stdlib/src/gleam/string.gleam new file mode 100644 index 0000000..c1e31c4 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/string.gleam @@ -0,0 +1,853 @@ +//// Strings in Gleam are UTF-8 binaries. They can be written in your code as +//// text surrounded by `"double quotes"`. + +import gleam/list +import gleam/option.{type Option, None, Some} +import gleam/order +import gleam/string_tree.{type StringTree} + +/// Determines if a `String` is empty. +/// +/// ## Examples +/// +/// ```gleam +/// is_empty("") +/// // -> True +/// ``` +/// +/// ```gleam +/// is_empty("the world") +/// // -> False +/// ``` +/// +pub fn is_empty(str: String) -> Bool { + str == "" +} + +/// Gets the number of grapheme clusters in a given `String`. +/// +/// This function has to iterate across the whole string to count the number of +/// graphemes, so it runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// length("Gleam") +/// // -> 5 +/// ``` +/// +/// ```gleam +/// length("ß↑e̊") +/// // -> 3 +/// ``` +/// +/// ```gleam +/// length("") +/// // -> 0 +/// ``` +/// +@external(erlang, "string", "length") +@external(javascript, "../gleam_stdlib.mjs", "string_length") +pub fn length(string: String) -> Int + +/// Reverses a `String`. +/// +/// This function has to iterate across the whole `String` so it runs in linear +/// time. +/// +/// ## Examples +/// +/// ```gleam +/// reverse("stressed") +/// // -> "desserts" +/// ``` +/// +pub fn reverse(string: String) -> String { + string + |> string_tree.from_string + |> string_tree.reverse + |> string_tree.to_string +} + +/// Creates a new `String` by replacing all occurrences of a given substring. +/// +/// ## Examples +/// +/// ```gleam +/// replace("www.example.com", each: ".", with: "-") +/// // -> "www-example-com" +/// ``` +/// +/// ```gleam +/// replace("a,b,c,d,e", each: ",", with: "/") +/// // -> "a/b/c/d/e" +/// ``` +/// +pub fn replace( + in string: String, + each pattern: String, + with substitute: String, +) -> String { + string + |> string_tree.from_string + |> string_tree.replace(each: pattern, with: substitute) + |> string_tree.to_string +} + +/// Creates a new `String` with all the graphemes in the input `String` converted to +/// lowercase. +/// +/// Useful for case-insensitive comparisons. +/// +/// ## Examples +/// +/// ```gleam +/// lowercase("X-FILES") +/// // -> "x-files" +/// ``` +/// +@external(erlang, "string", "lowercase") +@external(javascript, "../gleam_stdlib.mjs", "lowercase") +pub fn lowercase(string: String) -> String + +/// Creates a new `String` with all the graphemes in the input `String` converted to +/// uppercase. +/// +/// Useful for case-insensitive comparisons and VIRTUAL YELLING. +/// +/// ## Examples +/// +/// ```gleam +/// uppercase("skinner") +/// // -> "SKINNER" +/// ``` +/// +@external(erlang, "string", "uppercase") +@external(javascript, "../gleam_stdlib.mjs", "uppercase") +pub fn uppercase(string: String) -> String + +/// Compares two `String`s to see which is "larger" by comparing their graphemes. +/// +/// This does not compare the size or length of the given `String`s. +/// +/// ## Examples +/// +/// ```gleam +/// compare("Anthony", "Anthony") +/// // -> order.Eq +/// ``` +/// +/// ```gleam +/// compare("A", "B") +/// // -> order.Lt +/// ``` +/// +pub fn compare(a: String, b: String) -> order.Order { + case a == b { + True -> order.Eq + _ -> + case less_than(a, b) { + True -> order.Lt + False -> order.Gt + } + } +} + +@external(erlang, "gleam_stdlib", "less_than") +@external(javascript, "../gleam_stdlib.mjs", "less_than") +fn less_than(a: String, b: String) -> Bool + +/// Takes a substring given a start grapheme index and a length. Negative indexes +/// are taken starting from the *end* of the list. +/// +/// ## Examples +/// +/// ```gleam +/// slice(from: "gleam", at_index: 1, length: 2) +/// // -> "le" +/// ``` +/// +/// ```gleam +/// slice(from: "gleam", at_index: 1, length: 10) +/// // -> "leam" +/// ``` +/// +/// ```gleam +/// slice(from: "gleam", at_index: 10, length: 3) +/// // -> "" +/// ``` +/// +/// ```gleam +/// slice(from: "gleam", at_index: -2, length: 2) +/// // -> "am" +/// ``` +/// +/// ```gleam +/// slice(from: "gleam", at_index: -12, length: 2) +/// // -> "" +/// ``` +/// +pub fn slice(from string: String, at_index idx: Int, length len: Int) -> String { + case len < 0 { + True -> "" + False -> + case idx < 0 { + True -> { + let translated_idx = length(string) + idx + case translated_idx < 0 { + True -> "" + False -> do_slice(string, translated_idx, len) + } + } + False -> do_slice(string, idx, len) + } + } +} + +@external(erlang, "gleam_stdlib", "slice") +@external(javascript, "../gleam_stdlib.mjs", "string_slice") +fn do_slice(string: String, idx: Int, len: Int) -> String + +/// Drops contents of the first `String` that occur before the second `String`. +/// If the `from` string does not contain the `before` string, `from` is returned unchanged. +/// +/// ## Examples +/// +/// ```gleam +/// crop(from: "The Lone Gunmen", before: "Lone") +/// // -> "Lone Gunmen" +/// ``` +/// +@external(erlang, "gleam_stdlib", "crop_string") +@external(javascript, "../gleam_stdlib.mjs", "crop_string") +pub fn crop(from string: String, before substring: String) -> String + +/// Drops *n* graphemes from the start of a `String`. +/// +/// ## Examples +/// +/// ```gleam +/// drop_start(from: "The Lone Gunmen", up_to: 2) +/// // -> "e Lone Gunmen" +/// ``` +/// +pub fn drop_start(from string: String, up_to num_graphemes: Int) -> String { + case num_graphemes > 0 { + False -> string + True -> + case pop_grapheme(string) { + Ok(#(_, string)) -> drop_start(string, num_graphemes - 1) + Error(Nil) -> string + } + } +} + +/// Drops *n* graphemes from the end of a `String`. +/// +/// ## Examples +/// +/// ```gleam +/// drop_end(from: "Cigarette Smoking Man", up_to: 2) +/// // -> "Cigarette Smoking M" +/// ``` +/// +pub fn drop_end(from string: String, up_to num_graphemes: Int) -> String { + case num_graphemes < 0 { + True -> string + False -> slice(string, 0, length(string) - num_graphemes) + } +} + +/// Checks if the first `String` contains the second. +/// +/// ## Examples +/// +/// ```gleam +/// contains(does: "theory", contain: "ory") +/// // -> True +/// ``` +/// +/// ```gleam +/// contains(does: "theory", contain: "the") +/// // -> True +/// ``` +/// +/// ```gleam +/// contains(does: "theory", contain: "THE") +/// // -> False +/// ``` +/// +@external(erlang, "gleam_stdlib", "contains_string") +@external(javascript, "../gleam_stdlib.mjs", "contains_string") +pub fn contains(does haystack: String, contain needle: String) -> Bool + +/// Checks whether the first `String` starts with the second one. +/// +/// ## Examples +/// +/// ```gleam +/// starts_with("theory", "ory") +/// // -> False +/// ``` +/// +@external(erlang, "gleam_stdlib", "string_starts_with") +@external(javascript, "../gleam_stdlib.mjs", "starts_with") +pub fn starts_with(string: String, prefix: String) -> Bool + +/// Checks whether the first `String` ends with the second one. +/// +/// ## Examples +/// +/// ```gleam +/// ends_with("theory", "ory") +/// // -> True +/// ``` +/// +@external(erlang, "gleam_stdlib", "string_ends_with") +@external(javascript, "../gleam_stdlib.mjs", "ends_with") +pub fn ends_with(string: String, suffix: String) -> Bool + +/// Creates a list of `String`s by splitting a given string on a given substring. +/// +/// ## Examples +/// +/// ```gleam +/// split("home/gleam/desktop/", on: "/") +/// // -> ["home", "gleam", "desktop", ""] +/// ``` +/// +pub fn split(x: String, on substring: String) -> List(String) { + case substring { + "" -> to_graphemes(x) + _ -> + x + |> string_tree.from_string + |> string_tree.split(on: substring) + |> list.map(with: string_tree.to_string) + } +} + +/// Splits a `String` a single time on the given substring. +/// +/// Returns an `Error` if substring not present. +/// +/// ## Examples +/// +/// ```gleam +/// split_once("home/gleam/desktop/", on: "/") +/// // -> Ok(#("home", "gleam/desktop/")) +/// ``` +/// +/// ```gleam +/// split_once("home/gleam/desktop/", on: "?") +/// // -> Error(Nil) +/// ``` +/// +@external(javascript, "../gleam_stdlib.mjs", "split_once") +pub fn split_once( + string: String, + on substring: String, +) -> Result(#(String, String), Nil) { + case erl_split(string, substring) { + [first, rest] -> Ok(#(first, rest)) + _ -> Error(Nil) + } +} + +@external(erlang, "string", "split") +fn erl_split(a: String, b: String) -> List(String) + +/// Creates a new `String` by joining two `String`s together. +/// +/// This function typically copies both `String`s and runs in linear time, but +/// the exact behaviour will depend on how the runtime you are using optimises +/// your code. Benchmark and profile your code if you need to understand its +/// performance better. +/// +/// If you are joining together large string and want to avoid copying any data +/// you may want to investigate using the [`string_tree`](../gleam/string_tree.html) +/// module. +/// +/// ## Examples +/// +/// ```gleam +/// append(to: "butter", suffix: "fly") +/// // -> "butterfly" +/// ``` +/// +pub fn append(to first: String, suffix second: String) -> String { + first <> second +} + +/// Creates a new `String` by joining many `String`s together. +/// +/// This function copies both `String`s and runs in linear time. If you find +/// yourself joining `String`s frequently consider using the [`string_tree`](../gleam/string_tree.html) +/// module as it can append `String`s much faster! +/// +/// ## Examples +/// +/// ```gleam +/// concat(["never", "the", "less"]) +/// // -> "nevertheless" +/// ``` +/// +@external(erlang, "erlang", "list_to_binary") +pub fn concat(strings: List(String)) -> String { + concat_loop(strings, "") +} + +fn concat_loop(strings: List(String), accumulator: String) -> String { + case strings { + [string, ..strings] -> concat_loop(strings, accumulator <> string) + [] -> accumulator + } +} + +/// Creates a new `String` by repeating a `String` a given number of times. +/// +/// This function runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// repeat("ha", times: 3) +/// // -> "hahaha" +/// ``` +/// +pub fn repeat(string: String, times times: Int) -> String { + repeat_loop(string, times, "") +} + +fn repeat_loop(string: String, times: Int, acc: String) -> String { + case times <= 0 { + True -> acc + False -> repeat_loop(string, times - 1, acc <> string) + } +} + +/// Joins many `String`s together with a given separator. +/// +/// This function runs in linear time. +/// +/// ## Examples +/// +/// ```gleam +/// join(["home","evan","Desktop"], with: "/") +/// // -> "home/evan/Desktop" +/// ``` +/// +pub fn join(strings: List(String), with separator: String) -> String { + case strings { + [] -> "" + [first, ..rest] -> join_loop(rest, separator, first) + } +} + +fn join_loop( + strings: List(String), + separator: String, + accumulator: String, +) -> String { + case strings { + [] -> accumulator + [string, ..strings] -> + join_loop(strings, separator, accumulator <> separator <> string) + } +} + +/// Pads the start of a `String` until it has a given length. +/// +/// ## Examples +/// +/// ```gleam +/// pad_start("121", to: 5, with: ".") +/// // -> "..121" +/// ``` +/// +/// ```gleam +/// pad_start("121", to: 3, with: ".") +/// // -> "121" +/// ``` +/// +/// ```gleam +/// pad_start("121", to: 2, with: ".") +/// // -> "121" +/// ``` +/// +pub fn pad_start( + string: String, + to desired_length: Int, + with pad_string: String, +) -> String { + let current_length = length(string) + let to_pad_length = desired_length - current_length + + case to_pad_length <= 0 { + True -> string + False -> padding(to_pad_length, pad_string) <> string + } +} + +/// Pads the end of a `String` until it has a given length. +/// +/// ## Examples +/// +/// ```gleam +/// pad_end("123", to: 5, with: ".") +/// // -> "123.." +/// ``` +/// +/// ```gleam +/// pad_end("123", to: 3, with: ".") +/// // -> "123" +/// ``` +/// +/// ```gleam +/// pad_end("123", to: 2, with: ".") +/// // -> "123" +/// ``` +/// +pub fn pad_end( + string: String, + to desired_length: Int, + with pad_string: String, +) -> String { + let current_length = length(string) + let to_pad_length = desired_length - current_length + + case to_pad_length <= 0 { + True -> string + False -> string <> padding(to_pad_length, pad_string) + } +} + +fn padding(size: Int, pad_string: String) -> String { + let pad_string_length = length(pad_string) + let num_pads = size / pad_string_length + let extra = size % pad_string_length + + repeat(pad_string, num_pads) <> slice(pad_string, 0, extra) +} + +/// Removes whitespace on both sides of a `String`. +/// +/// Whitespace in this function is the set of nonbreakable whitespace +/// codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1]. +/// +/// [1]: https://unicode.org/reports/tr31/ +/// +/// ## Examples +/// +/// ```gleam +/// trim(" hats \n") +/// // -> "hats" +/// ``` +/// +pub fn trim(string: String) -> String { + string |> trim_start |> trim_end +} + +@external(erlang, "string", "trim") +fn erl_trim(a: String, b: Direction) -> String + +type Direction { + Leading + Trailing +} + +/// Removes whitespace at the start of a `String`. +/// +/// ## Examples +/// +/// ```gleam +/// trim_start(" hats \n") +/// // -> "hats \n" +/// ``` +/// +@external(javascript, "../gleam_stdlib.mjs", "trim_start") +pub fn trim_start(string: String) -> String { + erl_trim(string, Leading) +} + +/// Removes whitespace at the end of a `String`. +/// +/// ## Examples +/// +/// ```gleam +/// trim_end(" hats \n") +/// // -> " hats" +/// ``` +/// +@external(javascript, "../gleam_stdlib.mjs", "trim_end") +pub fn trim_end(string: String) -> String { + erl_trim(string, Trailing) +} + +/// Splits a non-empty `String` into its first element (head) and rest (tail). +/// This lets you pattern match on `String`s exactly as you would with lists. +/// +/// ## Performance +/// +/// There is a notable overhead to using this function, so you may not want to +/// use it in a tight loop. If you wish to efficiently parse a string you may +/// want to use alternatives such as the [splitter package](https://hex.pm/packages/splitter). +/// +/// ## Examples +/// +/// ```gleam +/// pop_grapheme("gleam") +/// // -> Ok(#("g", "leam")) +/// ``` +/// +/// ```gleam +/// pop_grapheme("") +/// // -> Error(Nil) +/// ``` +/// +@external(erlang, "gleam_stdlib", "string_pop_grapheme") +@external(javascript, "../gleam_stdlib.mjs", "pop_grapheme") +pub fn pop_grapheme(string: String) -> Result(#(String, String), Nil) + +/// Converts a `String` to a list of +/// [graphemes](https://en.wikipedia.org/wiki/Grapheme). +/// +/// ```gleam +/// to_graphemes("abc") +/// // -> ["a", "b", "c"] +/// ``` +/// +@external(javascript, "../gleam_stdlib.mjs", "graphemes") +pub fn to_graphemes(string: String) -> List(String) { + to_graphemes_loop(string, []) + |> list.reverse +} + +fn to_graphemes_loop(string: String, acc: List(String)) -> List(String) { + case pop_grapheme(string) { + Ok(#(grapheme, rest)) -> to_graphemes_loop(rest, [grapheme, ..acc]) + Error(_) -> acc + } +} + +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "codepoint") +fn unsafe_int_to_utf_codepoint(a: Int) -> UtfCodepoint + +/// Converts a `String` to a `List` of `UtfCodepoint`. +/// +/// See and +/// for an +/// explanation on code points. +/// +/// ## Examples +/// +/// ```gleam +/// "a" |> to_utf_codepoints +/// // -> [UtfCodepoint(97)] +/// ``` +/// +/// ```gleam +/// // Semantically the same as: +/// // ["🏳", "️", "‍", "🌈"] or: +/// // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow] +/// "🏳️‍🌈" |> to_utf_codepoints +/// // -> [ +/// // UtfCodepoint(127987), +/// // UtfCodepoint(65039), +/// // UtfCodepoint(8205), +/// // UtfCodepoint(127752), +/// // ] +/// ``` +/// +pub fn to_utf_codepoints(string: String) -> List(UtfCodepoint) { + do_to_utf_codepoints(string) +} + +@target(erlang) +fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) { + to_utf_codepoints_loop(<>, []) +} + +@target(erlang) +fn to_utf_codepoints_loop( + bit_array: BitArray, + acc: List(UtfCodepoint), +) -> List(UtfCodepoint) { + case bit_array { + <> -> + to_utf_codepoints_loop(rest, [first, ..acc]) + _ -> list.reverse(acc) + } +} + +@target(javascript) +fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) { + string + |> string_to_codepoint_integer_list + |> list.map(unsafe_int_to_utf_codepoint) +} + +@target(javascript) +@external(javascript, "../gleam_stdlib.mjs", "string_to_codepoint_integer_list") +fn string_to_codepoint_integer_list(string: String) -> List(Int) + +/// Converts a `List` of `UtfCodepoint`s to a `String`. +/// +/// See and +/// for an +/// explanation on code points. +/// +/// ## Examples +/// +/// ```gleam +/// let assert Ok(a) = utf_codepoint(97) +/// let assert Ok(b) = utf_codepoint(98) +/// let assert Ok(c) = utf_codepoint(99) +/// from_utf_codepoints([a, b, c]) +/// // -> "abc" +/// ``` +/// +@external(erlang, "gleam_stdlib", "utf_codepoint_list_to_string") +@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_list_to_string") +pub fn from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String + +/// Converts an integer to a `UtfCodepoint`. +/// +/// Returns an `Error` if the integer does not represent a valid UTF codepoint. +/// +pub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) { + case value { + i if i > 1_114_111 -> Error(Nil) + i if i >= 55_296 && i <= 57_343 -> Error(Nil) + i if i < 0 -> Error(Nil) + i -> Ok(unsafe_int_to_utf_codepoint(i)) + } +} + +/// Converts an UtfCodepoint to its ordinal code point value. +/// +/// ## Examples +/// +/// ```gleam +/// let assert [utf_codepoint, ..] = to_utf_codepoints("💜") +/// utf_codepoint_to_int(utf_codepoint) +/// // -> 128156 +/// ``` +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_to_int") +pub fn utf_codepoint_to_int(cp: UtfCodepoint) -> Int + +/// Converts a `String` into `Option(String)` where an empty `String` becomes +/// `None`. +/// +/// ## Examples +/// +/// ```gleam +/// to_option("") +/// // -> None +/// ``` +/// +/// ```gleam +/// to_option("hats") +/// // -> Some("hats") +/// ``` +/// +pub fn to_option(string: String) -> Option(String) { + case string { + "" -> None + _ -> Some(string) + } +} + +/// Returns the first grapheme cluster in a given `String` and wraps it in a +/// `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. +/// Otherwise, it returns `Ok(String)`. +/// +/// ## Examples +/// +/// ```gleam +/// first("") +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// first("icecream") +/// // -> Ok("i") +/// ``` +/// +pub fn first(string: String) -> Result(String, Nil) { + case pop_grapheme(string) { + Ok(#(first, _)) -> Ok(first) + Error(e) -> Error(e) + } +} + +/// Returns the last grapheme cluster in a given `String` and wraps it in a +/// `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. +/// Otherwise, it returns `Ok(String)`. +/// +/// ## Examples +/// +/// ```gleam +/// last("") +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// last("icecream") +/// // -> Ok("m") +/// ``` +/// +pub fn last(string: String) -> Result(String, Nil) { + case pop_grapheme(string) { + Ok(#(first, "")) -> Ok(first) + Ok(#(_, rest)) -> Ok(slice(rest, -1, 1)) + Error(e) -> Error(e) + } +} + +/// Creates a new `String` with the first grapheme in the input `String` +/// converted to uppercase and the remaining graphemes to lowercase. +/// +/// ## Examples +/// +/// ```gleam +/// capitalise("mamouna") +/// // -> "Mamouna" +/// ``` +/// +pub fn capitalise(string: String) -> String { + case pop_grapheme(string) { + Ok(#(first, rest)) -> append(to: uppercase(first), suffix: lowercase(rest)) + Error(_) -> "" + } +} + +/// Returns a `String` representation of a term in Gleam syntax. +/// +pub fn inspect(term: anything) -> String { + do_inspect(term) + |> string_tree.to_string +} + +@external(erlang, "gleam_stdlib", "inspect") +@external(javascript, "../gleam_stdlib.mjs", "inspect") +fn do_inspect(term: anything) -> StringTree + +/// Returns the number of bytes in a `String`. +/// +/// This function runs in constant time on Erlang and in linear time on +/// JavaScript. +/// +/// ## Examples +/// +/// ```gleam +/// byte_size("🏳️‍⚧️🏳️‍🌈👩🏾‍❤️‍👨🏻") +/// // -> 58 +/// ``` +/// +@external(erlang, "erlang", "byte_size") +@external(javascript, "../gleam_stdlib.mjs", "byte_size") +pub fn byte_size(string: String) -> Int diff --git a/build/packages/gleam_stdlib/src/gleam/string_tree.gleam b/build/packages/gleam_stdlib/src/gleam/string_tree.gleam new file mode 100644 index 0000000..22937e2 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/string_tree.gleam @@ -0,0 +1,208 @@ +import gleam/list + +/// `StringTree` is a type used for efficiently building text content to be +/// written to a file or a socket. Internally it is represented as tree so to +/// append or prepend to a string tree is a constant time operation that +/// allocates a new node in the tree without copying any of the content. When +/// writing to an output stream the tree is traversed and the content is sent +/// directly rather than copying it into a single buffer beforehand. +/// +/// On Erlang this type is compatible with Erlang's iodata. On JavaScript this +/// type is compatible with normal strings. +/// +/// The BEAM virtual machine has an optimisation for appending strings, where it +/// will mutate the string buffer when safe to do so, so if you are looking to +/// build a string through appending many small strings then you may get better +/// performance by not using a string tree. Always benchmark your performance +/// sensitive code. +/// +pub type StringTree + +/// Create an empty `StringTree`. Useful as the start of a pipe chaining many +/// trees together. +/// +pub fn new() -> StringTree { + from_strings([]) +} + +/// Prepends a `String` onto the start of some `StringTree`. +/// +/// Runs in constant time. +/// +pub fn prepend(to tree: StringTree, prefix prefix: String) -> StringTree { + append_tree(from_string(prefix), tree) +} + +/// Appends a `String` onto the end of some `StringTree`. +/// +/// Runs in constant time. +/// +pub fn append(to tree: StringTree, suffix second: String) -> StringTree { + append_tree(tree, from_string(second)) +} + +/// Prepends some `StringTree` onto the start of another. +/// +/// Runs in constant time. +/// +pub fn prepend_tree( + to tree: StringTree, + prefix prefix: StringTree, +) -> StringTree { + append_tree(prefix, tree) +} + +/// Appends some `StringTree` onto the end of another. +/// +/// Runs in constant time. +/// +@external(erlang, "gleam_stdlib", "iodata_append") +@external(javascript, "../gleam_stdlib.mjs", "add") +pub fn append_tree(to tree: StringTree, suffix suffix: StringTree) -> StringTree + +/// Converts a list of strings into a `StringTree`. +/// +/// Runs in constant time. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "concat") +pub fn from_strings(strings: List(String)) -> StringTree + +/// Joins a list of trees into a single tree. +/// +/// Runs in constant time. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "concat") +pub fn concat(trees: List(StringTree)) -> StringTree + +/// Converts a string into a `StringTree`. +/// +/// Runs in constant time. +/// +@external(erlang, "gleam_stdlib", "identity") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn from_string(string: String) -> StringTree + +/// Turns a `StringTree` into a `String` +/// +/// This function is implemented natively by the virtual machine and is highly +/// optimised. +/// +@external(erlang, "unicode", "characters_to_binary") +@external(javascript, "../gleam_stdlib.mjs", "identity") +pub fn to_string(tree: StringTree) -> String + +/// Returns the size of the `StringTree` in bytes. +/// +@external(erlang, "erlang", "iolist_size") +@external(javascript, "../gleam_stdlib.mjs", "length") +pub fn byte_size(tree: StringTree) -> Int + +/// Joins the given trees into a new tree separated with the given string. +/// +pub fn join(trees: List(StringTree), with sep: String) -> StringTree { + trees + |> list.intersperse(from_string(sep)) + |> concat +} + +/// Converts a `StringTree` to a new one where the contents have been +/// lowercased. +/// +@external(erlang, "string", "lowercase") +@external(javascript, "../gleam_stdlib.mjs", "lowercase") +pub fn lowercase(tree: StringTree) -> StringTree + +/// Converts a `StringTree` to a new one where the contents have been +/// uppercased. +/// +@external(erlang, "string", "uppercase") +@external(javascript, "../gleam_stdlib.mjs", "uppercase") +pub fn uppercase(tree: StringTree) -> StringTree + +/// Converts a `StringTree` to a new one with the contents reversed. +/// +@external(erlang, "string", "reverse") +pub fn reverse(tree: StringTree) -> StringTree { + tree + |> to_string + |> do_to_graphemes + |> list.reverse + |> from_strings +} + +@external(javascript, "../gleam_stdlib.mjs", "graphemes") +fn do_to_graphemes(string: String) -> List(String) + +type Direction { + All +} + +/// Splits a `StringTree` on a given pattern into a list of trees. +/// +@external(javascript, "../gleam_stdlib.mjs", "split") +pub fn split(tree: StringTree, on pattern: String) -> List(StringTree) { + erl_split(tree, pattern, All) +} + +@external(erlang, "string", "split") +fn erl_split(a: StringTree, b: String, c: Direction) -> List(StringTree) + +/// Replaces all instances of a pattern with a given string substitute. +/// +@external(erlang, "gleam_stdlib", "string_replace") +@external(javascript, "../gleam_stdlib.mjs", "string_replace") +pub fn replace( + in tree: StringTree, + each pattern: String, + with substitute: String, +) -> StringTree + +/// Compares two string trees to determine if they have the same textual +/// content. +/// +/// Comparing two string trees using the `==` operator may return `False` even +/// if they have the same content as they may have been build in different ways, +/// so using this function is often preferred. +/// +/// ## Examples +/// +/// ```gleam +/// from_strings(["a", "b"]) == from_string("ab") +/// // -> False +/// ``` +/// +/// ```gleam +/// is_equal(from_strings(["a", "b"]), from_string("ab")) +/// // -> True +/// ``` +/// +@external(erlang, "string", "equal") +pub fn is_equal(a: StringTree, b: StringTree) -> Bool { + a == b +} + +/// Inspects a `StringTree` to determine if it is equivalent to an empty string. +/// +/// ## Examples +/// +/// ```gleam +/// from_string("ok") |> is_empty +/// // -> False +/// ``` +/// +/// ```gleam +/// from_string("") |> is_empty +/// // -> True +/// ``` +/// +/// ```gleam +/// from_strings([]) |> is_empty +/// // -> True +/// ``` +/// +@external(erlang, "string", "is_empty") +pub fn is_empty(tree: StringTree) -> Bool { + from_string("") == tree +} diff --git a/build/packages/gleam_stdlib/src/gleam/uri.gleam b/build/packages/gleam_stdlib/src/gleam/uri.gleam new file mode 100644 index 0000000..de08428 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam/uri.gleam @@ -0,0 +1,765 @@ +//// Utilities for working with URIs +//// +//// This module provides functions for working with URIs (for example, parsing +//// URIs or encoding query strings). The functions in this module are implemented +//// according to [RFC 3986](https://tools.ietf.org/html/rfc3986). +//// +//// Query encoding (Form encoding) is defined in the +//// [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data). + +import gleam/int +import gleam/list +import gleam/option.{type Option, None, Some} +import gleam/string +import gleam/string_tree.{type StringTree} + +/// Type representing holding the parsed components of an URI. +/// All components of a URI are optional, except the path. +/// +pub type Uri { + Uri( + scheme: Option(String), + userinfo: Option(String), + host: Option(String), + port: Option(Int), + path: String, + query: Option(String), + fragment: Option(String), + ) +} + +/// Constant representing an empty URI, equivalent to "". +/// +/// ## Examples +/// +/// ```gleam +/// let uri = Uri(..empty, scheme: Some("https"), host: Some("example.com")) +/// // -> Uri( +/// // scheme: Some("https"), +/// // userinfo: None, +/// // host: Some("example.com"), +/// // port: None, +/// // path: "", +/// // query: None, +/// // fragment: None, +/// // ) +/// ``` +/// +pub const empty = Uri( + scheme: None, + userinfo: None, + host: None, + port: None, + path: "", + query: None, + fragment: None, +) + +/// Parses a compliant URI string into the `Uri` Type. +/// If the string is not a valid URI string then an error is returned. +/// +/// The opposite operation is `uri.to_string`. +/// +/// ## Examples +/// +/// ```gleam +/// parse("https://example.com:1234/a/b?query=true#fragment") +/// // -> Ok( +/// // Uri( +/// // scheme: Some("https"), +/// // userinfo: None, +/// // host: Some("example.com"), +/// // port: Some(1234), +/// // path: "/a/b", +/// // query: Some("query=true"), +/// // fragment: Some("fragment") +/// // ) +/// // ) +/// ``` +/// +@external(erlang, "gleam_stdlib", "uri_parse") +pub fn parse(uri_string: String) -> Result(Uri, Nil) { + // This parses a uri_string following the regex defined in + // https://tools.ietf.org/html/rfc3986#appendix-B + // + // TODO: This is not perfect and will be more permissive than its Erlang + // counterpart, ideally we want to replicate Erlang's implementation on the js + // target as well. + parse_scheme_loop(uri_string, uri_string, empty, 0) +} + +fn parse_scheme_loop( + original: String, + uri_string: String, + pieces: Uri, + size: Int, +) -> Result(Uri, Nil) { + case uri_string { + // `/` is not allowed to appear in a scheme so we know it's over and we can + // start parsing the authority with slashes. + "/" <> _ if size == 0 -> parse_authority_with_slashes(uri_string, pieces) + "/" <> _ -> { + let scheme = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) + parse_authority_with_slashes(uri_string, pieces) + } + + // `?` is not allowed to appear in a schemem, in an authority, or in a path; + // so if we see it we know it marks the beginning of the query part. + "?" <> rest if size == 0 -> parse_query_with_question_mark(rest, pieces) + "?" <> rest -> { + let scheme = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) + parse_query_with_question_mark(rest, pieces) + } + + // `#` is not allowed to appear in a scheme, in an authority, in a path or + // in a query; so if we see it we know it marks the beginning of the final + // fragment. + "#" <> rest if size == 0 -> parse_fragment(rest, pieces) + "#" <> rest -> { + let scheme = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) + parse_fragment(rest, pieces) + } + + // A colon marks the end of a uri scheme, but if it is not preceded by any + // character then it's not a valid URI. + ":" <> _ if size == 0 -> Error(Nil) + ":" <> rest -> { + let scheme = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) + parse_authority_with_slashes(rest, pieces) + } + + // If we could get to the end of the string and we've met no special + // chars whatsoever, that means the entire string is just a long path. + "" -> Ok(Uri(..pieces, path: original)) + + // In all other cases the first character is just a valid URI scheme + // character and we just keep munching characters until we reach the end of + // the uri scheme (or the end of the string and that would mean this is not + // a valid uri scheme since we found no `:`). + _ -> { + let #(_, rest) = pop_codeunit(uri_string) + parse_scheme_loop(original, rest, pieces, size + 1) + } + } +} + +fn parse_authority_with_slashes( + uri_string: String, + pieces: Uri, +) -> Result(Uri, Nil) { + case uri_string { + // To be a valid authority the string must start with a `//`, otherwise + // there's no authority and we just skip ahead to parsing the path. + "//" -> Ok(Uri(..pieces, host: Some(""))) + "//" <> rest -> parse_authority_pieces(rest, pieces) + _ -> parse_path(uri_string, pieces) + } +} + +fn parse_authority_pieces(string: String, pieces: Uri) -> Result(Uri, Nil) { + parse_userinfo_loop(string, string, pieces, 0) +} + +fn parse_userinfo_loop( + original: String, + uri_string: String, + pieces: Uri, + size: Int, +) -> Result(Uri, Nil) { + case uri_string { + // `@` marks the end of the userinfo and the start of the host part in the + // authority string. + "@" <> rest if size == 0 -> parse_host(rest, pieces) + "@" <> rest -> { + let userinfo = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, userinfo: Some(userinfo)) + parse_host(rest, pieces) + } + + // If we reach the end of the authority string without finding an `@` + // special character, then we know that the authority doesn't actually + // contain the userinfo part. + // The entire string we just went through was a host! So we parse it as + // such. + "" | "/" <> _ | "?" <> _ | "#" <> _ -> parse_host(original, pieces) + + // In all other cases we just keep munching characters increasing the size + // of the userinfo bit. + _ -> { + let #(_, rest) = pop_codeunit(uri_string) + parse_userinfo_loop(original, rest, pieces, size + 1) + } + } +} + +fn parse_host(uri_string: String, pieces: Uri) -> Result(Uri, Nil) { + // A host string can be in two formats: + // - \[[:.a-zA-Z0-9]*\] + // - [^:] + case uri_string { + // If we find an opening bracket we know it's the first format. + "[" <> _ -> parse_host_within_brackets(uri_string, pieces) + + // A `:` marks the beginning of the port part of the authority string. + ":" <> _ -> { + let pieces = Uri(..pieces, host: Some("")) + parse_port(uri_string, pieces) + } + + // If the string is empty then there's no need to keep going. The host is + // empty. + "" -> Ok(Uri(..pieces, host: Some(""))) + + // Otherwise it's the second format + _ -> parse_host_outside_of_brackets(uri_string, pieces) + } +} + +fn parse_host_within_brackets( + uri_string: String, + pieces: Uri, +) -> Result(Uri, Nil) { + parse_host_within_brackets_loop(uri_string, uri_string, pieces, 0) +} + +fn parse_host_within_brackets_loop( + original: String, + uri_string: String, + pieces: Uri, + size: Int, +) -> Result(Uri, Nil) { + case uri_string { + // If the string is over the entire string we were iterating through is the + // host part. + "" -> Ok(Uri(..pieces, host: Some(uri_string))) + + // A `]` marks the end of the host and the start of the port part. + "]" <> rest if size == 0 -> parse_port(rest, pieces) + "]" <> rest -> { + let host = codeunit_slice(original, at_index: 0, length: size + 1) + let pieces = Uri(..pieces, host: Some(host)) + parse_port(rest, pieces) + } + + // `/` marks the beginning of a path. + "/" <> _ if size == 0 -> parse_path(uri_string, pieces) + "/" <> _ -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_path(uri_string, pieces) + } + + // `?` marks the beginning of the query with question mark. + "?" <> rest if size == 0 -> parse_query_with_question_mark(rest, pieces) + "?" <> rest -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_query_with_question_mark(rest, pieces) + } + + // `#` marks the beginning of the fragment part. + "#" <> rest if size == 0 -> parse_fragment(rest, pieces) + "#" <> rest -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_fragment(rest, pieces) + } + + // In all other cases we just keep iterating. + _ -> { + let #(char, rest) = pop_codeunit(uri_string) + // Inside `[...]` there can only be some characters, if we find a special + // one then we know that we're actually parsing the other format for the + // host and we switch to that! + case is_valid_host_within_brackets_char(char) { + True -> + parse_host_within_brackets_loop(original, rest, pieces, size + 1) + + False -> + parse_host_outside_of_brackets_loop(original, original, pieces, 0) + } + } + } +} + +fn is_valid_host_within_brackets_char(char: Int) -> Bool { + // [0-9] + { 48 >= char && char <= 57 } + // [A-Z] + || { 65 >= char && char <= 90 } + // [a-z] + || { 97 >= char && char <= 122 } + // : + || char == 58 + // . + || char == 46 +} + +fn parse_host_outside_of_brackets( + uri_string: String, + pieces: Uri, +) -> Result(Uri, Nil) { + parse_host_outside_of_brackets_loop(uri_string, uri_string, pieces, 0) +} + +fn parse_host_outside_of_brackets_loop( + original: String, + uri_string: String, + pieces: Uri, + size: Int, +) -> Result(Uri, Nil) { + case uri_string { + "" -> Ok(Uri(..pieces, host: Some(original))) + + // `:` marks the beginning of the port. + ":" <> _ -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_port(uri_string, pieces) + } + + // `/` marks the beginning of a path. + "/" <> _ -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_path(uri_string, pieces) + } + + // `?` marks the beginning of the query with question mark. + "?" <> rest -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_query_with_question_mark(rest, pieces) + } + + // `#` marks the beginning of the fragment part. + "#" <> rest -> { + let host = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, host: Some(host)) + parse_fragment(rest, pieces) + } + + _ -> { + let #(_, rest) = pop_codeunit(uri_string) + parse_host_outside_of_brackets_loop(original, rest, pieces, size + 1) + } + } +} + +fn parse_port(uri_string: String, pieces: Uri) -> Result(Uri, Nil) { + case uri_string { + ":0" <> rest -> parse_port_loop(rest, pieces, 0) + ":1" <> rest -> parse_port_loop(rest, pieces, 1) + ":2" <> rest -> parse_port_loop(rest, pieces, 2) + ":3" <> rest -> parse_port_loop(rest, pieces, 3) + ":4" <> rest -> parse_port_loop(rest, pieces, 4) + ":5" <> rest -> parse_port_loop(rest, pieces, 5) + ":6" <> rest -> parse_port_loop(rest, pieces, 6) + ":7" <> rest -> parse_port_loop(rest, pieces, 7) + ":8" <> rest -> parse_port_loop(rest, pieces, 8) + ":9" <> rest -> parse_port_loop(rest, pieces, 9) + + // It means the port segment is not composed of numbers, the port is invalid + // and so is the uri! + ":" <> _ -> Error(Nil) + + // `?` marks the beginning of the query with question mark. + "?" <> rest -> parse_query_with_question_mark(rest, pieces) + + // `#` marks the beginning of the fragment part. + "#" <> rest -> parse_fragment(rest, pieces) + + // `/` marks the beginning of a path. + "/" <> _ -> parse_path(uri_string, pieces) + + "" -> Ok(pieces) + + _ -> Error(Nil) + } +} + +fn parse_port_loop( + uri_string: String, + pieces: Uri, + port: Int, +) -> Result(Uri, Nil) { + case uri_string { + // As long as we find port numbers we keep accumulating those. + "0" <> rest -> parse_port_loop(rest, pieces, port * 10) + "1" <> rest -> parse_port_loop(rest, pieces, port * 10 + 1) + "2" <> rest -> parse_port_loop(rest, pieces, port * 10 + 2) + "3" <> rest -> parse_port_loop(rest, pieces, port * 10 + 3) + "4" <> rest -> parse_port_loop(rest, pieces, port * 10 + 4) + "5" <> rest -> parse_port_loop(rest, pieces, port * 10 + 5) + "6" <> rest -> parse_port_loop(rest, pieces, port * 10 + 6) + "7" <> rest -> parse_port_loop(rest, pieces, port * 10 + 7) + "8" <> rest -> parse_port_loop(rest, pieces, port * 10 + 8) + "9" <> rest -> parse_port_loop(rest, pieces, port * 10 + 9) + + // `?` marks the beginning of the query with question mark. + "?" <> rest -> { + let pieces = Uri(..pieces, port: Some(port)) + parse_query_with_question_mark(rest, pieces) + } + + // `#` marks the beginning of the fragment part. + "#" <> rest -> { + let pieces = Uri(..pieces, port: Some(port)) + parse_fragment(rest, pieces) + } + + // `/` marks the beginning of a path. + "/" <> _ -> { + let pieces = Uri(..pieces, port: Some(port)) + parse_path(uri_string, pieces) + } + + // The string (and so the port) is over, we return what we parsed so far. + "" -> Ok(Uri(..pieces, port: Some(port))) + + // In all other cases we've ran into some invalid character inside the port + // so the uri is invalid! + _ -> Error(Nil) + } +} + +fn parse_path(uri_string: String, pieces: Uri) -> Result(Uri, Nil) { + parse_path_loop(uri_string, uri_string, pieces, 0) +} + +fn parse_path_loop( + original: String, + uri_string: String, + pieces: Uri, + size: Int, +) -> Result(Uri, Nil) { + case uri_string { + // `?` marks the beginning of the query with question mark. + "?" <> rest -> { + let path = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, path: path) + parse_query_with_question_mark(rest, pieces) + } + + // `#` marks the beginning of the fragment part. + "#" <> rest -> { + let path = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, path: path) + parse_fragment(rest, pieces) + } + + // If the string is over that means the entirety of the string was the path + // and it has an empty query and fragment. + "" -> Ok(Uri(..pieces, path: original)) + + // In all other cases the character is allowed to be part of the path so we + // just keep munching until we reach to its end. + _ -> { + let #(_, rest) = pop_codeunit(uri_string) + parse_path_loop(original, rest, pieces, size + 1) + } + } +} + +fn parse_query_with_question_mark( + uri_string: String, + pieces: Uri, +) -> Result(Uri, Nil) { + parse_query_with_question_mark_loop(uri_string, uri_string, pieces, 0) +} + +fn parse_query_with_question_mark_loop( + original: String, + uri_string: String, + pieces: Uri, + size: Int, +) -> Result(Uri, Nil) { + case uri_string { + // `#` marks the beginning of the fragment part. + "#" <> rest if size == 0 -> parse_fragment(rest, pieces) + "#" <> rest -> { + let query = codeunit_slice(original, at_index: 0, length: size) + let pieces = Uri(..pieces, query: Some(query)) + parse_fragment(rest, pieces) + } + + // If the string is over that means the entirety of the string was the query + // and it has an empty fragment. + "" -> Ok(Uri(..pieces, query: Some(original))) + + // In all other cases the character is allowed to be part of the query so we + // just keep munching until we reach to its end. + _ -> { + let #(_, rest) = pop_codeunit(uri_string) + parse_query_with_question_mark_loop(original, rest, pieces, size + 1) + } + } +} + +fn parse_fragment(rest: String, pieces: Uri) -> Result(Uri, Nil) { + Ok(Uri(..pieces, fragment: Some(rest))) +} + +// WARN: this function returns invalid strings! +// We need to return a String anyways to have this as the representation on the +// JavaScript target. +// Alternatively, we could rewrite the entire code to use a single +// `fold_codeunits`-style loop and a state machine. +@external(erlang, "gleam_stdlib", "string_pop_codeunit") +@external(javascript, "../gleam_stdlib.mjs", "pop_codeunit") +fn pop_codeunit(str: String) -> #(Int, String) + +@external(erlang, "binary", "part") +@external(javascript, "../gleam_stdlib.mjs", "string_codeunit_slice") +fn codeunit_slice(str: String, at_index from: Int, length length: Int) -> String + +/// Parses an urlencoded query string into a list of key value pairs. +/// Returns an error for invalid encoding. +/// +/// The opposite operation is `uri.query_to_string`. +/// +/// ## Examples +/// +/// ```gleam +/// parse_query("a=1&b=2") +/// // -> Ok([#("a", "1"), #("b", "2")]) +/// ``` +/// +@external(erlang, "gleam_stdlib", "parse_query") +@external(javascript, "../gleam_stdlib.mjs", "parse_query") +pub fn parse_query(query: String) -> Result(List(#(String, String)), Nil) + +/// Encodes a list of key value pairs as a URI query string. +/// +/// The opposite operation is `uri.parse_query`. +/// +/// ## Examples +/// +/// ```gleam +/// query_to_string([#("a", "1"), #("b", "2")]) +/// // -> "a=1&b=2" +/// ``` +/// +pub fn query_to_string(query: List(#(String, String))) -> String { + query + |> list.map(query_pair) + |> list.intersperse(string_tree.from_string("&")) + |> string_tree.concat + |> string_tree.to_string +} + +fn query_pair(pair: #(String, String)) -> StringTree { + string_tree.from_strings([percent_encode(pair.0), "=", percent_encode(pair.1)]) +} + +/// Encodes a string into a percent encoded representation. +/// +/// ## Examples +/// +/// ```gleam +/// percent_encode("100% great") +/// // -> "100%25%20great" +/// ``` +/// +@external(erlang, "gleam_stdlib", "percent_encode") +@external(javascript, "../gleam_stdlib.mjs", "percent_encode") +pub fn percent_encode(value: String) -> String + +/// Decodes a percent encoded string. +/// +/// ## Examples +/// +/// ```gleam +/// percent_decode("100%25%20great+fun") +/// // -> Ok("100% great+fun") +/// ``` +/// +@external(erlang, "gleam_stdlib", "percent_decode") +@external(javascript, "../gleam_stdlib.mjs", "percent_decode") +pub fn percent_decode(value: String) -> Result(String, Nil) + +/// Splits the path section of a URI into it's constituent segments. +/// +/// Removes empty segments and resolves dot-segments as specified in +/// [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC. +/// +/// ## Examples +/// +/// ```gleam +/// path_segments("/users/1") +/// // -> ["users" ,"1"] +/// ``` +/// +pub fn path_segments(path: String) -> List(String) { + remove_dot_segments(string.split(path, "/")) +} + +fn remove_dot_segments(input: List(String)) -> List(String) { + remove_dot_segments_loop(input, []) +} + +fn remove_dot_segments_loop( + input: List(String), + accumulator: List(String), +) -> List(String) { + case input { + [] -> list.reverse(accumulator) + [segment, ..rest] -> { + let accumulator = case segment, accumulator { + "", accumulator -> accumulator + ".", accumulator -> accumulator + "..", [] -> [] + "..", [_, ..accumulator] -> accumulator + segment, accumulator -> [segment, ..accumulator] + } + remove_dot_segments_loop(rest, accumulator) + } + } +} + +/// Encodes a `Uri` value as a URI string. +/// +/// The opposite operation is `uri.parse`. +/// +/// ## Examples +/// +/// ```gleam +/// let uri = Uri(..empty, scheme: Some("https"), host: Some("example.com")) +/// to_string(uri) +/// // -> "https://example.com" +/// ``` +/// +pub fn to_string(uri: Uri) -> String { + let parts = case uri.fragment { + Some(fragment) -> ["#", fragment] + None -> [] + } + let parts = case uri.query { + Some(query) -> ["?", query, ..parts] + None -> parts + } + let parts = [uri.path, ..parts] + let parts = case uri.host, string.starts_with(uri.path, "/") { + Some(host), False if host != "" -> ["/", ..parts] + _, _ -> parts + } + let parts = case uri.host, uri.port { + Some(_), Some(port) -> [":", int.to_string(port), ..parts] + _, _ -> parts + } + let parts = case uri.scheme, uri.userinfo, uri.host { + Some(s), Some(u), Some(h) -> [s, "://", u, "@", h, ..parts] + Some(s), None, Some(h) -> [s, "://", h, ..parts] + Some(s), Some(_), None | Some(s), None, None -> [s, ":", ..parts] + None, None, Some(h) -> ["//", h, ..parts] + _, _, _ -> parts + } + string.concat(parts) +} + +/// Fetches the origin of a URI. +/// +/// Returns the origin of a uri as defined in +/// [RFC 6454](https://tools.ietf.org/html/rfc6454) +/// +/// The supported URI schemes are `http` and `https`. +/// URLs without a scheme will return `Error`. +/// +/// ## Examples +/// +/// ```gleam +/// let assert Ok(uri) = parse("https://example.com/path?foo#bar") +/// origin(uri) +/// // -> Ok("https://example.com") +/// ``` +/// +pub fn origin(uri: Uri) -> Result(String, Nil) { + let Uri(scheme: scheme, host: host, port: port, ..) = uri + case host, scheme { + Some(h), Some("https") if port == Some(443) -> + Ok(string.concat(["https://", h])) + Some(h), Some("http") if port == Some(80) -> + Ok(string.concat(["http://", h])) + Some(h), Some(s) if s == "http" || s == "https" -> { + case port { + Some(p) -> Ok(string.concat([s, "://", h, ":", int.to_string(p)])) + None -> Ok(string.concat([s, "://", h])) + } + } + _, _ -> Error(Nil) + } +} + +/// Resolves a URI with respect to the given base URI. +/// +/// The base URI must be an absolute URI or this function will return an error. +/// The algorithm for merging uris is described in +/// [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2). +/// +pub fn merge(base: Uri, relative: Uri) -> Result(Uri, Nil) { + case base { + Uri(scheme: Some(_), host: Some(_), ..) -> + case relative { + Uri(host: Some(_), ..) -> { + let path = + string.split(relative.path, "/") + |> remove_dot_segments() + |> join_segments() + let resolved = + Uri( + option.or(relative.scheme, base.scheme), + None, + relative.host, + option.or(relative.port, base.port), + path, + relative.query, + relative.fragment, + ) + Ok(resolved) + } + _ -> { + let #(new_path, new_query) = case relative.path { + "" -> #(base.path, option.or(relative.query, base.query)) + _ -> { + let path_segments = case string.starts_with(relative.path, "/") { + True -> string.split(relative.path, "/") + False -> + string.split(base.path, "/") + |> drop_last() + |> list.append(string.split(relative.path, "/")) + } + let path = + path_segments + |> remove_dot_segments() + |> join_segments() + #(path, relative.query) + } + } + let resolved = + Uri( + base.scheme, + None, + base.host, + base.port, + new_path, + new_query, + relative.fragment, + ) + Ok(resolved) + } + } + _ -> Error(Nil) + } +} + +fn drop_last(elements: List(a)) -> List(a) { + list.take(from: elements, up_to: list.length(elements) - 1) +} + +fn join_segments(segments: List(String)) -> String { + string.join(["", ..segments], "/") +} diff --git a/build/packages/gleam_stdlib/src/gleam@bit_array.erl b/build/packages/gleam_stdlib/src/gleam@bit_array.erl new file mode 100644 index 0000000..80a11e4 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@bit_array.erl @@ -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; + + <> -> + <<<>/binary, + ":size(1)"/utf8>>; + + <> -> + <<<>/binary, + ":size(2)"/utf8>>; + + <> -> + <<<>/binary, + ":size(3)"/utf8>>; + + <> -> + <<<>/binary, + ":size(4)"/utf8>>; + + <> -> + <<<>/binary, + ":size(5)"/utf8>>; + + <> -> + <<<>/binary, + ":size(6)"/utf8>>; + + <> -> + <<<>/binary, + ":size(7)"/utf8>>; + + <> -> + Suffix = case Rest of + <<>> -> + <<""/utf8>>; + + _ -> + <<", "/utf8>> + end, + Accumulator@1 = <<<>/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 + {<>, + <>} -> + 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 + <> when Pref =:= Prefix -> + true; + + _ -> + false + end. diff --git a/build/packages/gleam_stdlib/src/gleam@bool.erl b/build/packages/gleam_stdlib/src/gleam@bool.erl new file mode 100644 index 0000000..a09a3eb --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@bool.erl @@ -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. diff --git a/build/packages/gleam_stdlib/src/gleam@bytes_tree.erl b/build/packages/gleam_stdlib/src/gleam@bytes_tree.erl new file mode 100644 index 0000000..5e78e9c --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@bytes_tree.erl @@ -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). diff --git a/build/packages/gleam_stdlib/src/gleam@dict.erl b/build/packages/gleam_stdlib/src/gleam@dict.erl new file mode 100644 index 0000000..ad3b17b --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@dict.erl @@ -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 + ). diff --git a/build/packages/gleam_stdlib/src/gleam@dynamic.erl b/build/packages/gleam_stdlib/src/gleam@dynamic.erl new file mode 100644 index 0000000..027b403 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@dynamic.erl @@ -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). diff --git a/build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl b/build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl new file mode 100644 index 0000000..0996e6c --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl @@ -0,0 +1,1084 @@ +-module(gleam@dynamic@decode). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleam/dynamic/decode.gleam"). +-export([run/2, success/1, decode_dynamic/1, map/2, map_errors/2, then/2, one_of/2, recursive/1, optional/1, decode_error/2, decode_bool/1, decode_int/1, decode_float/1, decode_bit_array/1, collapse_errors/2, failure/2, new_primitive_decoder/2, decode_string/1, dict/2, list/1, subfield/3, at/2, field/3, optional_field/4, optionally_at/3]). +-export_type([decode_error/0, decoder/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( + " The `Dynamic` type is used to represent dynamically typed data. That is, data\n" + " that we don't know the precise type of yet, so we need to introspect the data to\n" + " see if it is of the desired type before we can use it. Typically data like this\n" + " would come from user input or from untyped languages such as Erlang or JavaScript.\n" + "\n" + " This module provides the `Decoder` type and associated functions, which provides\n" + " a type-safe and composable way to convert dynamic data into some desired type,\n" + " or into errors if the data doesn't have the desired structure.\n" + "\n" + " The `Decoder` type is generic and has 1 type parameter, which is the type that\n" + " it attempts to decode. A `Decoder(String)` can be used to decode strings, and a\n" + " `Decoder(Option(Int))` can be used to decode `Option(Int)`s\n" + "\n" + " Decoders work using _runtime reflection_ and the data structures of the target\n" + " platform. Differences between Erlang and JavaScript data structures may impact\n" + " your decoders, so it is important to test your decoders on all supported\n" + " platforms.\n" + "\n" + " The decoding technique used by this module was inspired by Juraj Petráš'\n" + " [Toy](https://github.com/Hackder/toy), Go's `encoding/json`, and Elm's\n" + " `Json.Decode`. Thank you to them!\n" + "\n" + " # Examples\n" + "\n" + " Dynamic data may come from various sources and so many different syntaxes could\n" + " be used to describe or construct them. In these examples a pseudocode\n" + " syntax is used to describe the data.\n" + "\n" + " ## Simple types\n" + "\n" + " This module defines decoders for simple data types such as [`string`](#string),\n" + " [`int`](#int), [`float`](#float), [`bit_array`](#bit_array), and [`bool`](#bool).\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // \"Hello, Joe!\"\n" + "\n" + " let result = decode.run(data, decode.string)\n" + " assert result == Ok(\"Hello, Joe!\")\n" + " ```\n" + "\n" + " ## Lists\n" + "\n" + " The [`list`](#list) decoder decodes `List`s. To use it you must construct it by\n" + " passing in another decoder into the `list` function, which is the decoder that\n" + " is to be used for the elements of the list, type checking both the list and its\n" + " elements.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // [1, 2, 3, 4]\n" + "\n" + " let result = decode.run(data, decode.list(decode.int))\n" + " assert result == Ok([1, 2, 3, 4])\n" + " ```\n" + "\n" + " On Erlang this decoder can decode from lists, and on JavaScript it can\n" + " decode from lists as well as JavaScript arrays.\n" + "\n" + " ## Options\n" + "\n" + " The [`optional`](#optional) decoder is used to decode values that may or may not\n" + " be present. In other environment these might be called \"nullable\" values.\n" + "\n" + " Like the `list` decoder, the `optional` decoder takes another decoder,\n" + " which is used to decode the value if it is present.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // 12.45\n" + "\n" + " let result = decode.run(data, decode.optional(decode.float))\n" + " assert result == Ok(option.Some(12.45))\n" + " ```\n" + " ```gleam\n" + " // Data:\n" + " // null\n" + "\n" + " let result = decode.run(data, decode.optional(decode.int))\n" + " assert result == Ok(option.None)\n" + " ```\n" + "\n" + " This decoder knows how to handle multiple different runtime representations of\n" + " absent values, including `Nil`, `None`, `null`, and `undefined`.\n" + "\n" + " ## Dicts\n" + "\n" + " The [`dict`](#dict) decoder decodes `Dicts` and contains two other decoders, one\n" + " for the keys, one for the values.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // { \"Lucy\" -> 10, \"Nubi\" -> 20 }\n" + "\n" + " let result = decode.run(data, decode.dict(decode.string, decode.int))\n" + " assert result == Ok(dict.from_list([\n" + " #(\"Lucy\", 10),\n" + " #(\"Nubi\", 20),\n" + " ]))\n" + " ```\n" + "\n" + " ## Indexing objects\n" + "\n" + " The [`at`](#at) decoder can be used to decode a value that is nested within\n" + " key-value containers such as Gleam dicts, Erlang maps, or JavaScript objects.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // { \"one\" -> { \"two\" -> 123 } }\n" + "\n" + " let result = decode.run(data, decode.at([\"one\", \"two\"], decode.int))\n" + " assert result == Ok(123)\n" + " ```\n" + "\n" + " ## Indexing arrays\n" + "\n" + " If you use ints as keys then the [`at`](#at) decoder can be used to index into\n" + " array-like containers such as Gleam or Erlang tuples, or JavaScript arrays.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // [\"one\", \"two\", \"three\"]\n" + "\n" + " let result = decode.run(data, decode.at([1], decode.string))\n" + " assert result == Ok(\"two\")\n" + " ```\n" + "\n" + " ## Records\n" + "\n" + " Decoding records from dynamic data is more complex and requires combining a\n" + " decoder for each field and a special constructor that builds your records with\n" + " the decoded field values.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // {\n" + " // \"score\" -> 180,\n" + " // \"name\" -> \"Mel Smith\",\n" + " // \"is-admin\" -> false,\n" + " // \"enrolled\" -> true,\n" + " // \"colour\" -> \"Red\",\n" + " // }\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", decode.string)\n" + " use score <- decode.field(\"score\", decode.int)\n" + " use colour <- decode.field(\"colour\", decode.string)\n" + " use enrolled <- decode.field(\"enrolled\", decode.bool)\n" + " decode.success(Player(name:, score:, colour:, enrolled:))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(Player(\"Mel Smith\", 180, \"Red\", True))\n" + " ```\n" + "\n" + " ## Enum variants\n" + "\n" + " Imagine you have a custom type where all the variants do not contain any values.\n" + "\n" + " ```gleam\n" + " pub type PocketMonsterType {\n" + " Fire\n" + " Water\n" + " Grass\n" + " Electric\n" + " }\n" + " ```\n" + "\n" + " You might choose to encode these variants as strings, `\"fire\"` for `Fire`,\n" + " `\"water\"` for `Water`, and so on. To decode them you'll need to decode the dynamic\n" + " data as a string, but then you'll need to decode it further still as not all\n" + " strings are valid values for the enum. This can be done with the `then`\n" + " function, which enables running a second decoder after the first one\n" + " succeeds.\n" + "\n" + " ```gleam\n" + " let decoder = {\n" + " use decoded_string <- decode.then(decode.string)\n" + " case decoded_string {\n" + " // Return succeeding decoders for valid strings\n" + " \"fire\" -> decode.success(Fire)\n" + " \"water\" -> decode.success(Water)\n" + " \"grass\" -> decode.success(Grass)\n" + " \"electric\" -> decode.success(Electric)\n" + " // Return a failing decoder for any other strings\n" + " _ -> decode.failure(Fire, \"PocketMonsterType\")\n" + " }\n" + " }\n" + "\n" + " let result = decode.run(dynamic.from(\"water\"), decoder)\n" + " assert result == Ok(Water)\n" + "\n" + " let result = decode.run(dynamic.from(\"wobble\"), decoder)\n" + " assert result == Error([DecodeError(\"PocketMonsterType\", \"String\", [])])\n" + " ```\n" + "\n" + " ## Record variants\n" + "\n" + " Decoding type variants that contain other values is done by combining the\n" + " techniques from the \"enum variants\" and \"records\" examples. Imagine you have\n" + " this custom type that you want to decode:\n" + "\n" + " ```gleam\n" + " pub type PocketMonsterPerson {\n" + " Trainer(name: String, badge_count: Int)\n" + " GymLeader(name: String, speciality: PocketMonsterType)\n" + " }\n" + " ```\n" + " And you would like to be able to decode these from dynamic data like this:\n" + " ```erlang\n" + " {\n" + " \"type\" -> \"trainer\",\n" + " \"name\" -> \"Ash\",\n" + " \"badge-count\" -> 1,\n" + " }\n" + " ```\n" + " ```erlang\n" + " {\n" + " \"type\" -> \"gym-leader\",\n" + " \"name\" -> \"Misty\",\n" + " \"speciality\" -> \"water\",\n" + " }\n" + " ```\n" + "\n" + " Notice how both documents have a `\"type\"` field, which is used to indicate which\n" + " variant the data is for.\n" + "\n" + " First, define decoders for each of the variants:\n" + "\n" + " ```gleam\n" + " let trainer_decoder = {\n" + " use name <- decode.field(\"name\", decode.string)\n" + " use badge_count <- decode.field(\"badge-count\", decode.int)\n" + " decode.success(Trainer(name, badge_count))\n" + " }\n" + "\n" + " let gym_leader_decoder = {\n" + " use name <- decode.field(\"name\", decode.string)\n" + " use speciality <- decode.field(\"speciality\", pocket_monster_type_decoder)\n" + " decode.success(GymLeader(name, speciality))\n" + " }\n" + " ```\n" + "\n" + " A third decoder can be used to extract and decode the `\"type\"` field, and the\n" + " expression can evaluate to whichever decoder is suitable for the document.\n" + "\n" + " ```gleam\n" + " // Data:\n" + " // {\n" + " // \"type\" -> \"gym-leader\",\n" + " // \"name\" -> \"Misty\",\n" + " // \"speciality\" -> \"water\",\n" + " // }\n" + "\n" + " let decoder = {\n" + " use tag <- decode.field(\"type\", decode.string)\n" + " case tag {\n" + " \"gym-leader\" -> gym_leader_decoder\n" + " _ -> trainer_decoder\n" + " }\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(GymLeader(\"Misty\", Water))\n" + " ```\n" +). + +-type decode_error() :: {decode_error, binary(), binary(), list(binary())}. + +-opaque decoder(BXN) :: {decoder, + fun((gleam@dynamic:dynamic_()) -> {BXN, list(decode_error())})}. + +-file("src/gleam/dynamic/decode.gleam", 356). +?DOC( + " Run a decoder on a `Dynamic` value, decoding the value if it is of the\n" + " desired type, or returning errors.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = {\n" + " use name <- decode.field(\"email\", decode.string)\n" + " use email <- decode.field(\"password\", decode.string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " decode.run(data, decoder)\n" + " ```\n" +). +-spec run(gleam@dynamic:dynamic_(), decoder(BXV)) -> {ok, BXV} | + {error, list(decode_error())}. +run(Data, Decoder) -> + {Maybe_invalid_data, Errors} = (erlang:element(2, Decoder))(Data), + case Errors of + [] -> + {ok, Maybe_invalid_data}; + + [_ | _] -> + {error, Errors} + end. + +-file("src/gleam/dynamic/decode.gleam", 478). +?DOC( + " Finalise a decoder having successfully extracted a value.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"email\", \"lucy@example.com\"),\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", string)\n" + " use email <- decode.field(\"email\", string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" + " ```\n" +). +-spec success(BYW) -> decoder(BYW). +success(Data) -> + {decoder, fun(_) -> {Data, []} end}. + +-file("src/gleam/dynamic/decode.gleam", 717). +-spec decode_dynamic(gleam@dynamic:dynamic_()) -> {gleam@dynamic:dynamic_(), + list(decode_error())}. +decode_dynamic(Data) -> + {Data, []}. + +-file("src/gleam/dynamic/decode.gleam", 871). +?DOC( + " Apply a transformation function to any value decoded by the decoder.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.int |> decode.map(int.to_string)\n" + " let result = decode.run(dynamic.from(1000), decoder)\n" + " assert result == Ok(\"1000\")\n" + " ```\n" +). +-spec map(decoder(CBT), fun((CBT) -> CBV)) -> decoder(CBV). +map(Decoder, Transformer) -> + {decoder, + fun(D) -> + {Data, Errors} = (erlang:element(2, Decoder))(D), + {Transformer(Data), Errors} + end}. + +-file("src/gleam/dynamic/decode.gleam", 880). +?DOC(" Apply a transformation function to any errors returned by the decoder.\n"). +-spec map_errors( + decoder(CBX), + fun((list(decode_error())) -> list(decode_error())) +) -> decoder(CBX). +map_errors(Decoder, Transformer) -> + {decoder, + fun(D) -> + {Data, Errors} = (erlang:element(2, Decoder))(D), + {Data, Transformer(Errors)} + end}. + +-file("src/gleam/dynamic/decode.gleam", 918). +?DOC( + " Create a new decoder based upon the value of a previous decoder.\n" + "\n" + " This may be useful to run one previous decoder to use in further decoding.\n" +). +-spec then(decoder(CCF), fun((CCF) -> decoder(CCH))) -> decoder(CCH). +then(Decoder, Next) -> + {decoder, + fun(Dynamic_data) -> + {Data, Errors} = (erlang:element(2, Decoder))(Dynamic_data), + Decoder@1 = Next(Data), + {Data@1, _} = Layer = (erlang:element(2, Decoder@1))(Dynamic_data), + case Errors of + [] -> + Layer; + + [_ | _] -> + {Data@1, Errors} + end + end}. + +-file("src/gleam/dynamic/decode.gleam", 961). +-spec run_decoders( + gleam@dynamic:dynamic_(), + {CCP, list(decode_error())}, + list(decoder(CCP)) +) -> {CCP, list(decode_error())}. +run_decoders(Data, Failure, Decoders) -> + case Decoders of + [] -> + Failure; + + [Decoder | Decoders@1] -> + {_, Errors} = Layer = (erlang:element(2, Decoder))(Data), + case Errors of + [] -> + Layer; + + [_ | _] -> + run_decoders(Data, Failure, Decoders@1) + end + end. + +-file("src/gleam/dynamic/decode.gleam", 948). +?DOC( + " Create a new decoder from several other decoders. Each of the inner\n" + " decoders is run in turn, and the value from the first to succeed is used.\n" + "\n" + " If no decoder succeeds then the errors from the first decoder is used.\n" + " If you wish for different errors then you may wish to use the\n" + " `collapse_errors` or `map_errors` functions.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.one_of(decode.string, or: [\n" + " decode.int |> decode.map(int.to_string),\n" + " decode.float |> decode.map(float.to_string),\n" + " ])\n" + " decode.run(dynamic.from(1000), decoder)\n" + " // -> Ok(\"1000\")\n" + " ```\n" +). +-spec one_of(decoder(CCK), list(decoder(CCK))) -> decoder(CCK). +one_of(First, Alternatives) -> + {decoder, + fun(Dynamic_data) -> + {_, Errors} = Layer = (erlang:element(2, First))(Dynamic_data), + case Errors of + [] -> + Layer; + + [_ | _] -> + run_decoders(Dynamic_data, Layer, Alternatives) + end + end}. + +-file("src/gleam/dynamic/decode.gleam", 1044). +?DOC( + " Create a decoder that can refer to itself, useful for decoding deeply\n" + " nested data.\n" + "\n" + " Attempting to create a recursive decoder without this function could result\n" + " in an infinite loop. If you are using `field` or other `use`able functions\n" + " then you may not need to use this function.\n" + "\n" + " ```gleam\n" + " type Nested {\n" + " Nested(List(Nested))\n" + " Value(String)\n" + " }\n" + "\n" + " fn nested_decoder() -> decode.Decoder(Nested) {\n" + " use <- decode.recursive\n" + " decode.one_of(decode.string |> decode.map(Value), [\n" + " decode.list(nested_decoder()) |> decode.map(Nested),\n" + " ])\n" + " }\n" + " ```\n" +). +-spec recursive(fun(() -> decoder(CDA))) -> decoder(CDA). +recursive(Inner) -> + {decoder, + fun(Data) -> + Decoder = Inner(), + (erlang:element(2, Decoder))(Data) + end}. + +-file("src/gleam/dynamic/decode.gleam", 849). +?DOC( + " A decoder that decodes nullable values of a type decoded by with a given\n" + " decoder.\n" + "\n" + " This function can handle common representations of null on all runtimes, such as\n" + " `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on\n" + " JavaScript.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let result = decode.run(dynamic.from(100), decode.optional(decode.int))\n" + " assert result == Ok(option.Some(100))\n" + " ```\n" + "\n" + " ```gleam\n" + " let result = decode.run(dynamic.from(Nil), decode.optional(decode.int))\n" + " assert result == Ok(option.None)\n" + " ```\n" +). +-spec optional(decoder(CBP)) -> decoder(gleam@option:option(CBP)). +optional(Inner) -> + {decoder, fun(Data) -> case gleam_stdlib:is_null(Data) of + true -> + {none, []}; + + false -> + {Data@1, Errors} = (erlang:element(2, Inner))(Data), + {{some, Data@1}, Errors} + end end}. + +-file("src/gleam/dynamic/decode.gleam", 484). +?DOC(" Construct a decode error for some unexpected dynamic data.\n"). +-spec decode_error(binary(), gleam@dynamic:dynamic_()) -> list(decode_error()). +decode_error(Expected, Found) -> + [{decode_error, Expected, gleam_stdlib:classify_dynamic(Found), []}]. + +-file("src/gleam/dynamic/decode.gleam", 608). +-spec run_dynamic_function( + gleam@dynamic:dynamic_(), + binary(), + fun((gleam@dynamic:dynamic_()) -> {ok, BZQ} | {error, BZQ}) +) -> {BZQ, list(decode_error())}. +run_dynamic_function(Data, Name, F) -> + case F(Data) of + {ok, Data@1} -> + {Data@1, []}; + + {error, Zero} -> + {Zero, + [{decode_error, Name, gleam_stdlib:classify_dynamic(Data), []}]} + end. + +-file("src/gleam/dynamic/decode.gleam", 657). +-spec decode_bool(gleam@dynamic:dynamic_()) -> {boolean(), list(decode_error())}. +decode_bool(Data) -> + case gleam_stdlib:identity(true) =:= Data of + true -> + {true, []}; + + false -> + case gleam_stdlib:identity(false) =:= Data of + true -> + {false, []}; + + false -> + {false, decode_error(<<"Bool"/utf8>>, Data)} + end + end. + +-file("src/gleam/dynamic/decode.gleam", 679). +-spec decode_int(gleam@dynamic:dynamic_()) -> {integer(), list(decode_error())}. +decode_int(Data) -> + run_dynamic_function(Data, <<"Int"/utf8>>, fun gleam_stdlib:int/1). + +-file("src/gleam/dynamic/decode.gleam", 698). +-spec decode_float(gleam@dynamic:dynamic_()) -> {float(), list(decode_error())}. +decode_float(Data) -> + run_dynamic_function(Data, <<"Float"/utf8>>, fun gleam_stdlib:float/1). + +-file("src/gleam/dynamic/decode.gleam", 732). +-spec decode_bit_array(gleam@dynamic:dynamic_()) -> {bitstring(), + list(decode_error())}. +decode_bit_array(Data) -> + run_dynamic_function( + Data, + <<"BitArray"/utf8>>, + fun gleam_stdlib:bit_array/1 + ). + +-file("src/gleam/dynamic/decode.gleam", 904). +?DOC( + " Replace all errors produced by a decoder with one single error for a named\n" + " expected type.\n" + "\n" + " This function may be useful if you wish to simplify errors before\n" + " presenting them to a user, particularly when using the `one_of` function.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.string |> decode.collapse_errors(\"MyThing\")\n" + " let result = decode.run(dynamic.from(1000), decoder)\n" + " assert result == Error([DecodeError(\"MyThing\", \"Int\", [])])\n" + " ```\n" +). +-spec collapse_errors(decoder(CCC), binary()) -> decoder(CCC). +collapse_errors(Decoder, Name) -> + {decoder, + fun(Dynamic_data) -> + {Data, Errors} = Layer = (erlang:element(2, Decoder))(Dynamic_data), + case Errors of + [] -> + Layer; + + [_ | _] -> + {Data, decode_error(Name, Dynamic_data)} + end + end}. + +-file("src/gleam/dynamic/decode.gleam", 982). +?DOC( + " Define a decoder that always fails. The parameter for this function is the\n" + " name of the type that has failed to decode.\n" +). +-spec failure(CCU, binary()) -> decoder(CCU). +failure(Zero, Expected) -> + {decoder, fun(D) -> {Zero, decode_error(Expected, D)} end}. + +-file("src/gleam/dynamic/decode.gleam", 1011). +?DOC( + " Create a decoder for a new data type from a decoding function.\n" + "\n" + " This function is used for new primitive types. For example, you might\n" + " define a decoder for Erlang's pid type.\n" + "\n" + " A default \"zero\" value is also required to make a decoder. When this\n" + " decoder is used as part of a larger decoder this zero value used as\n" + " a placeholder so that the rest of the decoder can continue to run and\n" + " collect all decoding errors.\n" + "\n" + " If you were to make a decoder for the `String` type (rather than using the\n" + " build-in `string` decoder) you would define it like so:\n" + "\n" + " ```gleam\n" + " pub fn string_decoder() -> decode.Decoder(String) {\n" + " let default = \"\"\n" + " decode.new_primitive_decoder(\"String\", fn(data) {\n" + " case dynamic.string(data) {\n" + " Ok(x) -> Ok(x)\n" + " Error(_) -> Error(default)\n" + " }\n" + " })\n" + " }\n" + " ```\n" +). +-spec new_primitive_decoder( + binary(), + fun((gleam@dynamic:dynamic_()) -> {ok, CCW} | {error, CCW}) +) -> decoder(CCW). +new_primitive_decoder(Name, Decoding_function) -> + {decoder, fun(D) -> case Decoding_function(D) of + {ok, T} -> + {T, []}; + + {error, Zero} -> + {Zero, + [{decode_error, + Name, + gleam_stdlib:classify_dynamic(D), + []}]} + end end}. + +-file("src/gleam/dynamic/decode.gleam", 635). +-spec dynamic_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | + {error, binary()}. +dynamic_string(Data) -> + case gleam_stdlib:bit_array(Data) of + {ok, Data@1} -> + case gleam@bit_array:to_string(Data@1) of + {ok, String} -> + {ok, String}; + + {error, _} -> + {error, <<""/utf8>>} + end; + + {error, _} -> + {error, <<""/utf8>>} + end. + +-file("src/gleam/dynamic/decode.gleam", 630). +-spec decode_string(gleam@dynamic:dynamic_()) -> {binary(), + list(decode_error())}. +decode_string(Data) -> + run_dynamic_function(Data, <<"String"/utf8>>, fun dynamic_string/1). + +-file("src/gleam/dynamic/decode.gleam", 803). +-spec fold_dict( + {gleam@dict:dict(CBB, CBC), list(decode_error())}, + gleam@dynamic:dynamic_(), + gleam@dynamic:dynamic_(), + fun((gleam@dynamic:dynamic_()) -> {CBB, list(decode_error())}), + fun((gleam@dynamic:dynamic_()) -> {CBC, list(decode_error())}) +) -> {gleam@dict:dict(CBB, CBC), list(decode_error())}. +fold_dict(Acc, Key, Value, Key_decoder, Value_decoder) -> + case Key_decoder(Key) of + {Key@1, []} -> + case Value_decoder(Value) of + {Value@1, []} -> + Dict = gleam@dict:insert( + erlang:element(1, Acc), + Key@1, + Value@1 + ), + {Dict, erlang:element(2, Acc)}; + + {_, Errors} -> + push_path({maps:new(), Errors}, [<<"values"/utf8>>]) + end; + + {_, Errors@1} -> + push_path({maps:new(), Errors@1}, [<<"keys"/utf8>>]) + end. + +-file("src/gleam/dynamic/decode.gleam", 783). +?DOC( + " A decoder that decodes dicts where all keys and vales are decoded with\n" + " given decoders.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let values = dict.from_list([\n" + " #(\"one\", 1),\n" + " #(\"two\", 2),\n" + " ])\n" + "\n" + " let result =\n" + " decode.run(dynamic.from(values), decode.dict(decode.string, decode.int))\n" + " assert result == Ok(values)\n" + " ```\n" +). +-spec dict(decoder(CAU), decoder(CAW)) -> decoder(gleam@dict:dict(CAU, CAW)). +dict(Key, Value) -> + {decoder, fun(Data) -> case gleam_stdlib:dict(Data) of + {error, _} -> + {maps:new(), decode_error(<<"Dict"/utf8>>, Data)}; + + {ok, Dict} -> + gleam@dict:fold( + Dict, + {maps:new(), []}, + fun(A, K, V) -> case erlang:element(2, A) of + [] -> + fold_dict( + A, + K, + V, + erlang:element(2, Key), + erlang:element(2, Value) + ); + + [_ | _] -> + A + end end + ) + end end}. + +-file("src/gleam/dynamic/decode.gleam", 751). +?DOC( + " A decoder that decodes lists where all elements are decoded with a given\n" + " decoder.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let result =\n" + " decode.run(dynamic.from([1, 2, 3]), decode.list(of: decode.int))\n" + " assert result == Ok([1, 2, 3])\n" + " ```\n" +). +-spec list(decoder(CAI)) -> decoder(list(CAI)). +list(Inner) -> + {decoder, + fun(Data) -> + gleam_stdlib:list( + Data, + erlang:element(2, Inner), + fun(P, K) -> push_path(P, [K]) end, + 0, + [] + ) + end}. + +-file("src/gleam/dynamic/decode.gleam", 438). +-spec push_path({BYR, list(decode_error())}, list(any())) -> {BYR, + list(decode_error())}. +push_path(Layer, Path) -> + Decoder = one_of( + {decoder, fun decode_string/1}, + [begin + _pipe = {decoder, fun decode_int/1}, + map(_pipe, fun erlang:integer_to_binary/1) + end] + ), + Path@1 = gleam@list:map( + Path, + fun(Key) -> + Key@1 = gleam_stdlib:identity(Key), + case run(Key@1, Decoder) of + {ok, Key@2} -> + Key@2; + + {error, _} -> + <<<<"<"/utf8, + (gleam_stdlib:classify_dynamic(Key@1))/binary>>/binary, + ">"/utf8>> + end + end + ), + Errors = gleam@list:map( + erlang:element(2, Layer), + fun(Error) -> + {decode_error, + erlang:element(2, Error), + erlang:element(3, Error), + lists:append(Path@1, erlang:element(4, Error))} + end + ), + {erlang:element(1, Layer), Errors}. + +-file("src/gleam/dynamic/decode.gleam", 403). +-spec index( + list(BYF), + list(BYF), + fun((gleam@dynamic:dynamic_()) -> {BYI, list(decode_error())}), + gleam@dynamic:dynamic_(), + fun((gleam@dynamic:dynamic_(), list(BYF)) -> {BYI, list(decode_error())}) +) -> {BYI, list(decode_error())}. +index(Path, Position, Inner, Data, Handle_miss) -> + case Path of + [] -> + _pipe = Inner(Data), + push_path(_pipe, lists:reverse(Position)); + + [Key | Path@1] -> + case gleam_stdlib:index(Data, Key) of + {ok, {some, Data@1}} -> + index(Path@1, [Key | Position], Inner, Data@1, Handle_miss); + + {ok, none} -> + Handle_miss(Data, [Key | Position]); + + {error, Kind} -> + {Default, _} = Inner(Data), + _pipe@1 = {Default, + [{decode_error, + Kind, + gleam_stdlib:classify_dynamic(Data), + []}]}, + push_path(_pipe@1, lists:reverse(Position)) + end + end. + +-file("src/gleam/dynamic/decode.gleam", 324). +?DOC( + " The same as [`field`](#field), except taking a path to the value rather\n" + " than a field name.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"data\", dict.from_list([\n" + " #(\"email\", \"lucy@example.com\"),\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.subfield([\"data\", \"name\"], decode.string)\n" + " use email <- decode.subfield([\"data\", \"email\"], decode.string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" + " ```\n" +). +-spec subfield(list(any()), decoder(BXQ), fun((BXQ) -> decoder(BXS))) -> decoder(BXS). +subfield(Field_path, Field_decoder, Next) -> + {decoder, + fun(Data) -> + {Out, Errors1} = index( + Field_path, + [], + erlang:element(2, Field_decoder), + Data, + fun(Data@1, Position) -> + {Default, _} = (erlang:element(2, Field_decoder))(Data@1), + _pipe = {Default, + [{decode_error, + <<"Field"/utf8>>, + <<"Nothing"/utf8>>, + []}]}, + push_path(_pipe, lists:reverse(Position)) + end + ), + {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), + {Out@1, lists:append(Errors1, Errors2)} + end}. + +-file("src/gleam/dynamic/decode.gleam", 393). +?DOC( + " A decoder that decodes a value that is nested within other values. For\n" + " example, decoding a value that is within some deeply nested JSON objects.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.at([\"one\", \"two\"], decode.int)\n" + "\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"one\", dict.from_list([\n" + " #(\"two\", 1000),\n" + " ])),\n" + " ]))\n" + "\n" + "\n" + " decode.run(data, decoder)\n" + " // -> Ok(1000)\n" + " ```\n" + "\n" + " ```gleam\n" + " dynamic.from(Nil)\n" + " |> decode.run(decode.optional(decode.int))\n" + " // -> Ok(option.None)\n" + " ```\n" +). +-spec at(list(any()), decoder(BYC)) -> decoder(BYC). +at(Path, Inner) -> + {decoder, + fun(Data) -> + index( + Path, + [], + erlang:element(2, Inner), + Data, + fun(Data@1, Position) -> + {Default, _} = (erlang:element(2, Inner))(Data@1), + _pipe = {Default, + [{decode_error, + <<"Field"/utf8>>, + <<"Nothing"/utf8>>, + []}]}, + push_path(_pipe, lists:reverse(Position)) + end + ) + end}. + +-file("src/gleam/dynamic/decode.gleam", 523). +?DOC( + " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" + " of the desired type, or returning errors. An error is returned if there is\n" + " no field for the specified key.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"email\", \"lucy@example.com\"),\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", string)\n" + " use email <- decode.field(\"email\", string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" + " ```\n" + "\n" + " If you wish to decode a value that is more deeply nested within the dynamic\n" + " data, see [`subfield`](#subfield) and [`at`](#at).\n" + "\n" + " If you wish to return a default in the event that a field is not present,\n" + " see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).\n" +). +-spec field(any(), decoder(BZA), fun((BZA) -> decoder(BZC))) -> decoder(BZC). +field(Field_name, Field_decoder, Next) -> + subfield([Field_name], Field_decoder, Next). + +-file("src/gleam/dynamic/decode.gleam", 556). +?DOC( + " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" + " of the desired type, or returning errors. The given default value is\n" + " returned if there is no field for the specified key.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"name\", \"Lucy\"),\n" + " ]))\n" + "\n" + " let decoder = {\n" + " use name <- decode.field(\"name\", string)\n" + " use email <- decode.optional_field(\"email\", \"n/a\", string)\n" + " decode.success(SignUp(name: name, email: email))\n" + " }\n" + "\n" + " let result = decode.run(data, decoder)\n" + " assert result == Ok(SignUp(name: \"Lucy\", email: \"n/a\"))\n" + " ```\n" +). +-spec optional_field(any(), BZG, decoder(BZG), fun((BZG) -> decoder(BZI))) -> decoder(BZI). +optional_field(Key, Default, Field_decoder, Next) -> + {decoder, + fun(Data) -> + {Out, Errors1} = begin + _pipe = case gleam_stdlib:index(Data, Key) of + {ok, {some, Data@1}} -> + (erlang:element(2, Field_decoder))(Data@1); + + {ok, none} -> + {Default, []}; + + {error, Kind} -> + {Default, + [{decode_error, + Kind, + gleam_stdlib:classify_dynamic(Data), + []}]} + end, + push_path(_pipe, [Key]) + end, + {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), + {Out@1, lists:append(Errors1, Errors2)} + end}. + +-file("src/gleam/dynamic/decode.gleam", 598). +?DOC( + " A decoder that decodes a value that is nested within other values. For\n" + " example, decoding a value that is within some deeply nested JSON objects.\n" + "\n" + " This function will index into dictionaries with any key type, and if the key is\n" + " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" + " the first eight elements of Gleam lists.\n" + "\n" + " # Examples\n" + "\n" + " ```gleam\n" + " let decoder = decode.optionally_at([\"one\", \"two\"], 100, decode.int)\n" + "\n" + " let data = dynamic.from(dict.from_list([\n" + " #(\"one\", dict.from_list([])),\n" + " ]))\n" + "\n" + "\n" + " decode.run(data, decoder)\n" + " // -> Ok(100)\n" + " ```\n" +). +-spec optionally_at(list(any()), BZN, decoder(BZN)) -> decoder(BZN). +optionally_at(Path, Default, Inner) -> + {decoder, + fun(Data) -> + index( + Path, + [], + erlang:element(2, Inner), + Data, + fun(_, _) -> {Default, []} end + ) + end}. diff --git a/build/packages/gleam_stdlib/src/gleam@float.erl b/build/packages/gleam_stdlib/src/gleam@float.erl new file mode 100644 index 0000000..e893b8e --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@float.erl @@ -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: \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). diff --git a/build/packages/gleam_stdlib/src/gleam@function.erl b/build/packages/gleam_stdlib/src/gleam@function.erl new file mode 100644 index 0000000..c1e8b5a --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@function.erl @@ -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. diff --git a/build/packages/gleam_stdlib/src/gleam@int.erl b/build/packages/gleam_stdlib/src/gleam@int.erl new file mode 100644 index 0000000..b9f71b2 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@int.erl @@ -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). diff --git a/build/packages/gleam_stdlib/src/gleam@io.erl b/build/packages/gleam_stdlib/src/gleam@io.erl new file mode 100644 index 0000000..a21232e --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@io.erl @@ -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). diff --git a/build/packages/gleam_stdlib/src/gleam@list.erl b/build/packages/gleam_stdlib/src/gleam@list.erl new file mode 100644 index 0000000..f266a06 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@list.erl @@ -0,0 +1,2860 @@ +-module(gleam@list). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleam/list.gleam"). +-export([length/1, count/2, reverse/1, is_empty/1, contains/2, first/1, rest/1, group/2, filter/2, filter_map/2, map/2, map2/3, map_fold/3, index_map/2, try_map/2, drop/2, take/2, new/0, wrap/1, append/2, prepend/2, flatten/1, flat_map/2, fold/3, fold_right/3, index_fold/3, try_fold/3, fold_until/3, find/2, find_map/2, all/2, any/2, zip/2, strict_zip/2, unzip/1, intersperse/2, unique/1, sort/2, range/2, repeat/2, split/2, split_while/2, key_find/2, key_filter/2, key_pop/2, key_set/3, each/2, try_each/2, partition/2, permutations/1, window/2, window_by_2/1, drop_while/2, take_while/2, chunk/2, sized_chunk/2, reduce/2, scan/3, last/1, combinations/2, combination_pairs/1, transpose/1, interleave/1, shuffle/1, max/2, sample/2]). +-export_type([continue_or_stop/1, sorting/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( + " Lists are an ordered sequence of elements and are one of the most common\n" + " data types in Gleam.\n" + "\n" + " New elements can be added and removed from the front of a list in\n" + " constant time, while adding and removing from the end requires traversing\n" + " and copying the whole list, so keep this in mind when designing your\n" + " programs.\n" + "\n" + " There is a dedicated syntax for prefixing to a list:\n" + "\n" + " ```gleam\n" + " let new_list = [1, 2, ..existing_list]\n" + " ```\n" + "\n" + " And a matching syntax for getting the first elements of a list:\n" + "\n" + " ```gleam\n" + " case list {\n" + " [first_element, ..rest] -> first_element\n" + " _ -> \"this pattern matches when the list is empty\"\n" + " }\n" + " ```\n" + "\n" +). + +-type continue_or_stop(YG) :: {continue, YG} | {stop, YG}. + +-type sorting() :: ascending | descending. + +-file("src/gleam/list.gleam", 60). +-spec length_loop(list(any()), integer()) -> integer(). +length_loop(List, Count) -> + case List of + [_ | List@1] -> + length_loop(List@1, Count + 1); + + [] -> + Count + end. + +-file("src/gleam/list.gleam", 56). +?DOC( + " Counts the number of elements in a given list.\n" + "\n" + " This function has to traverse the list to determine the number of elements,\n" + " so it runs in linear time.\n" + "\n" + " This function is natively implemented by the virtual machine and is highly\n" + " optimised.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " length([])\n" + " // -> 0\n" + " ```\n" + "\n" + " ```gleam\n" + " length([1])\n" + " // -> 1\n" + " ```\n" + "\n" + " ```gleam\n" + " length([1, 2])\n" + " // -> 2\n" + " ```\n" +). +-spec length(list(any())) -> integer(). +length(List) -> + erlang:length(List). + +-file("src/gleam/list.gleam", 93). +-spec count_loop(list(YN), fun((YN) -> boolean()), integer()) -> integer(). +count_loop(List, Predicate, Acc) -> + case List of + [] -> + Acc; + + [First | Rest] -> + case Predicate(First) of + true -> + count_loop(Rest, Predicate, Acc + 1); + + false -> + count_loop(Rest, Predicate, Acc) + end + end. + +-file("src/gleam/list.gleam", 89). +?DOC( + " Counts the number of elements in a given list satisfying a given predicate.\n" + "\n" + " This function has to traverse the list to determine the number of elements,\n" + " so it runs in linear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " count([], fn(a) { a > 0 })\n" + " // -> 0\n" + " ```\n" + "\n" + " ```gleam\n" + " count([1], fn(a) { a > 0 })\n" + " // -> 1\n" + " ```\n" + "\n" + " ```gleam\n" + " count([1, 2, 3], int.is_odd)\n" + " // -> 2\n" + " ```\n" +). +-spec count(list(YL), fun((YL) -> boolean())) -> integer(). +count(List, Predicate) -> + count_loop(List, Predicate, 0). + +-file("src/gleam/list.gleam", 139). +?DOC( + " Reverses a list and prepends it to another list.\n" + " This function runs in linear time, proportional to the length of the list\n" + " to prepend.\n" +). +-spec reverse_and_prepend(list(YS), list(YS)) -> list(YS). +reverse_and_prepend(Prefix, Suffix) -> + case Prefix of + [] -> + Suffix; + + [First | Rest] -> + reverse_and_prepend(Rest, [First | Suffix]) + end. + +-file("src/gleam/list.gleam", 131). +?DOC( + " Creates a new list from a given list containing the same elements but in the\n" + " opposite order.\n" + "\n" + " This function has to traverse the list to create the new reversed list, so\n" + " it runs in linear time.\n" + "\n" + " This function is natively implemented by the virtual machine and is highly\n" + " optimised.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " reverse([])\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " reverse([1])\n" + " // -> [1]\n" + " ```\n" + "\n" + " ```gleam\n" + " reverse([1, 2])\n" + " // -> [2, 1]\n" + " ```\n" +). +-spec reverse(list(YP)) -> list(YP). +reverse(List) -> + lists:reverse(List). + +-file("src/gleam/list.gleam", 167). +?DOC( + " Determines whether or not the list is empty.\n" + "\n" + " This function runs in constant time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " is_empty([])\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " is_empty([1])\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " is_empty([1, 1])\n" + " // -> False\n" + " ```\n" +). +-spec is_empty(list(any())) -> boolean(). +is_empty(List) -> + List =:= []. + +-file("src/gleam/list.gleam", 203). +?DOC( + " Determines whether or not a given element exists within a given list.\n" + "\n" + " This function traverses the list to find the element, so it runs in linear\n" + " time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [] |> contains(any: 0)\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " [0] |> contains(any: 0)\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " [1] |> contains(any: 0)\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 1] |> contains(any: 0)\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 0] |> contains(any: 0)\n" + " // -> True\n" + " ```\n" +). +-spec contains(list(YY), YY) -> boolean(). +contains(List, Elem) -> + case List of + [] -> + false; + + [First | _] when First =:= Elem -> + true; + + [_ | Rest] -> + contains(Rest, Elem) + end. + +-file("src/gleam/list.gleam", 230). +?DOC( + " Gets the first element from the start of the list, if there is one.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " first([])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " first([0])\n" + " // -> Ok(0)\n" + " ```\n" + "\n" + " ```gleam\n" + " first([1, 2])\n" + " // -> Ok(1)\n" + " ```\n" +). +-spec first(list(AAA)) -> {ok, AAA} | {error, nil}. +first(List) -> + case List of + [] -> + {error, nil}; + + [First | _] -> + {ok, First} + end. + +-file("src/gleam/list.gleam", 259). +?DOC( + " Returns the list minus the first element. If the list is empty, `Error(Nil)` is\n" + " returned.\n" + "\n" + " This function runs in constant time and does not make a copy of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " rest([])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " rest([0])\n" + " // -> Ok([])\n" + " ```\n" + "\n" + " ```gleam\n" + " rest([1, 2])\n" + " // -> Ok([2])\n" + " ```\n" +). +-spec rest(list(AAE)) -> {ok, list(AAE)} | {error, nil}. +rest(List) -> + case List of + [] -> + {error, nil}; + + [_ | Rest] -> + {ok, Rest} + end. + +-file("src/gleam/list.gleam", 301). +-spec group_loop(list(AAP), fun((AAP) -> AAR), gleam@dict:dict(AAR, list(AAP))) -> gleam@dict:dict(AAR, list(AAP)). +group_loop(List, To_key, Groups) -> + case List of + [] -> + Groups; + + [First | Rest] -> + Key = To_key(First), + Groups@1 = case gleam_stdlib:map_get(Groups, Key) of + {error, _} -> + gleam@dict:insert(Groups, Key, [First]); + + {ok, Existing} -> + gleam@dict:insert(Groups, Key, [First | Existing]) + end, + group_loop(Rest, To_key, Groups@1) + end. + +-file("src/gleam/list.gleam", 297). +?DOC( + " Groups the elements from the given list by the given key function.\n" + "\n" + " Does not preserve the initial value order.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " import gleam/dict\n" + "\n" + " [Ok(3), Error(\"Wrong\"), Ok(200), Ok(73)]\n" + " |> group(by: fn(i) {\n" + " case i {\n" + " Ok(_) -> \"Successful\"\n" + " Error(_) -> \"Failed\"\n" + " }\n" + " })\n" + " |> dict.to_list\n" + " // -> [\n" + " // #(\"Failed\", [Error(\"Wrong\")]),\n" + " // #(\"Successful\", [Ok(73), Ok(200), Ok(3)])\n" + " // ]\n" + " ```\n" + "\n" + " ```gleam\n" + " import gleam/dict\n" + "\n" + " group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 })\n" + " |> dict.to_list\n" + " // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])]\n" + " ```\n" +). +-spec group(list(AAJ), fun((AAJ) -> AAL)) -> gleam@dict:dict(AAL, list(AAJ)). +group(List, Key) -> + group_loop(List, Key, maps:new()). + +-file("src/gleam/list.gleam", 338). +-spec filter_loop(list(ABB), fun((ABB) -> boolean()), list(ABB)) -> list(ABB). +filter_loop(List, Fun, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + New_acc = case Fun(First) of + true -> + [First | Acc]; + + false -> + Acc + end, + filter_loop(Rest, Fun, New_acc) + end. + +-file("src/gleam/list.gleam", 334). +?DOC( + " Returns a new list containing only the elements from the first list for\n" + " which the given functions returns `True`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " filter([2, 4, 6, 1], fn(x) { x > 2 })\n" + " // -> [4, 6]\n" + " ```\n" + "\n" + " ```gleam\n" + " filter([2, 4, 6, 1], fn(x) { x > 6 })\n" + " // -> []\n" + " ```\n" +). +-spec filter(list(AAY), fun((AAY) -> boolean())) -> list(AAY). +filter(List, Predicate) -> + filter_loop(List, Predicate, []). + +-file("src/gleam/list.gleam", 370). +-spec filter_map_loop( + list(ABM), + fun((ABM) -> {ok, ABO} | {error, any()}), + list(ABO) +) -> list(ABO). +filter_map_loop(List, Fun, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + New_acc = case Fun(First) of + {ok, First@1} -> + [First@1 | Acc]; + + {error, _} -> + Acc + end, + filter_map_loop(Rest, Fun, New_acc) + end. + +-file("src/gleam/list.gleam", 366). +?DOC( + " Returns a new list containing only the elements from the first list for\n" + " which the given functions returns `Ok(_)`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " filter_map([2, 4, 6, 1], Error)\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) })\n" + " // -> [3, 5, 7, 2]\n" + " ```\n" +). +-spec filter_map(list(ABF), fun((ABF) -> {ok, ABH} | {error, any()})) -> list(ABH). +filter_map(List, Fun) -> + filter_map_loop(List, Fun, []). + +-file("src/gleam/list.gleam", 401). +-spec map_loop(list(ABY), fun((ABY) -> ACA), list(ACA)) -> list(ACA). +map_loop(List, Fun, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + map_loop(Rest, Fun, [Fun(First) | Acc]) + end. + +-file("src/gleam/list.gleam", 397). +?DOC( + " Returns a new list containing only the elements of the first list after the\n" + " function has been applied to each one.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " map([2, 4, 6], fn(x) { x * 2 })\n" + " // -> [4, 8, 12]\n" + " ```\n" +). +-spec map(list(ABU), fun((ABU) -> ABW)) -> list(ABW). +map(List, Fun) -> + map_loop(List, Fun, []). + +-file("src/gleam/list.gleam", 428). +-spec map2_loop(list(ACJ), list(ACL), fun((ACJ, ACL) -> ACN), list(ACN)) -> list(ACN). +map2_loop(List1, List2, Fun, Acc) -> + case {List1, List2} of + {[], _} -> + lists:reverse(Acc); + + {_, []} -> + lists:reverse(Acc); + + {[A | As_], [B | Bs]} -> + map2_loop(As_, Bs, Fun, [Fun(A, B) | Acc]) + end. + +-file("src/gleam/list.gleam", 424). +?DOC( + " Combines two lists into a single list using the given function.\n" + "\n" + " If a list is longer than the other the extra elements are dropped.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y })\n" + " // -> [5, 7, 9]\n" + " ```\n" + "\n" + " ```gleam\n" + " map2([1, 2], [\"a\", \"b\", \"c\"], fn(i, x) { #(i, x) })\n" + " // -> [#(1, \"a\"), #(2, \"b\")]\n" + " ```\n" +). +-spec map2(list(ACD), list(ACF), fun((ACD, ACF) -> ACH)) -> list(ACH). +map2(List1, List2, Fun) -> + map2_loop(List1, List2, Fun, []). + +-file("src/gleam/list.gleam", 461). +-spec map_fold_loop(list(ACV), fun((ACX, ACV) -> {ACX, ACY}), ACX, list(ACY)) -> {ACX, + list(ACY)}. +map_fold_loop(List, Fun, Acc, List_acc) -> + case List of + [] -> + {Acc, lists:reverse(List_acc)}; + + [First | Rest] -> + {Acc@1, First@1} = Fun(Acc, First), + map_fold_loop(Rest, Fun, Acc@1, [First@1 | List_acc]) + end. + +-file("src/gleam/list.gleam", 453). +?DOC( + " Similar to `map` but also lets you pass around an accumulated value.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " map_fold(\n" + " over: [1, 2, 3],\n" + " from: 100,\n" + " with: fn(memo, i) { #(memo + i, i * 2) }\n" + " )\n" + " // -> #(106, [2, 4, 6])\n" + " ```\n" +). +-spec map_fold(list(ACQ), ACS, fun((ACS, ACQ) -> {ACS, ACT})) -> {ACS, + list(ACT)}. +map_fold(List, Initial, Fun) -> + map_fold_loop(List, Fun, Initial, []). + +-file("src/gleam/list.gleam", 493). +-spec index_map_loop( + list(ADF), + fun((ADF, integer()) -> ADH), + integer(), + list(ADH) +) -> list(ADH). +index_map_loop(List, Fun, Index, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + Acc@1 = [Fun(First, Index) | Acc], + index_map_loop(Rest, Fun, Index + 1, Acc@1) + end. + +-file("src/gleam/list.gleam", 489). +?DOC( + " Returns a new list containing only the elements of the first list after the\n" + " function has been applied to each one and their index.\n" + "\n" + " The index starts at 0, so the first element is 0, the second is 1, and so\n" + " on.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " index_map([\"a\", \"b\"], fn(x, i) { #(i, x) })\n" + " // -> [#(0, \"a\"), #(1, \"b\")]\n" + " ```\n" +). +-spec index_map(list(ADB), fun((ADB, integer()) -> ADD)) -> list(ADD). +index_map(List, Fun) -> + index_map_loop(List, Fun, 0, []). + +-file("src/gleam/list.gleam", 547). +-spec try_map_loop(list(ADT), fun((ADT) -> {ok, ADV} | {error, ADW}), list(ADV)) -> {ok, + list(ADV)} | + {error, ADW}. +try_map_loop(List, Fun, Acc) -> + case List of + [] -> + {ok, lists:reverse(Acc)}; + + [First | Rest] -> + case Fun(First) of + {ok, First@1} -> + try_map_loop(Rest, Fun, [First@1 | Acc]); + + {error, Error} -> + {error, Error} + end + end. + +-file("src/gleam/list.gleam", 540). +?DOC( + " Takes a function that returns a `Result` and applies it to each element in a\n" + " given list in turn.\n" + "\n" + " If the function returns `Ok(new_value)` for all elements in the list then a\n" + " list of the new values is returned.\n" + "\n" + " If the function returns `Error(reason)` for any of the elements then it is\n" + " returned immediately. None of the elements in the list are processed after\n" + " one returns an `Error`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " try_map([1, 2, 3], fn(x) { Ok(x + 2) })\n" + " // -> Ok([3, 4, 5])\n" + " ```\n" + "\n" + " ```gleam\n" + " try_map([1, 2, 3], fn(_) { Error(0) })\n" + " // -> Error(0)\n" + " ```\n" + "\n" + " ```gleam\n" + " try_map([[1], [2, 3]], first)\n" + " // -> Ok([1, 2])\n" + " ```\n" + "\n" + " ```gleam\n" + " try_map([[1], [], [2]], first)\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec try_map(list(ADK), fun((ADK) -> {ok, ADM} | {error, ADN})) -> {ok, + list(ADM)} | + {error, ADN}. +try_map(List, Fun) -> + try_map_loop(List, Fun, []). + +-file("src/gleam/list.gleam", 582). +?DOC( + " Returns a list that is the given list with up to the given number of\n" + " elements removed from the front of the list.\n" + "\n" + " If the element has less than the number of elements an empty list is\n" + " returned.\n" + "\n" + " This function runs in linear time but does not copy the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " drop([1, 2, 3, 4], 2)\n" + " // -> [3, 4]\n" + " ```\n" + "\n" + " ```gleam\n" + " drop([1, 2, 3, 4], 9)\n" + " // -> []\n" + " ```\n" +). +-spec drop(list(AED), integer()) -> list(AED). +drop(List, N) -> + case N =< 0 of + true -> + List; + + false -> + case List of + [] -> + []; + + [_ | Rest] -> + drop(Rest, N - 1) + end + end. + +-file("src/gleam/list.gleam", 617). +-spec take_loop(list(AEJ), integer(), list(AEJ)) -> list(AEJ). +take_loop(List, N, Acc) -> + case N =< 0 of + true -> + lists:reverse(Acc); + + false -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + take_loop(Rest, N - 1, [First | Acc]) + end + end. + +-file("src/gleam/list.gleam", 613). +?DOC( + " Returns a list containing the first given number of elements from the given\n" + " list.\n" + "\n" + " If the element has less than the number of elements then the full list is\n" + " returned.\n" + "\n" + " This function runs in linear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " take([1, 2, 3, 4], 2)\n" + " // -> [1, 2]\n" + " ```\n" + "\n" + " ```gleam\n" + " take([1, 2, 3, 4], 9)\n" + " // -> [1, 2, 3, 4]\n" + " ```\n" +). +-spec take(list(AEG), integer()) -> list(AEG). +take(List, N) -> + take_loop(List, N, []). + +-file("src/gleam/list.gleam", 637). +?DOC( + " Returns a new empty list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " new()\n" + " // -> []\n" + " ```\n" +). +-spec new() -> list(any()). +new() -> + []. + +-file("src/gleam/list.gleam", 657). +?DOC( + " Returns the given item wrapped in a list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " wrap(1)\n" + " // -> [1]\n" + "\n" + " wrap([\"a\", \"b\", \"c\"])\n" + " // -> [[\"a\", \"b\", \"c\"]]\n" + "\n" + " wrap([[]])\n" + " // -> [[[]]]\n" + " ```\n" +). +-spec wrap(AEP) -> list(AEP). +wrap(Item) -> + [Item]. + +-file("src/gleam/list.gleam", 678). +-spec append_loop(list(AEV), list(AEV)) -> list(AEV). +append_loop(First, Second) -> + case First of + [] -> + Second; + + [First@1 | Rest] -> + append_loop(Rest, [First@1 | Second]) + end. + +-file("src/gleam/list.gleam", 674). +?DOC( + " Joins one list onto the end of another.\n" + "\n" + " This function runs in linear time, and it traverses and copies the first\n" + " list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " append([1, 2], [3])\n" + " // -> [1, 2, 3]\n" + " ```\n" +). +-spec append(list(AER), list(AER)) -> list(AER). +append(First, Second) -> + lists:append(First, Second). + +-file("src/gleam/list.gleam", 698). +?DOC( + " Prefixes an item to a list. This can also be done using the dedicated\n" + " syntax instead\n" + "\n" + " ```gleam\n" + " let existing_list = [2, 3, 4]\n" + "\n" + " [1, ..existing_list]\n" + " // -> [1, 2, 3, 4]\n" + "\n" + " prepend(to: existing_list, this: 1)\n" + " // -> [1, 2, 3, 4]\n" + " ```\n" +). +-spec prepend(list(AEZ), AEZ) -> list(AEZ). +prepend(List, Item) -> + [Item | List]. + +-file("src/gleam/list.gleam", 719). +-spec flatten_loop(list(list(AFG)), list(AFG)) -> list(AFG). +flatten_loop(Lists, Acc) -> + case Lists of + [] -> + lists:reverse(Acc); + + [List | Further_lists] -> + flatten_loop(Further_lists, reverse_and_prepend(List, Acc)) + end. + +-file("src/gleam/list.gleam", 715). +?DOC( + " Joins a list of lists into a single list.\n" + "\n" + " This function traverses all elements twice on the JavaScript target.\n" + " This function traverses all elements once on the Erlang target.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " flatten([[1], [2, 3], []])\n" + " // -> [1, 2, 3]\n" + " ```\n" +). +-spec flatten(list(list(AFC))) -> list(AFC). +flatten(Lists) -> + lists:append(Lists). + +-file("src/gleam/list.gleam", 736). +?DOC( + " Maps the list with the given function into a list of lists, and then flattens it.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " flat_map([2, 4, 6], fn(x) { [x, x + 1] })\n" + " // -> [2, 3, 4, 5, 6, 7]\n" + " ```\n" +). +-spec flat_map(list(AFL), fun((AFL) -> list(AFN))) -> list(AFN). +flat_map(List, Fun) -> + lists:append(map(List, Fun)). + +-file("src/gleam/list.gleam", 748). +?DOC( + " Reduces a list of elements into a single value by calling a given function\n" + " on each element, going from left to right.\n" + "\n" + " `fold([1, 2, 3], 0, add)` is the equivalent of\n" + " `add(add(add(0, 1), 2), 3)`.\n" + "\n" + " This function runs in linear time.\n" +). +-spec fold(list(AFQ), AFS, fun((AFS, AFQ) -> AFS)) -> AFS. +fold(List, Initial, Fun) -> + case List of + [] -> + Initial; + + [First | Rest] -> + fold(Rest, Fun(Initial, First), Fun) + end. + +-file("src/gleam/list.gleam", 770). +?DOC( + " Reduces a list of elements into a single value by calling a given function\n" + " on each element, going from right to left.\n" + "\n" + " `fold_right([1, 2, 3], 0, add)` is the equivalent of\n" + " `add(add(add(0, 3), 2), 1)`.\n" + "\n" + " This function runs in linear time.\n" + "\n" + " Unlike `fold` this function is not tail recursive. Where possible use\n" + " `fold` instead as it will use less memory.\n" +). +-spec fold_right(list(AFT), AFV, fun((AFV, AFT) -> AFV)) -> AFV. +fold_right(List, Initial, Fun) -> + case List of + [] -> + Initial; + + [First | Rest] -> + Fun(fold_right(Rest, Initial, Fun), First) + end. + +-file("src/gleam/list.gleam", 798). +-spec index_fold_loop( + list(AFZ), + AGB, + fun((AGB, AFZ, integer()) -> AGB), + integer() +) -> AGB. +index_fold_loop(Over, Acc, With, Index) -> + case Over of + [] -> + Acc; + + [First | Rest] -> + index_fold_loop(Rest, With(Acc, First, Index), With, Index + 1) + end. + +-file("src/gleam/list.gleam", 790). +?DOC( + " Like fold but the folding function also receives the index of the current element.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [\"a\", \"b\", \"c\"]\n" + " |> index_fold([], fn(acc, item, index) { ... })\n" + " ```\n" +). +-spec index_fold(list(AFW), AFY, fun((AFY, AFW, integer()) -> AFY)) -> AFY. +index_fold(List, Initial, Fun) -> + index_fold_loop(List, Initial, Fun, 0). + +-file("src/gleam/list.gleam", 830). +?DOC( + " A variant of fold that might fail.\n" + "\n" + " The folding function should return `Result(accumulator, error)`.\n" + " If the returned value is `Ok(accumulator)` try_fold will try the next value in the list.\n" + " If the returned value is `Error(error)` try_fold will stop and return that error.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4]\n" + " |> try_fold(0, fn(acc, i) {\n" + " case i < 3 {\n" + " True -> Ok(acc + i)\n" + " False -> Error(Nil)\n" + " }\n" + " })\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec try_fold(list(AGC), AGE, fun((AGE, AGC) -> {ok, AGE} | {error, AGF})) -> {ok, + AGE} | + {error, AGF}. +try_fold(List, Initial, Fun) -> + case List of + [] -> + {ok, Initial}; + + [First | Rest] -> + case Fun(Initial, First) of + {ok, Result} -> + try_fold(Rest, Result, Fun); + + {error, _} = Error -> + Error + end + end. + +-file("src/gleam/list.gleam", 869). +?DOC( + " A variant of fold that allows to stop folding earlier.\n" + "\n" + " The folding function should return `ContinueOrStop(accumulator)`.\n" + " If the returned value is `Continue(accumulator)` fold_until will try the next value in the list.\n" + " If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4]\n" + " |> fold_until(0, fn(acc, i) {\n" + " case i < 3 {\n" + " True -> Continue(acc + i)\n" + " False -> Stop(acc)\n" + " }\n" + " })\n" + " // -> 3\n" + " ```\n" +). +-spec fold_until(list(AGK), AGM, fun((AGM, AGK) -> continue_or_stop(AGM))) -> AGM. +fold_until(List, Initial, Fun) -> + case List of + [] -> + Initial; + + [First | Rest] -> + case Fun(Initial, First) of + {continue, Next_accumulator} -> + fold_until(Rest, Next_accumulator, Fun); + + {stop, B} -> + B + end + end. + +-file("src/gleam/list.gleam", 906). +?DOC( + " Finds the first element in a given list for which the given function returns\n" + " `True`.\n" + "\n" + " Returns `Error(Nil)` if no such element is found.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " find([1, 2, 3], fn(x) { x > 2 })\n" + " // -> Ok(3)\n" + " ```\n" + "\n" + " ```gleam\n" + " find([1, 2, 3], fn(x) { x > 4 })\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " find([], fn(_) { True })\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec find(list(AGO), fun((AGO) -> boolean())) -> {ok, AGO} | {error, nil}. +find(List, Is_desired) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + case Is_desired(First) of + true -> + {ok, First}; + + false -> + find(Rest, Is_desired) + end + end. + +-file("src/gleam/list.gleam", 942). +?DOC( + " Finds the first element in a given list for which the given function returns\n" + " `Ok(new_value)`, then returns the wrapped `new_value`.\n" + "\n" + " Returns `Error(Nil)` if no such element is found.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " find_map([[], [2], [3]], first)\n" + " // -> Ok(2)\n" + " ```\n" + "\n" + " ```gleam\n" + " find_map([[], []], first)\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " find_map([], first)\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec find_map(list(AGS), fun((AGS) -> {ok, AGU} | {error, any()})) -> {ok, AGU} | + {error, nil}. +find_map(List, Fun) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + case Fun(First) of + {ok, First@1} -> + {ok, First@1}; + + {error, _} -> + find_map(Rest, Fun) + end + end. + +-file("src/gleam/list.gleam", 977). +?DOC( + " Returns `True` if the given function returns `True` for all the elements in\n" + " the given list. If the function returns `False` for any of the elements it\n" + " immediately returns `False` without checking the rest of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " all([], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " all([4, 5], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " all([4, 3], fn(x) { x > 3 })\n" + " // -> False\n" + " ```\n" +). +-spec all(list(AHA), fun((AHA) -> boolean())) -> boolean(). +all(List, Predicate) -> + case List of + [] -> + true; + + [First | Rest] -> + case Predicate(First) of + true -> + all(Rest, Predicate); + + false -> + false + end + end. + +-file("src/gleam/list.gleam", 1014). +?DOC( + " Returns `True` if the given function returns `True` for any the elements in\n" + " the given list. If the function returns `True` for any of the elements it\n" + " immediately returns `True` without checking the rest of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " any([], fn(x) { x > 3 })\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " any([4, 5], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" + "\n" + " ```gleam\n" + " any([4, 3], fn(x) { x > 4 })\n" + " // -> False\n" + " ```\n" + "\n" + " ```gleam\n" + " any([3, 4], fn(x) { x > 3 })\n" + " // -> True\n" + " ```\n" +). +-spec any(list(AHC), fun((AHC) -> boolean())) -> boolean(). +any(List, Predicate) -> + case List of + [] -> + false; + + [First | Rest] -> + case Predicate(First) of + true -> + true; + + false -> + any(Rest, Predicate) + end + end. + +-file("src/gleam/list.gleam", 1056). +-spec zip_loop(list(AHJ), list(AHL), list({AHJ, AHL})) -> list({AHJ, AHL}). +zip_loop(One, Other, Acc) -> + case {One, Other} of + {[First_one | Rest_one], [First_other | Rest_other]} -> + zip_loop(Rest_one, Rest_other, [{First_one, First_other} | Acc]); + + {_, _} -> + lists:reverse(Acc) + end. + +-file("src/gleam/list.gleam", 1052). +?DOC( + " Takes two lists and returns a single list of 2-element tuples.\n" + "\n" + " If one of the lists is longer than the other, the remaining elements from\n" + " the longer list are not used.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " zip([], [])\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " zip([1, 2], [3])\n" + " // -> [#(1, 3)]\n" + " ```\n" + "\n" + " ```gleam\n" + " zip([1], [3, 4])\n" + " // -> [#(1, 3)]\n" + " ```\n" + "\n" + " ```gleam\n" + " zip([1, 2], [3, 4])\n" + " // -> [#(1, 3), #(2, 4)]\n" + " ```\n" +). +-spec zip(list(AHE), list(AHG)) -> list({AHE, AHG}). +zip(List, Other) -> + zip_loop(List, Other, []). + +-file("src/gleam/list.gleam", 1097). +-spec strict_zip_loop(list(AHW), list(AHY), list({AHW, AHY})) -> {ok, + list({AHW, AHY})} | + {error, nil}. +strict_zip_loop(One, Other, Acc) -> + case {One, Other} of + {[], []} -> + {ok, lists:reverse(Acc)}; + + {[], _} -> + {error, nil}; + + {_, []} -> + {error, nil}; + + {[First_one | Rest_one], [First_other | Rest_other]} -> + strict_zip_loop( + Rest_one, + Rest_other, + [{First_one, First_other} | Acc] + ) + end. + +-file("src/gleam/list.gleam", 1090). +?DOC( + " Takes two lists and returns a single list of 2-element tuples.\n" + "\n" + " If one of the lists is longer than the other, an `Error` is returned.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " strict_zip([], [])\n" + " // -> Ok([])\n" + " ```\n" + "\n" + " ```gleam\n" + " strict_zip([1, 2], [3])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " strict_zip([1], [3, 4])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " strict_zip([1, 2], [3, 4])\n" + " // -> Ok([#(1, 3), #(2, 4)])\n" + " ```\n" +). +-spec strict_zip(list(AHP), list(AHR)) -> {ok, list({AHP, AHR})} | {error, nil}. +strict_zip(List, Other) -> + strict_zip_loop(List, Other, []). + +-file("src/gleam/list.gleam", 1128). +-spec unzip_loop(list({AIJ, AIK}), list(AIJ), list(AIK)) -> {list(AIJ), + list(AIK)}. +unzip_loop(Input, One, Other) -> + case Input of + [] -> + {lists:reverse(One), lists:reverse(Other)}; + + [{First_one, First_other} | Rest] -> + unzip_loop(Rest, [First_one | One], [First_other | Other]) + end. + +-file("src/gleam/list.gleam", 1124). +?DOC( + " Takes a single list of 2-element tuples and returns two lists.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " unzip([#(1, 2), #(3, 4)])\n" + " // -> #([1, 3], [2, 4])\n" + " ```\n" + "\n" + " ```gleam\n" + " unzip([])\n" + " // -> #([], [])\n" + " ```\n" +). +-spec unzip(list({AIE, AIF})) -> {list(AIE), list(AIF)}. +unzip(Input) -> + unzip_loop(Input, [], []). + +-file("src/gleam/list.gleam", 1163). +-spec intersperse_loop(list(AIT), AIT, list(AIT)) -> list(AIT). +intersperse_loop(List, Separator, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + intersperse_loop(Rest, Separator, [First, Separator | Acc]) + end. + +-file("src/gleam/list.gleam", 1156). +?DOC( + " Inserts a given value between each existing element in a given list.\n" + "\n" + " This function runs in linear time and copies the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " intersperse([1, 1, 1], 2)\n" + " // -> [1, 2, 1, 2, 1]\n" + " ```\n" + "\n" + " ```gleam\n" + " intersperse([], 2)\n" + " // -> []\n" + " ```\n" +). +-spec intersperse(list(AIQ), AIQ) -> list(AIQ). +intersperse(List, Elem) -> + case List of + [] -> + List; + + [_] -> + List; + + [First | Rest] -> + intersperse_loop(Rest, Elem, [First]) + end. + +-file("src/gleam/list.gleam", 1186). +-spec unique_loop(list(AJA), gleam@dict:dict(AJA, nil), list(AJA)) -> list(AJA). +unique_loop(List, Seen, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + case gleam@dict:has_key(Seen, First) of + true -> + unique_loop(Rest, Seen, Acc); + + false -> + unique_loop( + Rest, + gleam@dict:insert(Seen, First, nil), + [First | Acc] + ) + end + end. + +-file("src/gleam/list.gleam", 1182). +?DOC( + " Removes any duplicate elements from a given list.\n" + "\n" + " This function returns in loglinear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " unique([1, 1, 1, 4, 7, 3, 3, 4])\n" + " // -> [1, 4, 7, 3]\n" + " ```\n" +). +-spec unique(list(AIX)) -> list(AIX). +unique(List) -> + unique_loop(List, maps:new(), []). + +-file("src/gleam/list.gleam", 1272). +?DOC( + " Given a list it returns slices of it that are locally sorted in ascending\n" + " order.\n" + "\n" + " Imagine you have this list:\n" + "\n" + " ```\n" + " [1, 2, 3, 2, 1, 0]\n" + " ^^^^^^^ ^^^^^^^ This is a slice in descending order\n" + " |\n" + " | This is a slice that is sorted in ascending order\n" + " ```\n" + "\n" + " So the produced result will contain these two slices, each one sorted in\n" + " ascending order: `[[1, 2, 3], [0, 1, 2]]`.\n" + "\n" + " - `growing` is an accumulator with the current slice being grown\n" + " - `direction` is the growing direction of the slice being grown, it could\n" + " either be ascending or strictly descending\n" + " - `prev` is the previous element that needs to be added to the growing slice\n" + " it is carried around to check whether we have to keep growing the current\n" + " slice or not\n" + " - `acc` is the accumulator containing the slices sorted in ascending order\n" +). +-spec sequences( + list(AJJ), + fun((AJJ, AJJ) -> gleam@order:order()), + list(AJJ), + sorting(), + AJJ, + list(list(AJJ)) +) -> list(list(AJJ)). +sequences(List, Compare, Growing, Direction, Prev, Acc) -> + Growing@1 = [Prev | Growing], + case List of + [] -> + case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end; + + [New | Rest] -> + case {Compare(Prev, New), Direction} of + {gt, descending} -> + sequences(Rest, Compare, Growing@1, Direction, New, Acc); + + {lt, ascending} -> + sequences(Rest, Compare, Growing@1, Direction, New, Acc); + + {eq, ascending} -> + sequences(Rest, Compare, Growing@1, Direction, New, Acc); + + {gt, ascending} -> + Acc@1 = case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end, + case Rest of + [] -> + [[New] | Acc@1]; + + [Next | Rest@1] -> + Direction@1 = case Compare(New, Next) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + sequences( + Rest@1, + Compare, + [New], + Direction@1, + Next, + Acc@1 + ) + end; + + {lt, descending} -> + Acc@1 = case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end, + case Rest of + [] -> + [[New] | Acc@1]; + + [Next | Rest@1] -> + Direction@1 = case Compare(New, Next) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + sequences( + Rest@1, + Compare, + [New], + Direction@1, + Next, + Acc@1 + ) + end; + + {eq, descending} -> + Acc@1 = case Direction of + ascending -> + [lists:reverse(Growing@1) | Acc]; + + descending -> + [Growing@1 | Acc] + end, + case Rest of + [] -> + [[New] | Acc@1]; + + [Next | Rest@1] -> + Direction@1 = case Compare(New, Next) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + sequences( + Rest@1, + Compare, + [New], + Direction@1, + Next, + Acc@1 + ) + end + end + end. + +-file("src/gleam/list.gleam", 1420). +?DOC( + " Merges two lists sorted in ascending order into a single list sorted in\n" + " descending order according to the given comparator function.\n" + "\n" + " This reversing of the sort order is not avoidable if we want to implement\n" + " merge as a tail recursive function. We could reverse the accumulator before\n" + " returning it but that would end up being less efficient; so the merging\n" + " algorithm has to play around this.\n" +). +-spec merge_ascendings( + list(AKG), + list(AKG), + fun((AKG, AKG) -> gleam@order:order()), + list(AKG) +) -> list(AKG). +merge_ascendings(List1, List2, Compare, Acc) -> + case {List1, List2} of + {[], List} -> + reverse_and_prepend(List, Acc); + + {List, []} -> + reverse_and_prepend(List, Acc); + + {[First1 | Rest1], [First2 | Rest2]} -> + case Compare(First1, First2) of + lt -> + merge_ascendings(Rest1, List2, Compare, [First1 | Acc]); + + gt -> + merge_ascendings(List1, Rest2, Compare, [First2 | Acc]); + + eq -> + merge_ascendings(List1, Rest2, Compare, [First2 | Acc]) + end + end. + +-file("src/gleam/list.gleam", 1373). +?DOC( + " Given a list of ascending lists, it merges adjacent pairs into a single\n" + " descending list, halving their number.\n" + " It returns a list of the remaining descending lists.\n" +). +-spec merge_ascending_pairs( + list(list(AJU)), + fun((AJU, AJU) -> gleam@order:order()), + list(list(AJU)) +) -> list(list(AJU)). +merge_ascending_pairs(Sequences, Compare, Acc) -> + case Sequences of + [] -> + lists:reverse(Acc); + + [Sequence] -> + lists:reverse([lists:reverse(Sequence) | Acc]); + + [Ascending1, Ascending2 | Rest] -> + Descending = merge_ascendings(Ascending1, Ascending2, Compare, []), + merge_ascending_pairs(Rest, Compare, [Descending | Acc]) + end. + +-file("src/gleam/list.gleam", 1447). +?DOC( + " This is exactly the same as merge_ascendings but mirrored: it merges two\n" + " lists sorted in descending order into a single list sorted in ascending\n" + " order according to the given comparator function.\n" + "\n" + " This reversing of the sort order is not avoidable if we want to implement\n" + " merge as a tail recursive function. We could reverse the accumulator before\n" + " returning it but that would end up being less efficient; so the merging\n" + " algorithm has to play around this.\n" +). +-spec merge_descendings( + list(AKL), + list(AKL), + fun((AKL, AKL) -> gleam@order:order()), + list(AKL) +) -> list(AKL). +merge_descendings(List1, List2, Compare, Acc) -> + case {List1, List2} of + {[], List} -> + reverse_and_prepend(List, Acc); + + {List, []} -> + reverse_and_prepend(List, Acc); + + {[First1 | Rest1], [First2 | Rest2]} -> + case Compare(First1, First2) of + lt -> + merge_descendings(List1, Rest2, Compare, [First2 | Acc]); + + gt -> + merge_descendings(Rest1, List2, Compare, [First1 | Acc]); + + eq -> + merge_descendings(Rest1, List2, Compare, [First1 | Acc]) + end + end. + +-file("src/gleam/list.gleam", 1395). +?DOC(" This is the same as merge_ascending_pairs but flipped for descending lists.\n"). +-spec merge_descending_pairs( + list(list(AKA)), + fun((AKA, AKA) -> gleam@order:order()), + list(list(AKA)) +) -> list(list(AKA)). +merge_descending_pairs(Sequences, Compare, Acc) -> + case Sequences of + [] -> + lists:reverse(Acc); + + [Sequence] -> + lists:reverse([lists:reverse(Sequence) | Acc]); + + [Descending1, Descending2 | Rest] -> + Ascending = merge_descendings(Descending1, Descending2, Compare, []), + merge_descending_pairs(Rest, Compare, [Ascending | Acc]) + end. + +-file("src/gleam/list.gleam", 1339). +?DOC( + " Given some some sorted sequences (assumed to be sorted in `direction`) it\n" + " merges them all together until we're left with just a list sorted in\n" + " ascending order.\n" +). +-spec merge_all( + list(list(AJQ)), + sorting(), + fun((AJQ, AJQ) -> gleam@order:order()) +) -> list(AJQ). +merge_all(Sequences, Direction, Compare) -> + case {Sequences, Direction} of + {[], _} -> + []; + + {[Sequence], ascending} -> + Sequence; + + {[Sequence@1], descending} -> + lists:reverse(Sequence@1); + + {_, ascending} -> + Sequences@1 = merge_ascending_pairs(Sequences, Compare, []), + merge_all(Sequences@1, descending, Compare); + + {_, descending} -> + Sequences@2 = merge_descending_pairs(Sequences, Compare, []), + merge_all(Sequences@2, ascending, Compare) + end. + +-file("src/gleam/list.gleam", 1210). +?DOC( + " Sorts from smallest to largest based upon the ordering specified by a given\n" + " function.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " import gleam/int\n" + "\n" + " sort([4, 3, 6, 5, 4, 1, 2], by: int.compare)\n" + " // -> [1, 2, 3, 4, 4, 5, 6]\n" + " ```\n" +). +-spec sort(list(AJG), fun((AJG, AJG) -> gleam@order:order())) -> list(AJG). +sort(List, Compare) -> + case List of + [] -> + []; + + [X] -> + [X]; + + [X@1, Y | Rest] -> + Direction = case Compare(X@1, Y) of + lt -> + ascending; + + eq -> + ascending; + + gt -> + descending + end, + Sequences = sequences(Rest, Compare, [X@1], Direction, Y, []), + merge_all(Sequences, ascending, Compare) + end. + +-file("src/gleam/list.gleam", 1487). +-spec range_loop(integer(), integer(), list(integer())) -> list(integer()). +range_loop(Start, Stop, Acc) -> + case gleam@int:compare(Start, Stop) of + eq -> + [Stop | Acc]; + + gt -> + range_loop(Start, Stop + 1, [Stop | Acc]); + + lt -> + range_loop(Start, Stop - 1, [Stop | Acc]) + end. + +-file("src/gleam/list.gleam", 1483). +?DOC( + " Creates a list of ints ranging from a given start and finish.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " range(0, 0)\n" + " // -> [0]\n" + " ```\n" + "\n" + " ```gleam\n" + " range(0, 5)\n" + " // -> [0, 1, 2, 3, 4, 5]\n" + " ```\n" + "\n" + " ```gleam\n" + " range(1, -5)\n" + " // -> [1, 0, -1, -2, -3, -4, -5]\n" + " ```\n" +). +-spec range(integer(), integer()) -> list(integer()). +range(Start, Stop) -> + range_loop(Start, Stop, []). + +-file("src/gleam/list.gleam", 1513). +-spec repeat_loop(AKV, integer(), list(AKV)) -> list(AKV). +repeat_loop(Item, Times, Acc) -> + case Times =< 0 of + true -> + Acc; + + false -> + repeat_loop(Item, Times - 1, [Item | Acc]) + end. + +-file("src/gleam/list.gleam", 1509). +?DOC( + " Builds a list of a given value a given number of times.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " repeat(\"a\", times: 0)\n" + " // -> []\n" + " ```\n" + "\n" + " ```gleam\n" + " repeat(\"a\", times: 5)\n" + " // -> [\"a\", \"a\", \"a\", \"a\", \"a\"]\n" + " ```\n" +). +-spec repeat(AKT, integer()) -> list(AKT). +repeat(A, Times) -> + repeat_loop(A, Times, []). + +-file("src/gleam/list.gleam", 1546). +-spec split_loop(list(ALC), integer(), list(ALC)) -> {list(ALC), list(ALC)}. +split_loop(List, N, Taken) -> + case N =< 0 of + true -> + {lists:reverse(Taken), List}; + + false -> + case List of + [] -> + {lists:reverse(Taken), []}; + + [First | Rest] -> + split_loop(Rest, N - 1, [First | Taken]) + end + end. + +-file("src/gleam/list.gleam", 1542). +?DOC( + " Splits a list in two before the given index.\n" + "\n" + " If the list is not long enough to have the given index the before list will\n" + " be the input list, and the after list will be empty.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " split([6, 7, 8, 9], 0)\n" + " // -> #([], [6, 7, 8, 9])\n" + " ```\n" + "\n" + " ```gleam\n" + " split([6, 7, 8, 9], 2)\n" + " // -> #([6, 7], [8, 9])\n" + " ```\n" + "\n" + " ```gleam\n" + " split([6, 7, 8, 9], 4)\n" + " // -> #([6, 7, 8, 9], [])\n" + " ```\n" +). +-spec split(list(AKY), integer()) -> {list(AKY), list(AKY)}. +split(List, Index) -> + split_loop(List, Index, []). + +-file("src/gleam/list.gleam", 1582). +-spec split_while_loop(list(ALL), fun((ALL) -> boolean()), list(ALL)) -> {list(ALL), + list(ALL)}. +split_while_loop(List, F, Acc) -> + case List of + [] -> + {lists:reverse(Acc), []}; + + [First | Rest] -> + case F(First) of + true -> + split_while_loop(Rest, F, [First | Acc]); + + false -> + {lists:reverse(Acc), List} + end + end. + +-file("src/gleam/list.gleam", 1575). +?DOC( + " Splits a list in two before the first element that a given function returns\n" + " `False` for.\n" + "\n" + " If the function returns `True` for all elements the first list will be the\n" + " input list, and the second list will be empty.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 })\n" + " // -> #([1, 2, 3], [4, 5])\n" + " ```\n" + "\n" + " ```gleam\n" + " split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 })\n" + " // -> #([1, 2, 3, 4, 5], [])\n" + " ```\n" +). +-spec split_while(list(ALH), fun((ALH) -> boolean())) -> {list(ALH), list(ALH)}. +split_while(List, Predicate) -> + split_while_loop(List, Predicate, []). + +-file("src/gleam/list.gleam", 1622). +?DOC( + " Given a list of 2-element tuples, finds the first tuple that has a given\n" + " key as the first element and returns the second element.\n" + "\n" + " If no tuple is found with the given key then `Error(Nil)` is returned.\n" + "\n" + " This function may be useful for interacting with Erlang code where lists of\n" + " tuples are common.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_find([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" + " // -> Ok(0)\n" + " ```\n" + "\n" + " ```gleam\n" + " key_find([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" + " // -> Ok(1)\n" + " ```\n" + "\n" + " ```gleam\n" + " key_find([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec key_find(list({ALQ, ALR}), ALQ) -> {ok, ALR} | {error, nil}. +key_find(Keyword_list, Desired_key) -> + find_map( + Keyword_list, + fun(Keyword) -> + {Key, Value} = Keyword, + case Key =:= Desired_key of + true -> + {ok, Value}; + + false -> + {error, nil} + end + end + ). + +-file("src/gleam/list.gleam", 1653). +?DOC( + " Given a list of 2-element tuples, finds all tuples that have a given\n" + " key as the first element and returns the second element.\n" + "\n" + " This function may be useful for interacting with Erlang code where lists of\n" + " tuples are common.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_filter([#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)], \"a\")\n" + " // -> [0, 2]\n" + " ```\n" + "\n" + " ```gleam\n" + " key_filter([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" + " // -> []\n" + " ```\n" +). +-spec key_filter(list({ALV, ALW}), ALV) -> list(ALW). +key_filter(Keyword_list, Desired_key) -> + filter_map( + Keyword_list, + fun(Keyword) -> + {Key, Value} = Keyword, + case Key =:= Desired_key of + true -> + {ok, Value}; + + false -> + {error, nil} + end + end + ). + +-file("src/gleam/list.gleam", 1693). +-spec key_pop_loop(list({AMF, AMG}), AMF, list({AMF, AMG})) -> {ok, + {AMG, list({AMF, AMG})}} | + {error, nil}. +key_pop_loop(List, Key, Checked) -> + case List of + [] -> + {error, nil}; + + [{K, V} | Rest] when K =:= Key -> + {ok, {V, reverse_and_prepend(Checked, Rest)}}; + + [First | Rest@1] -> + key_pop_loop(Rest@1, Key, [First | Checked]) + end. + +-file("src/gleam/list.gleam", 1689). +?DOC( + " Given a list of 2-element tuples, finds the first tuple that has a given\n" + " key as the first element. This function will return the second element\n" + " of the found tuple and list with tuple removed.\n" + "\n" + " If no tuple is found with the given key then `Error(Nil)` is returned.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_pop([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" + " // -> Ok(#(0, [#(\"b\", 1)]))\n" + " ```\n" + "\n" + " ```gleam\n" + " key_pop([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" + " // -> Ok(#(1, [#(\"a\", 0)]))\n" + " ```\n" + "\n" + " ```gleam\n" + " key_pop([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" + " // -> Error(Nil)\n" + " ```\n" +). +-spec key_pop(list({ALZ, AMA}), ALZ) -> {ok, {AMA, list({ALZ, AMA})}} | + {error, nil}. +key_pop(List, Key) -> + key_pop_loop(List, Key, []). + +-file("src/gleam/list.gleam", 1727). +-spec key_set_loop(list({AMQ, AMR}), AMQ, AMR, list({AMQ, AMR})) -> list({AMQ, + AMR}). +key_set_loop(List, Key, Value, Inspected) -> + case List of + [{K, _} | Rest] when K =:= Key -> + reverse_and_prepend(Inspected, [{K, Value} | Rest]); + + [First | Rest@1] -> + key_set_loop(Rest@1, Key, Value, [First | Inspected]); + + [] -> + lists:reverse([{Key, Value} | Inspected]) + end. + +-file("src/gleam/list.gleam", 1723). +?DOC( + " Given a list of 2-element tuples, inserts a key and value into the list.\n" + "\n" + " If there was already a tuple with the key then it is replaced, otherwise it\n" + " is added to the end of the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " key_set([#(5, 0), #(4, 1)], 4, 100)\n" + " // -> [#(5, 0), #(4, 100)]\n" + " ```\n" + "\n" + " ```gleam\n" + " key_set([#(5, 0), #(4, 1)], 1, 100)\n" + " // -> [#(5, 0), #(4, 1), #(1, 100)]\n" + " ```\n" +). +-spec key_set(list({AMM, AMN}), AMM, AMN) -> list({AMM, AMN}). +key_set(List, Key, Value) -> + key_set_loop(List, Key, Value, []). + +-file("src/gleam/list.gleam", 1755). +?DOC( + " Calls a function for each element in a list, discarding the return value.\n" + "\n" + " Useful for calling a side effect for every item of a list.\n" + "\n" + " ```gleam\n" + " import gleam/io\n" + "\n" + " each([\"1\", \"2\", \"3\"], io.println)\n" + " // -> Nil\n" + " // 1\n" + " // 2\n" + " // 3\n" + " ```\n" +). +-spec each(list(AMV), fun((AMV) -> any())) -> nil. +each(List, F) -> + case List of + [] -> + nil; + + [First | Rest] -> + F(First), + each(Rest, F) + end. + +-file("src/gleam/list.gleam", 1781). +?DOC( + " Calls a `Result` returning function for each element in a list, discarding\n" + " the return value. If the function returns `Error` then the iteration is\n" + " stopped and the error is returned.\n" + "\n" + " Useful for calling a side effect for every item of a list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " try_each(\n" + " over: [1, 2, 3],\n" + " with: function_that_might_fail,\n" + " )\n" + " // -> Ok(Nil)\n" + " ```\n" +). +-spec try_each(list(AMY), fun((AMY) -> {ok, any()} | {error, ANB})) -> {ok, nil} | + {error, ANB}. +try_each(List, Fun) -> + case List of + [] -> + {ok, nil}; + + [First | Rest] -> + case Fun(First) of + {ok, _} -> + try_each(Rest, Fun); + + {error, E} -> + {error, E} + end + end. + +-file("src/gleam/list.gleam", 1814). +-spec partition_loop(list(BGB), fun((BGB) -> boolean()), list(BGB), list(BGB)) -> {list(BGB), + list(BGB)}. +partition_loop(List, Categorise, Trues, Falses) -> + case List of + [] -> + {lists:reverse(Trues), lists:reverse(Falses)}; + + [First | Rest] -> + case Categorise(First) of + true -> + partition_loop(Rest, Categorise, [First | Trues], Falses); + + false -> + partition_loop(Rest, Categorise, Trues, [First | Falses]) + end + end. + +-file("src/gleam/list.gleam", 1807). +?DOC( + " Partitions a list into a tuple/pair of lists\n" + " by a given categorisation function.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " import gleam/int\n" + "\n" + " [1, 2, 3, 4, 5] |> partition(int.is_odd)\n" + " // -> #([1, 3, 5], [2, 4])\n" + " ```\n" +). +-spec partition(list(ANG), fun((ANG) -> boolean())) -> {list(ANG), list(ANG)}. +partition(List, Categorise) -> + partition_loop(List, Categorise, [], []). + +-file("src/gleam/list.gleam", 1834). +?DOC( + " Returns all the permutations of a list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " permutations([1, 2])\n" + " // -> [[1, 2], [2, 1]]\n" + " ```\n" +). +-spec permutations(list(ANP)) -> list(list(ANP)). +permutations(List) -> + case List of + [] -> + [[]]; + + [_ | _] -> + _pipe@3 = index_map( + List, + fun(I, I_idx) -> + _pipe = index_fold( + List, + [], + fun(Acc, J, J_idx) -> case I_idx =:= J_idx of + true -> + Acc; + + false -> + [J | Acc] + end end + ), + _pipe@1 = lists:reverse(_pipe), + _pipe@2 = permutations(_pipe@1), + map(_pipe@2, fun(Permutation) -> [I | Permutation] end) + end + ), + lists:append(_pipe@3) + end. + +-file("src/gleam/list.gleam", 1874). +-spec window_loop(list(list(ANX)), list(ANX), integer()) -> list(list(ANX)). +window_loop(Acc, List, N) -> + Window = take(List, N), + case erlang:length(Window) =:= N of + true -> + window_loop([Window | Acc], drop(List, 1), N); + + false -> + lists:reverse(Acc) + end. + +-file("src/gleam/list.gleam", 1867). +?DOC( + " Returns a list of sliding windows.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " window([1,2,3,4,5], 3)\n" + " // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]\n" + " ```\n" + "\n" + " ```gleam\n" + " window([1, 2], 4)\n" + " // -> []\n" + " ```\n" +). +-spec window(list(ANT), integer()) -> list(list(ANT)). +window(List, N) -> + case N =< 0 of + true -> + []; + + false -> + window_loop([], List, N) + end. + +-file("src/gleam/list.gleam", 1897). +?DOC( + " Returns a list of tuples containing two contiguous elements.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " window_by_2([1,2,3,4])\n" + " // -> [#(1, 2), #(2, 3), #(3, 4)]\n" + " ```\n" + "\n" + " ```gleam\n" + " window_by_2([1])\n" + " // -> []\n" + " ```\n" +). +-spec window_by_2(list(AOD)) -> list({AOD, AOD}). +window_by_2(List) -> + zip(List, drop(List, 1)). + +-file("src/gleam/list.gleam", 1910). +?DOC( + " Drops the first elements in a given list for which the predicate function returns `True`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " drop_while([1, 2, 3, 4], fn (x) { x < 3 })\n" + " // -> [3, 4]\n" + " ```\n" +). +-spec drop_while(list(AOG), fun((AOG) -> boolean())) -> list(AOG). +drop_while(List, Predicate) -> + case List of + [] -> + []; + + [First | Rest] -> + case Predicate(First) of + true -> + drop_while(Rest, Predicate); + + false -> + [First | Rest] + end + end. + +-file("src/gleam/list.gleam", 1940). +-spec take_while_loop(list(AOM), fun((AOM) -> boolean()), list(AOM)) -> list(AOM). +take_while_loop(List, Predicate, Acc) -> + case List of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + case Predicate(First) of + true -> + take_while_loop(Rest, Predicate, [First | Acc]); + + false -> + lists:reverse(Acc) + end + end. + +-file("src/gleam/list.gleam", 1933). +?DOC( + " Takes the first elements in a given list for which the predicate function returns `True`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " take_while([1, 2, 3, 2, 4], fn (x) { x < 3 })\n" + " // -> [1, 2]\n" + " ```\n" +). +-spec take_while(list(AOJ), fun((AOJ) -> boolean())) -> list(AOJ). +take_while(List, Predicate) -> + take_while_loop(List, Predicate, []). + +-file("src/gleam/list.gleam", 1972). +-spec chunk_loop(list(AOV), fun((AOV) -> AOX), AOX, list(AOV), list(list(AOV))) -> list(list(AOV)). +chunk_loop(List, F, Previous_key, Current_chunk, Acc) -> + case List of + [First | Rest] -> + Key = F(First), + case Key =:= Previous_key of + true -> + chunk_loop(Rest, F, Key, [First | Current_chunk], Acc); + + false -> + New_acc = [lists:reverse(Current_chunk) | Acc], + chunk_loop(Rest, F, Key, [First], New_acc) + end; + + [] -> + lists:reverse([lists:reverse(Current_chunk) | Acc]) + end. + +-file("src/gleam/list.gleam", 1965). +?DOC( + " Returns a list of chunks in which\n" + " the return value of calling `f` on each element is the same.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 })\n" + " // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n" + " ```\n" +). +-spec chunk(list(AOQ), fun((AOQ) -> any())) -> list(list(AOQ)). +chunk(List, F) -> + case List of + [] -> + []; + + [First | Rest] -> + chunk_loop(Rest, F, F(First), [First], []) + end. + +-file("src/gleam/list.gleam", 2017). +-spec sized_chunk_loop( + list(APH), + integer(), + integer(), + list(APH), + list(list(APH)) +) -> list(list(APH)). +sized_chunk_loop(List, Count, Left, Current_chunk, Acc) -> + case List of + [] -> + case Current_chunk of + [] -> + lists:reverse(Acc); + + Remaining -> + lists:reverse([lists:reverse(Remaining) | Acc]) + end; + + [First | Rest] -> + Chunk = [First | Current_chunk], + case Left > 1 of + true -> + sized_chunk_loop(Rest, Count, Left - 1, Chunk, Acc); + + false -> + sized_chunk_loop( + Rest, + Count, + Count, + [], + [lists:reverse(Chunk) | Acc] + ) + end + end. + +-file("src/gleam/list.gleam", 2013). +?DOC( + " Returns a list of chunks containing `count` elements each.\n" + "\n" + " If the last chunk does not have `count` elements, it is instead\n" + " a partial chunk, with less than `count` elements.\n" + "\n" + " For any `count` less than 1 this function behaves as if it was set to 1.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2)\n" + " // -> [[1, 2], [3, 4], [5, 6]]\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3)\n" + " // -> [[1, 2, 3], [4, 5, 6], [7, 8]]\n" + " ```\n" +). +-spec sized_chunk(list(APD), integer()) -> list(list(APD)). +sized_chunk(List, Count) -> + sized_chunk_loop(List, Count, Count, [], []). + +-file("src/gleam/list.gleam", 2061). +?DOC( + " This function acts similar to fold, but does not take an initial state.\n" + " Instead, it starts from the first element in the list\n" + " and combines it with each subsequent element in turn using the given\n" + " function. The function is called as `fun(accumulator, current_element)`.\n" + "\n" + " Returns `Ok` to indicate a successful run, and `Error` if called on an\n" + " empty list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " [] |> reduce(fn(acc, x) { acc + x })\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x })\n" + " // -> Ok(15)\n" + " ```\n" +). +-spec reduce(list(APO), fun((APO, APO) -> APO)) -> {ok, APO} | {error, nil}. +reduce(List, Fun) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + {ok, fold(Rest, First, Fun)} + end. + +-file("src/gleam/list.gleam", 2085). +-spec scan_loop(list(APW), APY, list(APY), fun((APY, APW) -> APY)) -> list(APY). +scan_loop(List, Accumulator, Accumulated, Fun) -> + case List of + [] -> + lists:reverse(Accumulated); + + [First | Rest] -> + Next = Fun(Accumulator, First), + scan_loop(Rest, Next, [Next | Accumulated], Fun) + end. + +-file("src/gleam/list.gleam", 2077). +?DOC( + " Similar to `fold`, but yields the state of the accumulator at each stage.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i })\n" + " // -> [101, 103, 106]\n" + " ```\n" +). +-spec scan(list(APS), APU, fun((APU, APS) -> APU)) -> list(APU). +scan(List, Initial, Fun) -> + scan_loop(List, Initial, [], Fun). + +-file("src/gleam/list.gleam", 2118). +?DOC( + " Returns the last element in the given list.\n" + "\n" + " Returns `Error(Nil)` if the list is empty.\n" + "\n" + " This function runs in linear time.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " last([])\n" + " // -> Error(Nil)\n" + " ```\n" + "\n" + " ```gleam\n" + " last([1, 2, 3, 4, 5])\n" + " // -> Ok(5)\n" + " ```\n" +). +-spec last(list(AQB)) -> {ok, AQB} | {error, nil}. +last(List) -> + case List of + [] -> + {error, nil}; + + [Last] -> + {ok, Last}; + + [_ | Rest] -> + last(Rest) + end. + +-file("src/gleam/list.gleam", 2140). +?DOC( + " Return unique combinations of elements in the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " combinations([1, 2, 3], 2)\n" + " // -> [[1, 2], [1, 3], [2, 3]]\n" + " ```\n" + "\n" + " ```gleam\n" + " combinations([1, 2, 3, 4], 3)\n" + " // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]\n" + " ```\n" +). +-spec combinations(list(AQF), integer()) -> list(list(AQF)). +combinations(Items, N) -> + case {N, Items} of + {0, _} -> + [[]]; + + {_, []} -> + []; + + {_, [First | Rest]} -> + _pipe = combinations(Rest, N - 1), + _pipe@1 = map(_pipe, fun(Combination) -> [First | Combination] end), + _pipe@2 = lists:reverse(_pipe@1), + fold(_pipe@2, combinations(Rest, N), fun(Acc, C) -> [C | Acc] end) + end. + +-file("src/gleam/list.gleam", 2165). +-spec combination_pairs_loop(list(AQM), list({AQM, AQM})) -> list({AQM, AQM}). +combination_pairs_loop(Items, Acc) -> + case Items of + [] -> + lists:reverse(Acc); + + [First | Rest] -> + First_combinations = map(Rest, fun(Other) -> {First, Other} end), + Acc@1 = reverse_and_prepend(First_combinations, Acc), + combination_pairs_loop(Rest, Acc@1) + end. + +-file("src/gleam/list.gleam", 2161). +?DOC( + " Return unique pair combinations of elements in the list.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " combination_pairs([1, 2, 3])\n" + " // -> [#(1, 2), #(1, 3), #(2, 3)]\n" + " ```\n" +). +-spec combination_pairs(list(AQJ)) -> list({AQJ, AQJ}). +combination_pairs(Items) -> + combination_pairs_loop(Items, []). + +-file("src/gleam/list.gleam", 2220). +-spec take_firsts(list(list(ARG)), list(ARG), list(list(ARG))) -> {list(ARG), + list(list(ARG))}. +take_firsts(Rows, Column, Remaining_rows) -> + case Rows of + [] -> + {lists:reverse(Column), lists:reverse(Remaining_rows)}; + + [[] | Rest] -> + take_firsts(Rest, Column, Remaining_rows); + + [[First | Remaining_row] | Rest_rows] -> + Remaining_rows@1 = [Remaining_row | Remaining_rows], + take_firsts(Rest_rows, [First | Column], Remaining_rows@1) + end. + +-file("src/gleam/list.gleam", 2207). +-spec transpose_loop(list(list(AQZ)), list(list(AQZ))) -> list(list(AQZ)). +transpose_loop(Rows, Columns) -> + case Rows of + [] -> + lists:reverse(Columns); + + _ -> + {Column, Rest} = take_firsts(Rows, [], []), + case Column of + [_ | _] -> + transpose_loop(Rest, [Column | Columns]); + + [] -> + transpose_loop(Rest, Columns) + end + end. + +-file("src/gleam/list.gleam", 2203). +?DOC( + " Transpose rows and columns of the list of lists.\n" + "\n" + " Notice: This function is not tail recursive,\n" + " and thus may exceed stack size if called,\n" + " with large lists (on the JavaScript target).\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " transpose([[1, 2, 3], [101, 102, 103]])\n" + " // -> [[1, 101], [2, 102], [3, 103]]\n" + " ```\n" +). +-spec transpose(list(list(AQU))) -> list(list(AQU)). +transpose(List_of_lists) -> + transpose_loop(List_of_lists, []). + +-file("src/gleam/list.gleam", 2185). +?DOC( + " Make a list alternating the elements from the given lists\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " interleave([[1, 2], [101, 102], [201, 202]])\n" + " // -> [1, 101, 201, 2, 102, 202]\n" + " ```\n" +). +-spec interleave(list(list(AQQ))) -> list(AQQ). +interleave(List) -> + _pipe = transpose(List), + lists:append(_pipe). + +-file("src/gleam/list.gleam", 2253). +-spec shuffle_pair_unwrap_loop(list({float(), ARS}), list(ARS)) -> list(ARS). +shuffle_pair_unwrap_loop(List, Acc) -> + case List of + [] -> + Acc; + + [Elem_pair | Enumerable] -> + shuffle_pair_unwrap_loop( + Enumerable, + [erlang:element(2, Elem_pair) | Acc] + ) + end. + +-file("src/gleam/list.gleam", 2261). +-spec do_shuffle_by_pair_indexes(list({float(), ARW})) -> list({float(), ARW}). +do_shuffle_by_pair_indexes(List_of_pairs) -> + sort( + List_of_pairs, + fun(A_pair, B_pair) -> + gleam@float:compare( + erlang:element(1, A_pair), + erlang:element(1, B_pair) + ) + end + ). + +-file("src/gleam/list.gleam", 2246). +?DOC( + " Takes a list, randomly sorts all items and returns the shuffled list.\n" + "\n" + " This function uses `float.random` to decide the order of the elements.\n" + "\n" + " ## Example\n" + "\n" + " ```gleam\n" + " range(1, 10) |> shuffle()\n" + " // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5]\n" + " ```\n" +). +-spec shuffle(list(ARP)) -> list(ARP). +shuffle(List) -> + _pipe = List, + _pipe@1 = fold(_pipe, [], fun(Acc, A) -> [{rand:uniform(), A} | Acc] end), + _pipe@2 = do_shuffle_by_pair_indexes(_pipe@1), + shuffle_pair_unwrap_loop(_pipe@2, []). + +-file("src/gleam/list.gleam", 2293). +-spec max_loop(list(ASG), fun((ASG, ASG) -> gleam@order:order()), ASG) -> ASG. +max_loop(List, Compare, Max) -> + case List of + [] -> + Max; + + [First | Rest] -> + case Compare(First, Max) of + gt -> + max_loop(Rest, Compare, First); + + lt -> + max_loop(Rest, Compare, Max); + + eq -> + max_loop(Rest, Compare, Max) + end + end. + +-file("src/gleam/list.gleam", 2283). +?DOC( + " Takes a list and a comparator, and returns the maximum element in the list\n" + "\n" + "\n" + " ## Example\n" + "\n" + " ```gleam\n" + " range(1, 10) |> list.max(int.compare)\n" + " // -> Ok(10)\n" + " ```\n" + "\n" + " ```gleam\n" + " [\"a\", \"c\", \"b\"] |> list.max(string.compare)\n" + " // -> Ok(\"c\")\n" + " ```\n" +). +-spec max(list(ARZ), fun((ARZ, ARZ) -> gleam@order:order())) -> {ok, ARZ} | + {error, nil}. +max(List, Compare) -> + case List of + [] -> + {error, nil}; + + [First | Rest] -> + {ok, max_loop(Rest, Compare, First)} + end. + +-file("src/gleam/list.gleam", 2374). +-spec build_reservoir_loop( + list(ASV), + integer(), + gleam@dict:dict(integer(), ASV) +) -> {gleam@dict:dict(integer(), ASV), list(ASV)}. +build_reservoir_loop(List, Size, Reservoir) -> + Reservoir_size = maps:size(Reservoir), + case Reservoir_size >= Size of + true -> + {Reservoir, List}; + + false -> + case List of + [] -> + {Reservoir, []}; + + [First | Rest] -> + Reservoir@1 = gleam@dict:insert( + Reservoir, + Reservoir_size, + First + ), + build_reservoir_loop(Rest, Size, Reservoir@1) + end + end. + +-file("src/gleam/list.gleam", 2370). +?DOC( + " Builds the initial reservoir used by Algorithm L.\n" + " This is a dictionary with keys ranging from `0` up to `n - 1` where each\n" + " value is the corresponding element at that position in `list`.\n" + "\n" + " This also returns the remaining elements of `list` that didn't end up in\n" + " the reservoir.\n" +). +-spec build_reservoir(list(ASQ), integer()) -> {gleam@dict:dict(integer(), ASQ), + list(ASQ)}. +build_reservoir(List, N) -> + build_reservoir_loop(List, N, maps:new()). + +-file("src/gleam/list.gleam", 2358). +-spec log_random() -> float(). +log_random() -> + Random@1 = case gleam@float:logarithm( + rand:uniform() + 2.2250738585072014e-308 + ) of + {ok, Random} -> Random; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <>, + module => <<"gleam/list"/utf8>>, + function => <<"log_random"/utf8>>, + line => 2359, + value => _assert_fail, + start => 55490, + 'end' => 55561, + pattern_start => 55501, + pattern_end => 55511}) + end, + Random@1. + +-file("src/gleam/list.gleam", 2335). +-spec sample_loop( + list(ASK), + gleam@dict:dict(integer(), ASK), + integer(), + float() +) -> gleam@dict:dict(integer(), ASK). +sample_loop(List, Reservoir, N, W) -> + Skip = begin + Log@1 = case gleam@float:logarithm(1.0 - W) of + {ok, Log} -> Log; + _assert_fail -> + erlang:error(#{gleam_error => let_assert, + message => <<"Pattern match failed, no pattern matched the value."/utf8>>, + file => <>, + module => <<"gleam/list"/utf8>>, + function => <<"sample_loop"/utf8>>, + line => 2342, + value => _assert_fail, + start => 55051, + 'end' => 55097, + pattern_start => 55062, + pattern_end => 55069}) + end, + erlang:round(math:floor(case Log@1 of + +0.0 -> +0.0; + -0.0 -> -0.0; + Gleam@denominator -> log_random() / Gleam@denominator + end)) + end, + case drop(List, Skip) of + [] -> + Reservoir; + + [First | Rest] -> + Reservoir@1 = gleam@dict:insert( + Reservoir, + gleam@int:random(N), + First + ), + W@1 = W * math:exp(case erlang:float(N) of + +0.0 -> +0.0; + -0.0 -> -0.0; + Gleam@denominator@1 -> log_random() / Gleam@denominator@1 + end), + sample_loop(Rest, Reservoir@1, N, W@1) + end. + +-file("src/gleam/list.gleam", 2317). +?DOC( + " Returns a random sample of up to n elements from a list using reservoir\n" + " sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L).\n" + " Returns an empty list if the sample size is less than or equal to 0.\n" + "\n" + " Order is not random, only selection is.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " reservoir_sample([1, 2, 3, 4, 5], 3)\n" + " // -> [2, 4, 5] // A random sample of 3 items\n" + " ```\n" +). +-spec sample(list(ASH), integer()) -> list(ASH). +sample(List, N) -> + {Reservoir, Rest} = build_reservoir(List, N), + case gleam@dict:is_empty(Reservoir) of + true -> + []; + + false -> + W = math:exp(case erlang:float(N) of + +0.0 -> +0.0; + -0.0 -> -0.0; + Gleam@denominator -> log_random() / Gleam@denominator + end), + maps:values(sample_loop(Rest, Reservoir, N, W)) + end. diff --git a/build/packages/gleam_stdlib/src/gleam@option.erl b/build/packages/gleam_stdlib/src/gleam@option.erl new file mode 100644 index 0000000..cbacd70 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@option.erl @@ -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, []). diff --git a/build/packages/gleam_stdlib/src/gleam@order.erl b/build/packages/gleam_stdlib/src/gleam@order.erl new file mode 100644 index 0000000..5ad2cb2 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@order.erl @@ -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. diff --git a/build/packages/gleam_stdlib/src/gleam@pair.erl b/build/packages/gleam_stdlib/src/gleam@pair.erl new file mode 100644 index 0000000..228140e --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@pair.erl @@ -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}. diff --git a/build/packages/gleam_stdlib/src/gleam@result.erl b/build/packages/gleam_stdlib/src/gleam@result.erl new file mode 100644 index 0000000..3a0deb5 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@result.erl @@ -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. diff --git a/build/packages/gleam_stdlib/src/gleam@set.erl b/build/packages/gleam_stdlib/src/gleam@set.erl new file mode 100644 index 0000000..6a15c29 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@set.erl @@ -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)). diff --git a/build/packages/gleam_stdlib/src/gleam@string.erl b/build/packages/gleam_stdlib/src/gleam@string.erl new file mode 100644 index 0000000..a441003 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@string.erl @@ -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) -> + <>. + +-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 + 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, <>) + 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, + <<<>/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 -> + <> + 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 + <> -> + 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(<>, []). + +-file("src/gleam/string.gleam", 663). +?DOC( + " Converts a `String` to a `List` of `UtfCodepoint`.\n" + "\n" + " See and\n" + " 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 and\n" + " 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). diff --git a/build/packages/gleam_stdlib/src/gleam@string_tree.erl b/build/packages/gleam_stdlib/src/gleam@string_tree.erl new file mode 100644 index 0000000..c36c1b2 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@string_tree.erl @@ -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). diff --git a/build/packages/gleam_stdlib/src/gleam@uri.erl b/build/packages/gleam_stdlib/src/gleam@uri.erl new file mode 100644 index 0000000..3f94175 --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam@uri.erl @@ -0,0 +1,1030 @@ +-module(gleam@uri). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleam/uri.gleam"). +-export([parse_query/1, percent_encode/1, query_to_string/1, percent_decode/1, path_segments/1, to_string/1, origin/1, merge/2, parse/1]). +-export_type([uri/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( + " Utilities for working with URIs\n" + "\n" + " This module provides functions for working with URIs (for example, parsing\n" + " URIs or encoding query strings). The functions in this module are implemented\n" + " according to [RFC 3986](https://tools.ietf.org/html/rfc3986).\n" + "\n" + " Query encoding (Form encoding) is defined in the\n" + " [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data).\n" +). + +-type uri() :: {uri, + gleam@option:option(binary()), + gleam@option:option(binary()), + gleam@option:option(binary()), + gleam@option:option(integer()), + binary(), + gleam@option:option(binary()), + gleam@option:option(binary())}. + +-file("src/gleam/uri.gleam", 289). +-spec is_valid_host_within_brackets_char(integer()) -> boolean(). +is_valid_host_within_brackets_char(Char) -> + (((((48 >= Char) andalso (Char =< 57)) orelse ((65 >= Char) andalso (Char =< 90))) + orelse ((97 >= Char) andalso (Char =< 122))) + orelse (Char =:= 58)) + orelse (Char =:= 46). + +-file("src/gleam/uri.gleam", 503). +-spec parse_fragment(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_fragment(Rest, Pieces) -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + {some, Rest}}}. + +-file("src/gleam/uri.gleam", 475). +-spec parse_query_with_question_mark_loop(binary(), binary(), uri(), integer()) -> {ok, + uri()} | + {error, nil}. +parse_query_with_question_mark_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"#"/utf8, Rest/binary>> when Size =:= 0 -> + parse_fragment(Rest, Pieces); + + <<"#"/utf8, Rest@1/binary>> -> + Query = binary:part(Original, 0, Size), + Pieces@1 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + {some, Query}, + erlang:element(8, Pieces)}, + parse_fragment(Rest@1, Pieces@1); + + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + {some, Original}, + erlang:element(8, Pieces)}}; + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_query_with_question_mark_loop( + Original, + Rest@2, + Pieces, + Size + 1 + ) + end. + +-file("src/gleam/uri.gleam", 468). +-spec parse_query_with_question_mark(binary(), uri()) -> {ok, uri()} | + {error, nil}. +parse_query_with_question_mark(Uri_string, Pieces) -> + parse_query_with_question_mark_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 434). +-spec parse_path_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | + {error, nil}. +parse_path_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"?"/utf8, Rest/binary>> -> + Path = binary:part(Original, 0, Size), + Pieces@1 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + Path, + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_query_with_question_mark(Rest, Pieces@1); + + <<"#"/utf8, Rest@1/binary>> -> + Path@1 = binary:part(Original, 0, Size), + Pieces@2 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + Path@1, + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_fragment(Rest@1, Pieces@2); + + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + Original, + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_path_loop(Original, Rest@2, Pieces, Size + 1) + end. + +-file("src/gleam/uri.gleam", 430). +-spec parse_path(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_path(Uri_string, Pieces) -> + parse_path_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 385). +-spec parse_port_loop(binary(), uri(), integer()) -> {ok, uri()} | {error, nil}. +parse_port_loop(Uri_string, Pieces, Port) -> + case Uri_string of + <<"0"/utf8, Rest/binary>> -> + parse_port_loop(Rest, Pieces, Port * 10); + + <<"1"/utf8, Rest@1/binary>> -> + parse_port_loop(Rest@1, Pieces, (Port * 10) + 1); + + <<"2"/utf8, Rest@2/binary>> -> + parse_port_loop(Rest@2, Pieces, (Port * 10) + 2); + + <<"3"/utf8, Rest@3/binary>> -> + parse_port_loop(Rest@3, Pieces, (Port * 10) + 3); + + <<"4"/utf8, Rest@4/binary>> -> + parse_port_loop(Rest@4, Pieces, (Port * 10) + 4); + + <<"5"/utf8, Rest@5/binary>> -> + parse_port_loop(Rest@5, Pieces, (Port * 10) + 5); + + <<"6"/utf8, Rest@6/binary>> -> + parse_port_loop(Rest@6, Pieces, (Port * 10) + 6); + + <<"7"/utf8, Rest@7/binary>> -> + parse_port_loop(Rest@7, Pieces, (Port * 10) + 7); + + <<"8"/utf8, Rest@8/binary>> -> + parse_port_loop(Rest@8, Pieces, (Port * 10) + 8); + + <<"9"/utf8, Rest@9/binary>> -> + parse_port_loop(Rest@9, Pieces, (Port * 10) + 9); + + <<"?"/utf8, Rest@10/binary>> -> + Pieces@1 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + {some, Port}, + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_query_with_question_mark(Rest@10, Pieces@1); + + <<"#"/utf8, Rest@11/binary>> -> + Pieces@2 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + {some, Port}, + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_fragment(Rest@11, Pieces@2); + + <<"/"/utf8, _/binary>> -> + Pieces@3 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + {some, Port}, + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_path(Uri_string, Pieces@3); + + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + {some, Port}, + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + _ -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 353). +-spec parse_port(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_port(Uri_string, Pieces) -> + case Uri_string of + <<":0"/utf8, Rest/binary>> -> + parse_port_loop(Rest, Pieces, 0); + + <<":1"/utf8, Rest@1/binary>> -> + parse_port_loop(Rest@1, Pieces, 1); + + <<":2"/utf8, Rest@2/binary>> -> + parse_port_loop(Rest@2, Pieces, 2); + + <<":3"/utf8, Rest@3/binary>> -> + parse_port_loop(Rest@3, Pieces, 3); + + <<":4"/utf8, Rest@4/binary>> -> + parse_port_loop(Rest@4, Pieces, 4); + + <<":5"/utf8, Rest@5/binary>> -> + parse_port_loop(Rest@5, Pieces, 5); + + <<":6"/utf8, Rest@6/binary>> -> + parse_port_loop(Rest@6, Pieces, 6); + + <<":7"/utf8, Rest@7/binary>> -> + parse_port_loop(Rest@7, Pieces, 7); + + <<":8"/utf8, Rest@8/binary>> -> + parse_port_loop(Rest@8, Pieces, 8); + + <<":9"/utf8, Rest@9/binary>> -> + parse_port_loop(Rest@9, Pieces, 9); + + <<":"/utf8, _/binary>> -> + {error, nil}; + + <<"?"/utf8, Rest@10/binary>> -> + parse_query_with_question_mark(Rest@10, Pieces); + + <<"#"/utf8, Rest@11/binary>> -> + parse_fragment(Rest@11, Pieces); + + <<"/"/utf8, _/binary>> -> + parse_path(Uri_string, Pieces); + + <<""/utf8>> -> + {ok, Pieces}; + + _ -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 309). +-spec parse_host_outside_of_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, + uri()} | + {error, nil}. +parse_host_outside_of_brackets_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Original}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + <<":"/utf8, _/binary>> -> + Host = binary:part(Original, 0, Size), + Pieces@1 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_port(Uri_string, Pieces@1); + + <<"/"/utf8, _/binary>> -> + Host@1 = binary:part(Original, 0, Size), + Pieces@2 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host@1}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_path(Uri_string, Pieces@2); + + <<"?"/utf8, Rest/binary>> -> + Host@2 = binary:part(Original, 0, Size), + Pieces@3 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host@2}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_query_with_question_mark(Rest, Pieces@3); + + <<"#"/utf8, Rest@1/binary>> -> + Host@3 = binary:part(Original, 0, Size), + Pieces@4 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host@3}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_fragment(Rest@1, Pieces@4); + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_host_outside_of_brackets_loop( + Original, + Rest@2, + Pieces, + Size + 1 + ) + end. + +-file("src/gleam/uri.gleam", 229). +-spec parse_host_within_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, + uri()} | + {error, nil}. +parse_host_within_brackets_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Uri_string}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + <<"]"/utf8, Rest/binary>> when Size =:= 0 -> + parse_port(Rest, Pieces); + + <<"]"/utf8, Rest@1/binary>> -> + Host = binary:part(Original, 0, Size + 1), + Pieces@1 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_port(Rest@1, Pieces@1); + + <<"/"/utf8, _/binary>> when Size =:= 0 -> + parse_path(Uri_string, Pieces); + + <<"/"/utf8, _/binary>> -> + Host@1 = binary:part(Original, 0, Size), + Pieces@2 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host@1}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_path(Uri_string, Pieces@2); + + <<"?"/utf8, Rest@2/binary>> when Size =:= 0 -> + parse_query_with_question_mark(Rest@2, Pieces); + + <<"?"/utf8, Rest@3/binary>> -> + Host@2 = binary:part(Original, 0, Size), + Pieces@3 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host@2}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_query_with_question_mark(Rest@3, Pieces@3); + + <<"#"/utf8, Rest@4/binary>> when Size =:= 0 -> + parse_fragment(Rest@4, Pieces); + + <<"#"/utf8, Rest@5/binary>> -> + Host@3 = binary:part(Original, 0, Size), + Pieces@4 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, Host@3}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_fragment(Rest@5, Pieces@4); + + _ -> + {Char, Rest@6} = gleam_stdlib:string_pop_codeunit(Uri_string), + case is_valid_host_within_brackets_char(Char) of + true -> + parse_host_within_brackets_loop( + Original, + Rest@6, + Pieces, + Size + 1 + ); + + false -> + parse_host_outside_of_brackets_loop( + Original, + Original, + Pieces, + 0 + ) + end + end. + +-file("src/gleam/uri.gleam", 222). +-spec parse_host_within_brackets(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_host_within_brackets(Uri_string, Pieces) -> + parse_host_within_brackets_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 302). +-spec parse_host_outside_of_brackets(binary(), uri()) -> {ok, uri()} | + {error, nil}. +parse_host_outside_of_brackets(Uri_string, Pieces) -> + parse_host_outside_of_brackets_loop(Uri_string, Uri_string, Pieces, 0). + +-file("src/gleam/uri.gleam", 199). +-spec parse_host(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_host(Uri_string, Pieces) -> + case Uri_string of + <<"["/utf8, _/binary>> -> + parse_host_within_brackets(Uri_string, Pieces); + + <<":"/utf8, _/binary>> -> + Pieces@1 = {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, <<""/utf8>>}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_port(Uri_string, Pieces@1); + + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, <<""/utf8>>}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + _ -> + parse_host_outside_of_brackets(Uri_string, Pieces) + end. + +-file("src/gleam/uri.gleam", 167). +-spec parse_userinfo_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | + {error, nil}. +parse_userinfo_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"@"/utf8, Rest/binary>> when Size =:= 0 -> + parse_host(Rest, Pieces); + + <<"@"/utf8, Rest@1/binary>> -> + Userinfo = binary:part(Original, 0, Size), + Pieces@1 = {uri, + erlang:element(2, Pieces), + {some, Userinfo}, + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_host(Rest@1, Pieces@1); + + <<""/utf8>> -> + parse_host(Original, Pieces); + + <<"/"/utf8, _/binary>> -> + parse_host(Original, Pieces); + + <<"?"/utf8, _/binary>> -> + parse_host(Original, Pieces); + + <<"#"/utf8, _/binary>> -> + parse_host(Original, Pieces); + + _ -> + {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_userinfo_loop(Original, Rest@2, Pieces, Size + 1) + end. + +-file("src/gleam/uri.gleam", 163). +-spec parse_authority_pieces(binary(), uri()) -> {ok, uri()} | {error, nil}. +parse_authority_pieces(String, Pieces) -> + parse_userinfo_loop(String, String, Pieces, 0). + +-file("src/gleam/uri.gleam", 150). +-spec parse_authority_with_slashes(binary(), uri()) -> {ok, uri()} | + {error, nil}. +parse_authority_with_slashes(Uri_string, Pieces) -> + case Uri_string of + <<"//"/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + {some, <<""/utf8>>}, + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + <<"//"/utf8, Rest/binary>> -> + parse_authority_pieces(Rest, Pieces); + + _ -> + parse_path(Uri_string, Pieces) + end. + +-file("src/gleam/uri.gleam", 91). +-spec parse_scheme_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | + {error, nil}. +parse_scheme_loop(Original, Uri_string, Pieces, Size) -> + case Uri_string of + <<"/"/utf8, _/binary>> when Size =:= 0 -> + parse_authority_with_slashes(Uri_string, Pieces); + + <<"/"/utf8, _/binary>> -> + Scheme = binary:part(Original, 0, Size), + Pieces@1 = {uri, + {some, string:lowercase(Scheme)}, + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_authority_with_slashes(Uri_string, Pieces@1); + + <<"?"/utf8, Rest/binary>> when Size =:= 0 -> + parse_query_with_question_mark(Rest, Pieces); + + <<"?"/utf8, Rest@1/binary>> -> + Scheme@1 = binary:part(Original, 0, Size), + Pieces@2 = {uri, + {some, string:lowercase(Scheme@1)}, + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_query_with_question_mark(Rest@1, Pieces@2); + + <<"#"/utf8, Rest@2/binary>> when Size =:= 0 -> + parse_fragment(Rest@2, Pieces); + + <<"#"/utf8, Rest@3/binary>> -> + Scheme@2 = binary:part(Original, 0, Size), + Pieces@3 = {uri, + {some, string:lowercase(Scheme@2)}, + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_fragment(Rest@3, Pieces@3); + + <<":"/utf8, _/binary>> when Size =:= 0 -> + {error, nil}; + + <<":"/utf8, Rest@4/binary>> -> + Scheme@3 = binary:part(Original, 0, Size), + Pieces@4 = {uri, + {some, string:lowercase(Scheme@3)}, + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + erlang:element(6, Pieces), + erlang:element(7, Pieces), + erlang:element(8, Pieces)}, + parse_authority_with_slashes(Rest@4, Pieces@4); + + <<""/utf8>> -> + {ok, + {uri, + erlang:element(2, Pieces), + erlang:element(3, Pieces), + erlang:element(4, Pieces), + erlang:element(5, Pieces), + Original, + erlang:element(7, Pieces), + erlang:element(8, Pieces)}}; + + _ -> + {_, Rest@5} = gleam_stdlib:string_pop_codeunit(Uri_string), + parse_scheme_loop(Original, Rest@5, Pieces, Size + 1) + end. + +-file("src/gleam/uri.gleam", 534). +?DOC( + " Parses an urlencoded query string into a list of key value pairs.\n" + " Returns an error for invalid encoding.\n" + "\n" + " The opposite operation is `uri.query_to_string`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " parse_query(\"a=1&b=2\")\n" + " // -> Ok([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" + " ```\n" +). +-spec parse_query(binary()) -> {ok, list({binary(), binary()})} | {error, nil}. +parse_query(Query) -> + gleam_stdlib:parse_query(Query). + +-file("src/gleam/uri.gleam", 570). +?DOC( + " Encodes a string into a percent encoded representation.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " percent_encode(\"100% great\")\n" + " // -> \"100%25%20great\"\n" + " ```\n" +). +-spec percent_encode(binary()) -> binary(). +percent_encode(Value) -> + gleam_stdlib:percent_encode(Value). + +-file("src/gleam/uri.gleam", 555). +-spec query_pair({binary(), binary()}) -> gleam@string_tree:string_tree(). +query_pair(Pair) -> + gleam_stdlib:identity( + [gleam_stdlib:percent_encode(erlang:element(1, Pair)), + <<"="/utf8>>, + gleam_stdlib:percent_encode(erlang:element(2, Pair))] + ). + +-file("src/gleam/uri.gleam", 547). +?DOC( + " Encodes a list of key value pairs as a URI query string.\n" + "\n" + " The opposite operation is `uri.parse_query`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " query_to_string([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" + " // -> \"a=1&b=2\"\n" + " ```\n" +). +-spec query_to_string(list({binary(), binary()})) -> binary(). +query_to_string(Query) -> + _pipe = Query, + _pipe@1 = gleam@list:map(_pipe, fun query_pair/1), + _pipe@2 = gleam@list:intersperse( + _pipe@1, + gleam_stdlib:identity(<<"&"/utf8>>) + ), + _pipe@3 = gleam_stdlib:identity(_pipe@2), + unicode:characters_to_binary(_pipe@3). + +-file("src/gleam/uri.gleam", 583). +?DOC( + " Decodes a percent encoded string.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " percent_decode(\"100%25%20great+fun\")\n" + " // -> Ok(\"100% great+fun\")\n" + " ```\n" +). +-spec percent_decode(binary()) -> {ok, binary()} | {error, nil}. +percent_decode(Value) -> + gleam_stdlib:percent_decode(Value). + +-file("src/gleam/uri.gleam", 605). +-spec remove_dot_segments_loop(list(binary()), list(binary())) -> list(binary()). +remove_dot_segments_loop(Input, Accumulator) -> + case Input of + [] -> + lists:reverse(Accumulator); + + [Segment | Rest] -> + Accumulator@5 = case {Segment, Accumulator} of + {<<""/utf8>>, Accumulator@1} -> + Accumulator@1; + + {<<"."/utf8>>, Accumulator@2} -> + Accumulator@2; + + {<<".."/utf8>>, []} -> + []; + + {<<".."/utf8>>, [_ | Accumulator@3]} -> + Accumulator@3; + + {Segment@1, Accumulator@4} -> + [Segment@1 | Accumulator@4] + end, + remove_dot_segments_loop(Rest, Accumulator@5) + end. + +-file("src/gleam/uri.gleam", 601). +-spec remove_dot_segments(list(binary())) -> list(binary()). +remove_dot_segments(Input) -> + remove_dot_segments_loop(Input, []). + +-file("src/gleam/uri.gleam", 597). +?DOC( + " Splits the path section of a URI into it's constituent segments.\n" + "\n" + " Removes empty segments and resolves dot-segments as specified in\n" + " [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " path_segments(\"/users/1\")\n" + " // -> [\"users\" ,\"1\"]\n" + " ```\n" +). +-spec path_segments(binary()) -> list(binary()). +path_segments(Path) -> + remove_dot_segments(gleam@string:split(Path, <<"/"/utf8>>)). + +-file("src/gleam/uri.gleam", 636). +?DOC( + " Encodes a `Uri` value as a URI string.\n" + "\n" + " The opposite operation is `uri.parse`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " let uri = Uri(..empty, scheme: Some(\"https\"), host: Some(\"example.com\"))\n" + " to_string(uri)\n" + " // -> \"https://example.com\"\n" + " ```\n" +). +-spec to_string(uri()) -> binary(). +to_string(Uri) -> + Parts = case erlang:element(8, Uri) of + {some, Fragment} -> + [<<"#"/utf8>>, Fragment]; + + none -> + [] + end, + Parts@1 = case erlang:element(7, Uri) of + {some, Query} -> + [<<"?"/utf8>>, Query | Parts]; + + none -> + Parts + end, + Parts@2 = [erlang:element(6, Uri) | Parts@1], + Parts@3 = case {erlang:element(4, Uri), + gleam_stdlib:string_starts_with(erlang:element(6, Uri), <<"/"/utf8>>)} of + {{some, Host}, false} when Host =/= <<""/utf8>> -> + [<<"/"/utf8>> | Parts@2]; + + {_, _} -> + Parts@2 + end, + Parts@4 = case {erlang:element(4, Uri), erlang:element(5, Uri)} of + {{some, _}, {some, Port}} -> + [<<":"/utf8>>, erlang:integer_to_binary(Port) | Parts@3]; + + {_, _} -> + Parts@3 + end, + Parts@5 = case {erlang:element(2, Uri), + erlang:element(3, Uri), + erlang:element(4, Uri)} of + {{some, S}, {some, U}, {some, H}} -> + [S, <<"://"/utf8>>, U, <<"@"/utf8>>, H | Parts@4]; + + {{some, S@1}, none, {some, H@1}} -> + [S@1, <<"://"/utf8>>, H@1 | Parts@4]; + + {{some, S@2}, {some, _}, none} -> + [S@2, <<":"/utf8>> | Parts@4]; + + {{some, S@2}, none, none} -> + [S@2, <<":"/utf8>> | Parts@4]; + + {none, none, {some, H@2}} -> + [<<"//"/utf8>>, H@2 | Parts@4]; + + {_, _, _} -> + Parts@4 + end, + erlang:list_to_binary(Parts@5). + +-file("src/gleam/uri.gleam", 680). +?DOC( + " Fetches the origin of a URI.\n" + "\n" + " Returns the origin of a uri as defined in\n" + " [RFC 6454](https://tools.ietf.org/html/rfc6454)\n" + "\n" + " The supported URI schemes are `http` and `https`.\n" + " URLs without a scheme will return `Error`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " let assert Ok(uri) = parse(\"https://example.com/path?foo#bar\")\n" + " origin(uri)\n" + " // -> Ok(\"https://example.com\")\n" + " ```\n" +). +-spec origin(uri()) -> {ok, binary()} | {error, nil}. +origin(Uri) -> + {uri, Scheme, _, Host, Port, _, _, _} = Uri, + case {Host, Scheme} of + {{some, H}, {some, <<"https"/utf8>>}} when Port =:= {some, 443} -> + {ok, erlang:list_to_binary([<<"https://"/utf8>>, H])}; + + {{some, H@1}, {some, <<"http"/utf8>>}} when Port =:= {some, 80} -> + {ok, erlang:list_to_binary([<<"http://"/utf8>>, H@1])}; + + {{some, H@2}, {some, S}} when (S =:= <<"http"/utf8>>) orelse (S =:= <<"https"/utf8>>) -> + case Port of + {some, P} -> + {ok, + erlang:list_to_binary( + [S, + <<"://"/utf8>>, + H@2, + <<":"/utf8>>, + erlang:integer_to_binary(P)] + )}; + + none -> + {ok, erlang:list_to_binary([S, <<"://"/utf8>>, H@2])} + end; + + {_, _} -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 759). +-spec drop_last(list(DGQ)) -> list(DGQ). +drop_last(Elements) -> + gleam@list:take(Elements, erlang:length(Elements) - 1). + +-file("src/gleam/uri.gleam", 763). +-spec join_segments(list(binary())) -> binary(). +join_segments(Segments) -> + gleam@string:join([<<""/utf8>> | Segments], <<"/"/utf8>>). + +-file("src/gleam/uri.gleam", 703). +?DOC( + " Resolves a URI with respect to the given base URI.\n" + "\n" + " The base URI must be an absolute URI or this function will return an error.\n" + " The algorithm for merging uris is described in\n" + " [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2).\n" +). +-spec merge(uri(), uri()) -> {ok, uri()} | {error, nil}. +merge(Base, Relative) -> + case Base of + {uri, {some, _}, _, {some, _}, _, _, _, _} -> + case Relative of + {uri, _, _, {some, _}, _, _, _, _} -> + Path = begin + _pipe = gleam@string:split( + erlang:element(6, Relative), + <<"/"/utf8>> + ), + _pipe@1 = remove_dot_segments(_pipe), + join_segments(_pipe@1) + end, + Resolved = {uri, + gleam@option:'or'( + erlang:element(2, Relative), + erlang:element(2, Base) + ), + none, + erlang:element(4, Relative), + gleam@option:'or'( + erlang:element(5, Relative), + erlang:element(5, Base) + ), + Path, + erlang:element(7, Relative), + erlang:element(8, Relative)}, + {ok, Resolved}; + + _ -> + {New_path, New_query} = case erlang:element(6, Relative) of + <<""/utf8>> -> + {erlang:element(6, Base), + gleam@option:'or'( + erlang:element(7, Relative), + erlang:element(7, Base) + )}; + + _ -> + Path_segments = case gleam_stdlib:string_starts_with( + erlang:element(6, Relative), + <<"/"/utf8>> + ) of + true -> + gleam@string:split( + erlang:element(6, Relative), + <<"/"/utf8>> + ); + + false -> + _pipe@2 = gleam@string:split( + erlang:element(6, Base), + <<"/"/utf8>> + ), + _pipe@3 = drop_last(_pipe@2), + lists:append( + _pipe@3, + gleam@string:split( + erlang:element(6, Relative), + <<"/"/utf8>> + ) + ) + end, + Path@1 = begin + _pipe@4 = Path_segments, + _pipe@5 = remove_dot_segments(_pipe@4), + join_segments(_pipe@5) + end, + {Path@1, erlang:element(7, Relative)} + end, + Resolved@1 = {uri, + erlang:element(2, Base), + none, + erlang:element(4, Base), + erlang:element(5, Base), + New_path, + New_query, + erlang:element(8, Relative)}, + {ok, Resolved@1} + end; + + _ -> + {error, nil} + end. + +-file("src/gleam/uri.gleam", 81). +?DOC( + " Parses a compliant URI string into the `Uri` Type.\n" + " If the string is not a valid URI string then an error is returned.\n" + "\n" + " The opposite operation is `uri.to_string`.\n" + "\n" + " ## Examples\n" + "\n" + " ```gleam\n" + " parse(\"https://example.com:1234/a/b?query=true#fragment\")\n" + " // -> Ok(\n" + " // Uri(\n" + " // scheme: Some(\"https\"),\n" + " // userinfo: None,\n" + " // host: Some(\"example.com\"),\n" + " // port: Some(1234),\n" + " // path: \"/a/b\",\n" + " // query: Some(\"query=true\"),\n" + " // fragment: Some(\"fragment\")\n" + " // )\n" + " // )\n" + " ```\n" +). +-spec parse(binary()) -> {ok, uri()} | {error, nil}. +parse(Uri_string) -> + gleam_stdlib:uri_parse(Uri_string). diff --git a/build/packages/gleam_stdlib/src/gleam_stdlib.app.src b/build/packages/gleam_stdlib/src/gleam_stdlib.app.src new file mode 100644 index 0000000..2cac7ac --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam_stdlib.app.src @@ -0,0 +1,31 @@ +{application, gleam_stdlib, [ + {vsn, "0.62.0"}, + {applications, []}, + {description, "A standard library for the Gleam programming language"}, + {modules, [gleam@bit_array, + gleam@bool, + gleam@bytes_tree, + gleam@dict, + gleam@dynamic, + gleam@dynamic@decode, + gleam@float, + gleam@function, + gleam@int, + gleam@io, + gleam@list, + gleam@option, + gleam@order, + gleam@pair, + gleam@result, + gleam@set, + gleam@string, + gleam@string_tree, + gleam@uri, + gleam_stdlib, + gleam_stdlib@@main, + gleam_stdlib_test_ffi, + gleeunit_ffi, + gleeunit_gleam_panic_ffi, + gleeunit_progress]}, + {registered, []} +]}. diff --git a/build/packages/gleam_stdlib/src/gleam_stdlib.erl b/build/packages/gleam_stdlib/src/gleam_stdlib.erl new file mode 100644 index 0000000..0bfcd2f --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam_stdlib.erl @@ -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, 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, + <> + 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(<>, Acc) -> + case percent_ok(H) of + true -> + percent_encode(T, <>); + false -> + <> = <>, + percent_encode(T, <>) + 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, <>); + false -> + {error, nil} + end; +percent_decode(<>, Acc) -> + percent_decode(Cs, <>); +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) || <> <= 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) -> <> 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(<>, 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(<>, _PrevChar, _Acc) + when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) -> + {error, nil}; +inspect_maybe_gleam_atom(<>, none, Acc) -> + inspect_maybe_gleam_atom(Rest, First, <>); +inspect_maybe_gleam_atom(<<"_", Rest/binary>>, _PrevChar, Acc) -> + inspect_maybe_gleam_atom(Rest, $_, Acc); +inspect_maybe_gleam_atom(<>, $_, Acc) -> + inspect_maybe_gleam_atom(Rest, First, <>); +inspect_maybe_gleam_atom(<>, _PrevChar, Acc) -> + inspect_maybe_gleam_atom(Rest, 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, <<"<<">>), + <>">>. + +inspect_bit_array(<<>>, Acc) -> + Acc; +inspect_bit_array(<>, Acc) -> + inspect_bit_array(Rest, append_segment(Acc, erlang:integer_to_binary(X))); +inspect_bit_array(Rest, Acc) -> + Size = bit_size(Rest), + <> = Rest, + X1 = erlang:integer_to_binary(X), + Size1 = erlang:integer_to_binary(Size), + Segment = <>, + inspect_bit_array(<<>>, append_segment(Acc, Segment)). + +bit_array_to_int_and_size(A) -> + Size = bit_size(A), + <> = A, + {A1, Size}. + +append_segment(<<"<<">>, Segment) -> + <<"<<", Segment/binary>>; +append_segment(Acc, Segment) -> + <>. + + +inspect_maybe_utf8_string(Binary, Acc) -> + case Binary of + <<>> -> {ok, <<$", Acc/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 -> <> + end, + inspect_maybe_utf8_string(Rest, <>); + _ -> {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. diff --git a/build/packages/gleam_stdlib/src/gleam_stdlib.mjs b/build/packages/gleam_stdlib/src/gleam_stdlib.mjs new file mode 100644 index 0000000..2edf3ad --- /dev/null +++ b/build/packages/gleam_stdlib/src/gleam_stdlib.mjs @@ -0,0 +1,1044 @@ +import { + BitArray, + Error, + List, + Ok, + Result, + UtfCodepoint, + stringBits, + toBitArray, + bitArraySlice, + NonEmpty, + Empty, + CustomType, +} from "./gleam.mjs"; +import { Some, None } from "./gleam/option.mjs"; +import Dict from "./dict.mjs"; +import { classify } from "./gleam/dynamic.mjs"; +import { DecodeError } from "./gleam/dynamic/decode.mjs"; + +const Nil = undefined; +const NOT_FOUND = {}; + +export function identity(x) { + return x; +} + +export function parse_int(value) { + if (/^[-+]?(\d+)$/.test(value)) { + return new Ok(parseInt(value)); + } else { + return new Error(Nil); + } +} + +export function parse_float(value) { + if (/^[-+]?(\d+)\.(\d+)([eE][-+]?\d+)?$/.test(value)) { + return new Ok(parseFloat(value)); + } else { + return new Error(Nil); + } +} + +export function to_string(term) { + return term.toString(); +} + +export function int_to_base_string(int, base) { + return int.toString(base).toUpperCase(); +} + +const int_base_patterns = { + 2: /[^0-1]/, + 3: /[^0-2]/, + 4: /[^0-3]/, + 5: /[^0-4]/, + 6: /[^0-5]/, + 7: /[^0-6]/, + 8: /[^0-7]/, + 9: /[^0-8]/, + 10: /[^0-9]/, + 11: /[^0-9a]/, + 12: /[^0-9a-b]/, + 13: /[^0-9a-c]/, + 14: /[^0-9a-d]/, + 15: /[^0-9a-e]/, + 16: /[^0-9a-f]/, + 17: /[^0-9a-g]/, + 18: /[^0-9a-h]/, + 19: /[^0-9a-i]/, + 20: /[^0-9a-j]/, + 21: /[^0-9a-k]/, + 22: /[^0-9a-l]/, + 23: /[^0-9a-m]/, + 24: /[^0-9a-n]/, + 25: /[^0-9a-o]/, + 26: /[^0-9a-p]/, + 27: /[^0-9a-q]/, + 28: /[^0-9a-r]/, + 29: /[^0-9a-s]/, + 30: /[^0-9a-t]/, + 31: /[^0-9a-u]/, + 32: /[^0-9a-v]/, + 33: /[^0-9a-w]/, + 34: /[^0-9a-x]/, + 35: /[^0-9a-y]/, + 36: /[^0-9a-z]/, +}; + +export function int_from_base_string(string, base) { + if (int_base_patterns[base].test(string.replace(/^-/, "").toLowerCase())) { + return new Error(Nil); + } + + const result = parseInt(string, base); + + if (isNaN(result)) { + return new Error(Nil); + } + + return new Ok(result); +} + +export function string_replace(string, target, substitute) { + return string.replaceAll(target, substitute); +} + +export function string_reverse(string) { + return [...string].reverse().join(""); +} + +export function string_length(string) { + if (string === "") { + return 0; + } + const iterator = graphemes_iterator(string); + if (iterator) { + let i = 0; + for (const _ of iterator) { + i++; + } + return i; + } else { + return string.match(/./gsu).length; + } +} + +export function graphemes(string) { + const iterator = graphemes_iterator(string); + if (iterator) { + return List.fromArray(Array.from(iterator).map((item) => item.segment)); + } else { + return List.fromArray(string.match(/./gsu)); + } +} + +let segmenter = undefined; + +function graphemes_iterator(string) { + if (globalThis.Intl && Intl.Segmenter) { + segmenter ||= new Intl.Segmenter(); + return segmenter.segment(string)[Symbol.iterator](); + } +} + +export function pop_grapheme(string) { + let first; + const iterator = graphemes_iterator(string); + if (iterator) { + first = iterator.next().value?.segment; + } else { + first = string.match(/./su)?.[0]; + } + if (first) { + return new Ok([first, string.slice(first.length)]); + } else { + return new Error(Nil); + } +} + +export function pop_codeunit(str) { + return [str.charCodeAt(0) | 0, str.slice(1)]; +} + +export function lowercase(string) { + return string.toLowerCase(); +} + +export function uppercase(string) { + return string.toUpperCase(); +} + +export function less_than(a, b) { + return a < b; +} + +export function add(a, b) { + return a + b; +} + +export function split(xs, pattern) { + return List.fromArray(xs.split(pattern)); +} + +export function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} + +export function length(data) { + return data.length; +} + +export function string_slice(string, idx, len) { + if (len <= 0 || idx >= string.length) { + return ""; + } + + const iterator = graphemes_iterator(string); + if (iterator) { + while (idx-- > 0) { + iterator.next(); + } + + let result = ""; + + while (len-- > 0) { + const v = iterator.next().value; + if (v === undefined) { + break; + } + + result += v.segment; + } + + return result; + } else { + return string + .match(/./gsu) + .slice(idx, idx + len) + .join(""); + } +} + +export function string_codeunit_slice(str, from, length) { + return str.slice(from, from + length); +} +export function crop_string(string, substring) { + return string.substring(string.indexOf(substring)); +} + +export function contains_string(haystack, needle) { + return haystack.indexOf(needle) >= 0; +} + +export function starts_with(haystack, needle) { + return haystack.startsWith(needle); +} + +export function ends_with(haystack, needle) { + return haystack.endsWith(needle); +} + +export function split_once(haystack, needle) { + const index = haystack.indexOf(needle); + if (index >= 0) { + const before = haystack.slice(0, index); + const after = haystack.slice(index + needle.length); + return new Ok([before, after]); + } else { + return new Error(Nil); + } +} + +const unicode_whitespaces = [ + "\u0020", // Space + "\u0009", // Horizontal tab + "\u000A", // Line feed + "\u000B", // Vertical tab + "\u000C", // Form feed + "\u000D", // Carriage return + "\u0085", // Next line + "\u2028", // Line separator + "\u2029", // Paragraph separator +].join(""); + +const trim_start_regex = /* @__PURE__ */ new RegExp( + `^[${unicode_whitespaces}]*`, +); +const trim_end_regex = /* @__PURE__ */ new RegExp(`[${unicode_whitespaces}]*$`); + +export function trim_start(string) { + return string.replace(trim_start_regex, ""); +} + +export function trim_end(string) { + return string.replace(trim_end_regex, ""); +} + +export function bit_array_from_string(string) { + return toBitArray([stringBits(string)]); +} + +export function bit_array_bit_size(bit_array) { + return bit_array.bitSize; +} + +export function bit_array_byte_size(bit_array) { + return bit_array.byteSize; +} + +export function bit_array_pad_to_bytes(bit_array) { + const trailingBitsCount = bit_array.bitSize % 8; + + // If the bit array is a whole number of bytes it can be returned unchanged + if (trailingBitsCount === 0) { + return bit_array; + } + + const finalByte = bit_array.byteAt(bit_array.byteSize - 1); + + // The required final byte has its unused trailing bits set to zero + const unusedBitsCount = 8 - trailingBitsCount; + const correctFinalByte = (finalByte >> unusedBitsCount) << unusedBitsCount; + + // If the unused bits in the final byte are already set to zero then the + // existing buffer can be re-used, avoiding a copy + if (finalByte === correctFinalByte) { + return new BitArray( + bit_array.rawBuffer, + bit_array.byteSize * 8, + bit_array.bitOffset, + ); + } + + // Copy the bit array into a new aligned buffer and set the correct final byte + const buffer = new Uint8Array(bit_array.byteSize); + for (let i = 0; i < buffer.length - 1; i++) { + buffer[i] = bit_array.byteAt(i); + } + buffer[buffer.length - 1] = correctFinalByte; + + return new BitArray(buffer); +} + +export function bit_array_concat(bit_arrays) { + return toBitArray(bit_arrays.toArray()); +} + +export function console_log(term) { + console.log(term); +} + +export function console_error(term) { + console.error(term); +} + +export function crash(message) { + throw new globalThis.Error(message); +} + +export function bit_array_to_string(bit_array) { + // If the bit array isn't a whole number of bytes then return an error + if (bit_array.bitSize % 8 !== 0) { + return new Error(Nil); + } + + try { + const decoder = new TextDecoder("utf-8", { fatal: true }); + + if (bit_array.bitOffset === 0) { + return new Ok(decoder.decode(bit_array.rawBuffer)); + } else { + // The input data isn't aligned, so copy it into a new aligned buffer so + // that TextDecoder can be used + const buffer = new Uint8Array(bit_array.byteSize); + for (let i = 0; i < buffer.length; i++) { + buffer[i] = bit_array.byteAt(i); + } + return new Ok(decoder.decode(buffer)); + } + } catch { + return new Error(Nil); + } +} + +export function print(string) { + if (typeof process === "object" && process.stdout?.write) { + process.stdout.write(string); // We can write without a trailing newline + } else if (typeof Deno === "object") { + Deno.stdout.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline + } else { + console.log(string); // We're in a browser. Newlines are mandated + } +} + +export function print_error(string) { + if (typeof process === "object" && process.stderr?.write) { + process.stderr.write(string); // We can write without a trailing newline + } else if (typeof Deno === "object") { + Deno.stderr.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline + } else { + console.error(string); // We're in a browser. Newlines are mandated + } +} + +export function print_debug(string) { + if (typeof process === "object" && process.stderr?.write) { + process.stderr.write(string + "\n"); // If we're in Node.js, use `stderr` + } else if (typeof Deno === "object") { + Deno.stderr.writeSync(new TextEncoder().encode(string + "\n")); // If we're in Deno, use `stderr` + } else { + console.log(string); // Otherwise, use `console.log` (so that it doesn't look like an error) + } +} + +export function ceiling(float) { + return Math.ceil(float); +} + +export function floor(float) { + return Math.floor(float); +} + +export function round(float) { + return Math.round(float); +} + +export function truncate(float) { + return Math.trunc(float); +} + +export function power(base, exponent) { + // It is checked in Gleam that: + // - The base is non-negative and that the exponent is not fractional. + // - The base is non-zero and the exponent is non-negative (otherwise + // the result will essentially be division by zero). + // It can thus be assumed that valid input is passed to the Math.pow + // function and a NaN or Infinity value will not be produced. + return Math.pow(base, exponent); +} + +export function random_uniform() { + const random_uniform_result = Math.random(); + // With round-to-nearest-even behavior, the ranges claimed for the functions below + // (excluding the one for Math.random() itself) aren't exact. + // If extremely large bounds are chosen (2^53 or higher), + // it's possible in extremely rare cases to calculate the usually-excluded upper bound. + // Note that as numbers in JavaScript are IEEE 754 floating point numbers + // See: + // Because of this, we just loop 'until' we get a valid result where 0.0 <= x < 1.0: + if (random_uniform_result === 1.0) { + return random_uniform(); + } + return random_uniform_result; +} + +export function bit_array_slice(bits, position, length) { + const start = Math.min(position, position + length); + const end = Math.max(position, position + length); + + if (start < 0 || end * 8 > bits.bitSize) { + return new Error(Nil); + } + + return new Ok(bitArraySlice(bits, start * 8, end * 8)); +} + +export function codepoint(int) { + return new UtfCodepoint(int); +} + +export function string_to_codepoint_integer_list(string) { + return List.fromArray(Array.from(string).map((item) => item.codePointAt(0))); +} + +export function utf_codepoint_list_to_string(utf_codepoint_integer_list) { + return utf_codepoint_integer_list + .toArray() + .map((x) => String.fromCodePoint(x.value)) + .join(""); +} + +export function utf_codepoint_to_int(utf_codepoint) { + return utf_codepoint.value; +} + +export function new_map() { + return Dict.new(); +} + +export function map_size(map) { + return map.size; +} + +export function map_to_list(map) { + return List.fromArray(map.entries()); +} + +export function map_remove(key, map) { + return map.delete(key); +} + +export function map_get(map, key) { + const value = map.get(key, NOT_FOUND); + if (value === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value); +} + +export function map_insert(key, value, map) { + return map.set(key, value); +} + +function unsafe_percent_decode(string) { + return decodeURIComponent(string || ""); +} + +function unsafe_percent_decode_query(string) { + return decodeURIComponent((string || "").replace("+", " ")); +} + +export function percent_decode(string) { + try { + return new Ok(unsafe_percent_decode(string)); + } catch { + return new Error(Nil); + } +} + +export function percent_encode(string) { + return encodeURIComponent(string).replace("%2B", "+"); +} + +export function parse_query(query) { + try { + const pairs = []; + for (const section of query.split("&")) { + const [key, value] = section.split("="); + if (!key) continue; + + const decodedKey = unsafe_percent_decode_query(key); + const decodedValue = unsafe_percent_decode_query(value); + pairs.push([decodedKey, decodedValue]); + } + return new Ok(List.fromArray(pairs)); + } catch { + return new Error(Nil); + } +} + +const b64EncodeLookup = [ + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, +]; + +let b64TextDecoder; + +// Implementation based on https://github.com/mitschabaude/fast-base64/blob/main/js.js +export function encode64(bit_array, padding) { + b64TextDecoder ??= new TextDecoder(); + + bit_array = bit_array_pad_to_bytes(bit_array); + + const m = bit_array.byteSize; + const k = m % 3; + const n = Math.floor(m / 3) * 4 + (k && k + 1); + const N = Math.ceil(m / 3) * 4; + const encoded = new Uint8Array(N); + + for (let i = 0, j = 0; j < m; i += 4, j += 3) { + const y = + (bit_array.byteAt(j) << 16) + + (bit_array.byteAt(j + 1) << 8) + + (bit_array.byteAt(j + 2) | 0); + + encoded[i] = b64EncodeLookup[y >> 18]; + encoded[i + 1] = b64EncodeLookup[(y >> 12) & 0x3f]; + encoded[i + 2] = b64EncodeLookup[(y >> 6) & 0x3f]; + encoded[i + 3] = b64EncodeLookup[y & 0x3f]; + } + + let base64 = b64TextDecoder.decode(new Uint8Array(encoded.buffer, 0, n)); + + if (padding) { + if (k === 1) { + base64 += "=="; + } else if (k === 2) { + base64 += "="; + } + } + + return base64; +} + +// From https://developer.mozilla.org/en-US/docs/Glossary/Base64 +export function decode64(sBase64) { + try { + const binString = atob(sBase64); + const length = binString.length; + const array = new Uint8Array(length); + for (let i = 0; i < length; i++) { + array[i] = binString.charCodeAt(i); + } + return new Ok(new BitArray(array)); + } catch { + return new Error(Nil); + } +} + +export function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (typeof data === "boolean") { + return "Bool"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Array`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Nil"; + } else if (data === undefined) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} + +export function byte_size(string) { + return new TextEncoder().encode(string).length; +} + +// In JavaScript bitwise operations convert numbers to a sequence of 32 bits +// while Erlang uses arbitrary precision. +// To get around this problem and get consistent results use BigInt and then +// downcast the value back to a Number value. + +export function bitwise_and(x, y) { + return Number(BigInt(x) & BigInt(y)); +} + +export function bitwise_not(x) { + return Number(~BigInt(x)); +} + +export function bitwise_or(x, y) { + return Number(BigInt(x) | BigInt(y)); +} + +export function bitwise_exclusive_or(x, y) { + return Number(BigInt(x) ^ BigInt(y)); +} + +export function bitwise_shift_left(x, y) { + return Number(BigInt(x) << BigInt(y)); +} + +export function bitwise_shift_right(x, y) { + return Number(BigInt(x) >> BigInt(y)); +} + +export function inspect(v) { + return new Inspector().inspect(v); +} + +export function float_to_string(float) { + const string = float.toString().replace("+", ""); + if (string.indexOf(".") >= 0) { + return string; + } else { + const index = string.indexOf("e"); + if (index >= 0) { + return string.slice(0, index) + ".0" + string.slice(index); + } else { + return string + ".0"; + } + } +} + +class Inspector { + #references = new Set(); + + inspect(v) { + const t = typeof v; + if (v === true) return "True"; + if (v === false) return "False"; + if (v === null) return "//js(null)"; + if (v === undefined) return "Nil"; + if (t === "string") return this.#string(v); + if (t === "bigint" || Number.isInteger(v)) return v.toString(); + if (t === "number") return float_to_string(v); + if (v instanceof UtfCodepoint) return this.#utfCodepoint(v); + if (v instanceof BitArray) return this.#bit_array(v); + if (v instanceof RegExp) return `//js(${v})`; + if (v instanceof Date) return `//js(Date("${v.toISOString()}"))`; + if (v instanceof globalThis.Error) return `//js(${v.toString()})`; + if (v instanceof Function) { + const args = []; + for (const i of Array(v.length).keys()) + args.push(String.fromCharCode(i + 97)); + return `//fn(${args.join(", ")}) { ... }`; + } + + if (this.#references.size === this.#references.add(v).size) { + return "//js(circular reference)"; + } + + let printed; + if (Array.isArray(v)) { + printed = `#(${v.map((v) => this.inspect(v)).join(", ")})`; + } else if (v instanceof List) { + printed = this.#list(v); + } else if (v instanceof CustomType) { + printed = this.#customType(v); + } else if (v instanceof Dict) { + printed = this.#dict(v); + } else if (v instanceof Set) { + return `//js(Set(${[...v].map((v) => this.inspect(v)).join(", ")}))`; + } else { + printed = this.#object(v); + } + this.#references.delete(v); + return printed; + } + + #object(v) { + const name = Object.getPrototypeOf(v)?.constructor?.name || "Object"; + const props = []; + for (const k of Object.keys(v)) { + props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); + } + const body = props.length ? " " + props.join(", ") + " " : ""; + const head = name === "Object" ? "" : name + " "; + return `//js(${head}{${body}})`; + } + + #dict(map) { + let body = "dict.from_list(["; + let first = true; + map.forEach((value, key) => { + if (!first) body = body + ", "; + body = body + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")"; + first = false; + }); + return body + "])"; + } + + #customType(record) { + const props = Object.keys(record) + .map((label) => { + const value = this.inspect(record[label]); + return isNaN(parseInt(label)) ? `${label}: ${value}` : value; + }) + .join(", "); + return props + ? `${record.constructor.name}(${props})` + : record.constructor.name; + } + + #list(list) { + if (list instanceof Empty) { + return "[]"; + } + + let char_out = 'charlist.from_string("'; + let list_out = "["; + + let current = list; + while (current instanceof NonEmpty) { + let element = current.head; + current = current.tail; + + if (list_out !== "[") { + list_out += ", "; + } + list_out += this.inspect(element); + + if (char_out) { + if (Number.isInteger(element) && element >= 32 && element <= 126) { + char_out += String.fromCharCode(element); + } else { + char_out = null; + } + } + } + + if (char_out) { + return char_out + '")'; + } else { + return list_out + "]"; + } + } + + #string(str) { + let new_str = '"'; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + switch (char) { + case "\n": + new_str += "\\n"; + break; + case "\r": + new_str += "\\r"; + break; + case "\t": + new_str += "\\t"; + break; + case "\f": + new_str += "\\f"; + break; + case "\\": + new_str += "\\\\"; + break; + case '"': + new_str += '\\"'; + break; + default: + if (char < " " || (char > "~" && char < "\u{00A0}")) { + new_str += + "\\u{" + + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + + "}"; + } else { + new_str += char; + } + } + } + new_str += '"'; + return new_str; + } + + #utfCodepoint(codepoint) { + return `//utfcodepoint(${String.fromCodePoint(codepoint.value)})`; + } + + #bit_array(bits) { + if (bits.bitSize === 0) { + return "<<>>"; + } + + let acc = "<<"; + + for (let i = 0; i < bits.byteSize - 1; i++) { + acc += bits.byteAt(i).toString(); + acc += ", "; + } + + if (bits.byteSize * 8 === bits.bitSize) { + acc += bits.byteAt(bits.byteSize - 1).toString(); + } else { + const trailingBitsCount = bits.bitSize % 8; + acc += bits.byteAt(bits.byteSize - 1) >> (8 - trailingBitsCount); + acc += `:size(${trailingBitsCount})`; + } + + acc += ">>"; + return acc; + } +} + +export function base16_encode(bit_array) { + const trailingBitsCount = bit_array.bitSize % 8; + + let result = ""; + + for (let i = 0; i < bit_array.byteSize; i++) { + let byte = bit_array.byteAt(i); + + if (i === bit_array.byteSize - 1 && trailingBitsCount !== 0) { + const unusedBitsCount = 8 - trailingBitsCount; + byte = (byte >> unusedBitsCount) << unusedBitsCount; + } + + result += byte.toString(16).padStart(2, "0").toUpperCase(); + } + + return result; +} + +export function base16_decode(string) { + const bytes = new Uint8Array(string.length / 2); + for (let i = 0; i < string.length; i += 2) { + const a = parseInt(string[i], 16); + const b = parseInt(string[i + 1], 16); + if (isNaN(a) || isNaN(b)) return new Error(Nil); + bytes[i / 2] = a * 16 + b; + } + return new Ok(new BitArray(bytes)); +} + +export function bit_array_to_int_and_size(bits) { + const trailingBitsCount = bits.bitSize % 8; + const unusedBitsCount = trailingBitsCount === 0 ? 0 : 8 - trailingBitsCount; + + return [bits.byteAt(0) >> unusedBitsCount, bits.bitSize]; +} + +export function bit_array_starts_with(bits, prefix) { + if (prefix.bitSize > bits.bitSize) { + return false; + } + + // Check any whole bytes + const byteCount = Math.trunc(prefix.bitSize / 8); + for (let i = 0; i < byteCount; i++) { + if (bits.byteAt(i) !== prefix.byteAt(i)) { + return false; + } + } + + // Check any trailing bits at the end of the prefix + if (prefix.bitSize % 8 !== 0) { + const unusedBitsCount = 8 - (prefix.bitSize % 8); + if ( + bits.byteAt(byteCount) >> unusedBitsCount !== + prefix.byteAt(byteCount) >> unusedBitsCount + ) { + return false; + } + } + + return true; +} + +export function log(x) { + // It is checked in Gleam that: + // - The input is strictly positive (x > 0) + // - This ensures that Math.log will never return NaN or -Infinity + // The function can thus safely pass the input to Math.log + // and a valid finite float will always be produced. + return Math.log(x); +} + +export function exp(x) { + return Math.exp(x); +} + +export function list_to_array(list) { + let current = list; + let array = []; + while (current instanceof NonEmpty) { + array.push(current.head); + current = current.tail; + } + return array; +} + +export function index(data, key) { + // Dictionaries and dictionary-like objects can be indexed + if (data instanceof Dict || data instanceof WeakMap || data instanceof Map) { + const token = {}; + const entry = data.get(key, token); + if (entry === token) return new Ok(new None()); + return new Ok(new Some(entry)); + } + + const key_is_int = Number.isInteger(key); + + // Only elements 0-7 of lists can be indexed, negative indices are not allowed + if (key_is_int && key >= 0 && key < 8 && data instanceof List) { + let i = 0; + for (const value of data) { + if (i === key) return new Ok(new Some(value)); + i++; + } + return new Error("Indexable"); + } + + // Arrays and objects can be indexed + if ( + (key_is_int && Array.isArray(data)) || + (data && typeof data === "object") || + (data && Object.getPrototypeOf(data) === Object.prototype) + ) { + if (key in data) return new Ok(new Some(data[key])); + return new Ok(new None()); + } + + return new Error(key_is_int ? "Indexable" : "Dict"); +} + +export function list(data, decode, pushPath, index, emptyList) { + if (!(data instanceof List || Array.isArray(data))) { + const error = new DecodeError("List", classify(data), emptyList); + return [emptyList, List.fromArray([error])]; + } + + const decoded = []; + + for (const element of data) { + const layer = decode(element); + const [out, errors] = layer; + + if (errors instanceof NonEmpty) { + const [_, errors] = pushPath(layer, index.toString()); + return [emptyList, errors]; + } + decoded.push(out); + index++; + } + + return [List.fromArray(decoded), emptyList]; +} + +export function dict(data) { + if (data instanceof Dict) { + return new Ok(data); + } + if (data instanceof Map || data instanceof WeakMap) { + return new Ok(Dict.fromMap(data)); + } + if (data == null) { + return new Error("Dict"); + } + if (typeof data !== "object") { + return new Error("Dict"); + } + const proto = Object.getPrototypeOf(data); + if (proto === Object.prototype || proto === null) { + return new Ok(Dict.fromObject(data)); + } + return new Error("Dict"); +} + +export function bit_array(data) { + if (data instanceof BitArray) return new Ok(data); + if (data instanceof Uint8Array) return new Ok(new BitArray(data)); + return new Error(new BitArray(new Uint8Array())); +} + +export function float(data) { + if (typeof data === "number") return new Ok(data); + return new Error(0.0); +} + +export function int(data) { + if (Number.isInteger(data)) return new Ok(data); + return new Error(0); +} + +export function string(data) { + if (typeof data === "string") return new Ok(data); + return new Error(""); +} + +export function is_null(data) { + return data === null || data === undefined; +} diff --git a/build/packages/gleeunit/LICENCE b/build/packages/gleeunit/LICENCE new file mode 100644 index 0000000..c7967c3 --- /dev/null +++ b/build/packages/gleeunit/LICENCE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2021, Louis Pilfold . + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/build/packages/gleeunit/README.md b/build/packages/gleeunit/README.md new file mode 100644 index 0000000..4d81364 --- /dev/null +++ b/build/packages/gleeunit/README.md @@ -0,0 +1,44 @@ +# gleeunit + +A simple test runner for Gleam, using EUnit on Erlang and a custom runner on JS. + +[![Package Version](https://img.shields.io/hexpm/v/gleeunit)](https://hex.pm/packages/gleeunit) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleeunit/) + + +```sh +gleam add gleeunit@1 --dev +``` +```gleam +// In test/yourapp_test.gleam +import gleeunit + +pub fn main() { + gleeunit.main() +} +``` + +Now any public function with a name ending in `_test` in the `test` directory +will be found and run as a test. + +```gleam +pub fn some_function_test() { + assert some_function() == "Hello!" +} +``` + +Run the tests by entering `gleam test` in the command line. + +### Deno + +If using the Deno JavaScript runtime, you will need to add the following to your +`gleam.toml`. + +```toml +[javascript.deno] +allow_read = [ + "gleam.toml", + "test", + "build", +] +``` diff --git a/build/packages/gleeunit/gleam.toml b/build/packages/gleeunit/gleam.toml new file mode 100644 index 0000000..b79d611 --- /dev/null +++ b/build/packages/gleeunit/gleam.toml @@ -0,0 +1,16 @@ +name = "gleeunit" +version = "1.6.0" +licences = ["Apache-2.0"] +description = "A simple test runner for Gleam, using EUnit on Erlang" +repository = { type = "github", user = "lpil", repo = "gleeunit" } +links = [{ title = "Sponsor", href = "https://github.com/sponsors/lpil" }] +gleam = ">= 1.11.0" + +[javascript.deno] +allow_read = ["gleam.toml", "test", "build"] + +[dependencies] +gleam_stdlib = ">= 0.60.0 and < 1.0.0" + +[dev-dependencies] +testhelper = { "path" = "./testhelper" } diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl new file mode 100644 index 0000000..9360941 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl @@ -0,0 +1,6 @@ +-record(assert, { + start :: integer(), + 'end' :: integer(), + expression_start :: integer(), + kind :: gleeunit@internal@gleam_panic:assert_kind() +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl new file mode 100644 index 0000000..812663c --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl @@ -0,0 +1,5 @@ +-record(asserted_expression, { + start :: integer(), + 'end' :: integer(), + kind :: gleeunit@internal@gleam_panic:expression_kind() +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl new file mode 100644 index 0000000..eee44c9 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl @@ -0,0 +1,5 @@ +-record(binary_operator, { + operator :: binary(), + left :: gleeunit@internal@gleam_panic:asserted_expression(), + right :: gleeunit@internal@gleam_panic:asserted_expression() +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl new file mode 100644 index 0000000..e7ffaa0 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl @@ -0,0 +1 @@ +-record(expression, {value :: gleam@dynamic:dynamic_()}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl new file mode 100644 index 0000000..9d55488 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl @@ -0,0 +1,3 @@ +-record(function_call, { + arguments :: list(gleeunit@internal@gleam_panic:asserted_expression()) +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl new file mode 100644 index 0000000..cf36764 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl @@ -0,0 +1,8 @@ +-record(gleam_panic, { + message :: binary(), + file :: binary(), + module :: binary(), + function :: binary(), + line :: integer(), + kind :: gleeunit@internal@gleam_panic:panic_kind() +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl new file mode 100644 index 0000000..11f865e --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl @@ -0,0 +1,7 @@ +-record(let_assert, { + start :: integer(), + 'end' :: integer(), + pattern_start :: integer(), + pattern_end :: integer(), + value :: gleam@dynamic:dynamic_() +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl new file mode 100644 index 0000000..2396489 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl @@ -0,0 +1 @@ +-record(literal, {value :: gleam@dynamic:dynamic_()}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl new file mode 100644 index 0000000..0424990 --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl @@ -0,0 +1,3 @@ +-record(other_expression, { + expression :: gleeunit@internal@gleam_panic:asserted_expression() +}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl b/build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl new file mode 100644 index 0000000..575ccce --- /dev/null +++ b/build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl @@ -0,0 +1 @@ +-record(state, {passed :: integer(), failed :: integer(), skipped :: integer()}). diff --git a/build/packages/gleeunit/src/gleeunit.app.src b/build/packages/gleeunit/src/gleeunit.app.src new file mode 100644 index 0000000..6d458ca --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit.app.src @@ -0,0 +1,16 @@ +{application, gleeunit, [ + {vsn, "1.6.0"}, + {applications, [gleam_stdlib]}, + {description, "A simple test runner for Gleam, using EUnit on Erlang"}, + {modules, [erlang_test_module, + gleeunit, + gleeunit@@main, + gleeunit@internal@gleam_panic, + gleeunit@internal@reporting, + gleeunit@should, + gleeunit_ffi, + gleeunit_gleam_panic_ffi, + gleeunit_progress, + gleeunit_test_ffi]}, + {registered, []} +]}. diff --git a/build/packages/gleeunit/src/gleeunit.erl b/build/packages/gleeunit/src/gleeunit.erl new file mode 100644 index 0000000..ba208f2 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit.erl @@ -0,0 +1,87 @@ +-module(gleeunit). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleeunit.gleam"). +-export([main/0]). +-export_type([atom_/0, encoding/0, report_module_name/0, gleeunit_progress_option/0, eunit_option/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 atom_() :: any(). + +-type encoding() :: utf8. + +-type report_module_name() :: gleeunit_progress. + +-type gleeunit_progress_option() :: {colored, boolean()}. + +-type eunit_option() :: verbose | + no_tty | + {report, {report_module_name(), list(gleeunit_progress_option())}}. + +-file("src/gleeunit.gleam", 37). +-spec gleam_to_erlang_module_name(binary()) -> binary(). +gleam_to_erlang_module_name(Path) -> + case gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) of + true -> + _pipe = Path, + _pipe@1 = gleam@string:replace( + _pipe, + <<".gleam"/utf8>>, + <<""/utf8>> + ), + gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"@"/utf8>>); + + false -> + _pipe@2 = Path, + _pipe@3 = gleam@string:split(_pipe@2, <<"/"/utf8>>), + _pipe@4 = gleam@list:last(_pipe@3), + _pipe@5 = gleam@result:unwrap(_pipe@4, Path), + gleam@string:replace(_pipe@5, <<".erl"/utf8>>, <<""/utf8>>) + end. + +-file("src/gleeunit.gleam", 18). +-spec do_main() -> nil. +do_main() -> + Options = [verbose, + no_tty, + {report, {gleeunit_progress, [{colored, true}]}}], + Result = begin + _pipe = gleeunit_ffi:find_files( + <<"**/*.{erl,gleam}"/utf8>>, + <<"test"/utf8>> + ), + _pipe@1 = gleam@list:map(_pipe, fun gleam_to_erlang_module_name/1), + _pipe@2 = gleam@list:map( + _pipe@1, + fun(_capture) -> erlang:binary_to_atom(_capture, utf8) end + ), + gleeunit_ffi:run_eunit(_pipe@2, Options) + end, + Code = case Result of + {ok, _} -> + 0; + + {error, _} -> + 1 + end, + erlang:halt(Code). + +-file("src/gleeunit.gleam", 13). +?DOC( + " Find and run all test functions for the current project using Erlang's EUnit\n" + " test framework, or a custom JavaScript test runner.\n" + "\n" + " Any Erlang or Gleam function in the `test` directory with a name ending in\n" + " `_test` is considered a test function and will be run.\n" + "\n" + " A test that panics is considered a failure.\n" +). +-spec main() -> nil. +main() -> + do_main(). diff --git a/build/packages/gleeunit/src/gleeunit.gleam b/build/packages/gleeunit/src/gleeunit.gleam new file mode 100644 index 0000000..4e7b3ec --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit.gleam @@ -0,0 +1,80 @@ +import gleam/list +import gleam/result +import gleam/string + +/// Find and run all test functions for the current project using Erlang's EUnit +/// test framework, or a custom JavaScript test runner. +/// +/// Any Erlang or Gleam function in the `test` directory with a name ending in +/// `_test` is considered a test function and will be run. +/// +/// A test that panics is considered a failure. +/// +pub fn main() -> Nil { + do_main() +} + +@external(javascript, "./gleeunit_ffi.mjs", "main") +fn do_main() -> Nil { + let options = [Verbose, NoTty, Report(#(GleeunitProgress, [Colored(True)]))] + + let result = + find_files(matching: "**/*.{erl,gleam}", in: "test") + |> list.map(gleam_to_erlang_module_name) + |> list.map(dangerously_convert_string_to_atom(_, Utf8)) + |> run_eunit(options) + + let code = case result { + Ok(_) -> 0 + Error(_) -> 1 + } + halt(code) +} + +@external(erlang, "erlang", "halt") +fn halt(a: Int) -> Nil + +fn gleam_to_erlang_module_name(path: String) -> String { + case string.ends_with(path, ".gleam") { + True -> + path + |> string.replace(".gleam", "") + |> string.replace("/", "@") + + False -> + path + |> string.split("/") + |> list.last + |> result.unwrap(path) + |> string.replace(".erl", "") + } +} + +@external(erlang, "gleeunit_ffi", "find_files") +fn find_files(matching matching: String, in in: String) -> List(String) + +type Atom + +type Encoding { + Utf8 +} + +@external(erlang, "erlang", "binary_to_atom") +fn dangerously_convert_string_to_atom(a: String, b: Encoding) -> Atom + +type ReportModuleName { + GleeunitProgress +} + +type GleeunitProgressOption { + Colored(Bool) +} + +type EunitOption { + Verbose + NoTty + Report(#(ReportModuleName, List(GleeunitProgressOption))) +} + +@external(erlang, "gleeunit_ffi", "run_eunit") +fn run_eunit(a: List(Atom), b: List(EunitOption)) -> Result(Nil, a) diff --git a/build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam b/build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam new file mode 100644 index 0000000..6a5d309 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam @@ -0,0 +1,49 @@ +import gleam/dynamic + +pub type GleamPanic { + GleamPanic( + message: String, + file: String, + module: String, + function: String, + line: Int, + kind: PanicKind, + ) +} + +pub type PanicKind { + Todo + Panic + LetAssert( + start: Int, + end: Int, + pattern_start: Int, + pattern_end: Int, + value: dynamic.Dynamic, + ) + Assert(start: Int, end: Int, expression_start: Int, kind: AssertKind) +} + +pub type AssertKind { + BinaryOperator( + operator: String, + left: AssertedExpression, + right: AssertedExpression, + ) + FunctionCall(arguments: List(AssertedExpression)) + OtherExpression(expression: AssertedExpression) +} + +pub type AssertedExpression { + AssertedExpression(start: Int, end: Int, kind: ExpressionKind) +} + +pub type ExpressionKind { + Literal(value: dynamic.Dynamic) + Expression(value: dynamic.Dynamic) + Unevaluated +} + +@external(erlang, "gleeunit_gleam_panic_ffi", "from_dynamic") +@external(javascript, "./gleeunit_gleam_panic_ffi.mjs", "from_dynamic") +pub fn from_dynamic(data: dynamic.Dynamic) -> Result(GleamPanic, Nil) diff --git a/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl b/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl new file mode 100644 index 0000000..d78f5e5 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl @@ -0,0 +1,49 @@ +-module(gleeunit_gleam_panic_ffi). +-export([from_dynamic/1]). + +from_dynamic(#{ + gleam_error := assert, + start := Start, + 'end' := End, + expression_start := EStart +} = E) -> + wrap(E, {assert, Start, End, EStart, assert_kind(E)}); +from_dynamic(#{ + gleam_error := let_assert, + start := Start, + 'end' := End, + pattern_start := PStart, + pattern_end := PEnd, + value := Value +} = E) -> + wrap(E, {let_assert, Start, End, PStart, PEnd, Value}); +from_dynamic(#{gleam_error := panic} = E) -> + wrap(E, panic); +from_dynamic(#{gleam_error := todo} = E) -> + wrap(E, todo); +from_dynamic(_) -> + {error, nil}. + +assert_kind(#{kind := binary_operator, left := L, right := R, operator := O}) -> + {binary_operator, atom_to_binary(O), expression(L), expression(R)}; +assert_kind(#{kind := function_call, arguments := Arguments}) -> + {function_call, lists:map(fun expression/1, Arguments)}; +assert_kind(#{kind := expression, expression := Expression}) -> + {other_expression, expression(Expression)}. + +expression(#{start := S, 'end' := E, kind := literal, value := Value}) -> + {asserted_expression, S, E, {literal, Value}}; +expression(#{start := S, 'end' := E, kind := expression, value := Value}) -> + {asserted_expression, S, E, {expression, Value}}; +expression(#{start := S, 'end' := E, kind := unevaluated}) -> + {asserted_expression, S, E, unevaluated}. + +wrap(#{ + gleam_error := _, + file := File, + message := Message, + module := Module, + function := Function, + line := Line +}, Kind) -> + {ok, {gleam_panic, Message, File, Module, Function, Line, Kind}}. diff --git a/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs b/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs new file mode 100644 index 0000000..cef7646 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs @@ -0,0 +1,91 @@ +import { Ok, Error, Empty, NonEmpty } from "../../gleam.mjs"; +import { + GleamPanic, + Todo, + Panic, + LetAssert, + Assert, + BinaryOperator, + FunctionCall, + OtherExpression, + AssertedExpression, + Literal, + Expression, + Unevaluated, +} from "./gleam_panic.mjs"; + +export function from_dynamic(error) { + if (!(error instanceof globalThis.Error) || !error.gleam_error) { + return new Error(undefined); + } + + if (error.gleam_error === "todo") { + return wrap(error, new Todo()); + } + + if (error.gleam_error === "panic") { + return wrap(error, new Panic()); + } + + if (error.gleam_error === "let_assert") { + let kind = new LetAssert( + error.start, + error.end, + error.pattern_start, + error.pattern_end, + error.value, + ); + return wrap(error, kind); + } + + if (error.gleam_error === "assert") { + let kind = new Assert( + error.start, + error.end, + error.expression_start, + assert_kind(error), + ); + return wrap(error, kind); + } + + return new Error(undefined); +} + +function assert_kind(error) { + if (error.kind == "binary_operator") { + return new BinaryOperator( + error.operator, + expression(error.left), + expression(error.right), + ); + } + + if (error.kind == "function_call") { + let list = new Empty(); + let i = error.arguments.length; + while (i--) { + list = new NonEmpty(expression(error.arguments[i]), list); + } + return new FunctionCall(list); + } + + return new OtherExpression(expression(error.expression)); +} + +function expression(data) { + const expression = new AssertedExpression(data.start, data.end, undefined); + if (data.kind == "literal") { + expression.kind = new Literal(data.value); + } else if (data.kind == "expression") { + expression.kind = new Expression(data.value); + } else { + expression.kind = new Unevaluated(); + } + return expression; +} + +function wrap(e, kind) { + return new Ok( + new GleamPanic(e.message, e.file, e.module, e.function, e.line, kind), + ); +} diff --git a/build/packages/gleeunit/src/gleeunit/internal/reporting.gleam b/build/packages/gleeunit/src/gleeunit/internal/reporting.gleam new file mode 100644 index 0000000..97c3fcb --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit/internal/reporting.gleam @@ -0,0 +1,227 @@ +import gleam/bit_array +import gleam/dynamic +import gleam/int +import gleam/io +import gleam/list +import gleam/option.{type Option} +import gleam/result +import gleam/string +import gleeunit/internal/gleam_panic.{type GleamPanic} + +pub type State { + State(passed: Int, failed: Int, skipped: Int) +} + +pub fn new_state() -> State { + State(passed: 0, failed: 0, skipped: 0) +} + +pub fn finished(state: State) -> Int { + case state { + State(passed: 0, failed: 0, skipped: 0) -> { + io.println("\nNo tests found!") + 1 + } + State(failed: 0, skipped: 0, ..) -> { + let message = "\n" <> int.to_string(state.passed) <> " tests, no failures" + io.println(green(message)) + 0 + } + State(skipped: 0, ..) -> { + let message = + "\n" + <> int.to_string(state.passed) + <> " tests, " + <> int.to_string(state.failed) + <> " failures" + io.println(red(message)) + 0 + } + State(failed: 0, ..) -> { + let message = + "\n" + <> int.to_string(state.passed) + <> " tests, 0 failures, " + <> int.to_string(state.skipped) + <> " skipped" + io.println(yellow(message)) + 1 + } + State(..) -> { + let message = + "\n" + <> int.to_string(state.passed) + <> " tests, " + <> int.to_string(state.failed) + <> " failures, " + <> " skipped" + io.println(red(message)) + 1 + } + } +} + +pub fn test_passed(state: State) -> State { + io.print(green(".")) + State(..state, passed: state.passed + 1) +} + +pub fn test_failed( + state: State, + module: String, + function: String, + error: dynamic.Dynamic, +) -> State { + let message = case gleam_panic.from_dynamic(error) { + Ok(error) -> { + let src = option.from_result(read_file(error.file)) + format_gleam_error(error, module, function, src) + } + Error(_) -> format_unknown(module, function, error) + } + + io.print("\n" <> message) + State(..state, failed: state.failed + 1) +} + +fn format_unknown( + module: String, + function: String, + error: dynamic.Dynamic, +) -> String { + string.concat([ + grey(module <> "." <> function) <> "\n", + "An unexpected error occurred:\n", + "\n", + " " <> string.inspect(error) <> "\n", + ]) +} + +fn format_gleam_error( + error: GleamPanic, + module: String, + function: String, + src: Option(BitArray), +) -> String { + let location = grey(error.file <> ":" <> int.to_string(error.line)) + + case error.kind { + gleam_panic.Panic -> { + string.concat([ + bold(red("panic")) <> " " <> location <> "\n", + cyan(" test") <> ": " <> module <> "." <> function <> "\n", + cyan(" info") <> ": " <> error.message <> "\n", + ]) + } + + gleam_panic.Todo -> { + string.concat([ + bold(yellow("todo")) <> " " <> location <> "\n", + cyan(" test") <> ": " <> module <> "." <> function <> "\n", + cyan(" info") <> ": " <> error.message <> "\n", + ]) + } + + gleam_panic.Assert(start:, end:, kind:, ..) -> { + string.concat([ + bold(red("assert")) <> " " <> location <> "\n", + cyan(" test") <> ": " <> module <> "." <> function <> "\n", + code_snippet(src, start, end), + assert_info(kind), + cyan(" info") <> ": " <> error.message <> "\n", + ]) + } + + gleam_panic.LetAssert(start:, end:, value:, ..) -> { + string.concat([ + bold(red("let assert")) <> " " <> location <> "\n", + cyan(" test") <> ": " <> module <> "." <> function <> "\n", + code_snippet(src, start, end), + cyan("value") <> ": " <> string.inspect(value) <> "\n", + cyan(" info") <> ": " <> error.message <> "\n", + ]) + } + } +} + +fn assert_info(kind: gleam_panic.AssertKind) -> String { + case kind { + gleam_panic.BinaryOperator(left:, right:, ..) -> { + string.concat([assert_value(" left", left), assert_value("right", right)]) + } + + gleam_panic.FunctionCall(arguments:) -> { + arguments + |> list.index_map(fn(e, i) { + let number = string.pad_start(int.to_string(i), 5, " ") + assert_value(number, e) + }) + |> string.concat + } + + gleam_panic.OtherExpression(..) -> "" + } +} + +fn assert_value(name: String, value: gleam_panic.AssertedExpression) -> String { + cyan(name) <> ": " <> inspect_value(value) <> "\n" +} + +fn inspect_value(value: gleam_panic.AssertedExpression) -> String { + case value.kind { + gleam_panic.Unevaluated -> grey("unevaluated") + gleam_panic.Literal(..) -> grey("literal") + gleam_panic.Expression(value:) -> string.inspect(value) + } +} + +fn code_snippet(src: Option(BitArray), start: Int, end: Int) -> String { + { + use src <- result.try(option.to_result(src, Nil)) + use snippet <- result.try(bit_array.slice(src, start, end - start)) + use snippet <- result.try(bit_array.to_string(snippet)) + let snippet = cyan(" code") <> ": " <> snippet <> "\n" + Ok(snippet) + } + |> result.unwrap("") +} + +pub fn test_skipped(state: State, module: String, function: String) -> State { + io.print("\n" <> module <> "." <> function <> yellow(" skipped")) + State(..state, skipped: state.skipped + 1) +} + +fn bold(text: String) -> String { + "\u{001b}[1m" <> text <> "\u{001b}[22m" +} + +fn cyan(text: String) -> String { + "\u{001b}[36m" <> text <> "\u{001b}[39m" +} + +fn yellow(text: String) -> String { + "\u{001b}[33m" <> text <> "\u{001b}[39m" +} + +fn green(text: String) -> String { + "\u{001b}[32m" <> text <> "\u{001b}[39m" +} + +fn red(text: String) -> String { + "\u{001b}[31m" <> text <> "\u{001b}[39m" +} + +fn grey(text: String) -> String { + "\u{001b}[90m" <> text <> "\u{001b}[39m" +} + +@external(erlang, "file", "read_file") +fn read_file(path: String) -> Result(BitArray, dynamic.Dynamic) { + case read_file_text(path) { + Ok(text) -> Ok(bit_array.from_string(text)) + Error(e) -> Error(e) + } +} + +@external(javascript, "../../gleeunit_ffi.mjs", "read_file") +fn read_file_text(path: String) -> Result(String, dynamic.Dynamic) diff --git a/build/packages/gleeunit/src/gleeunit/should.gleam b/build/packages/gleeunit/src/gleeunit/should.gleam new file mode 100644 index 0000000..11cd82b --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit/should.gleam @@ -0,0 +1,72 @@ +//// Use the `assert` keyword instead of this module. + +import gleam/option.{type Option, None, Some} +import gleam/string + +pub fn equal(a: t, b: t) -> Nil { + case a == b { + True -> Nil + _ -> + panic as string.concat([ + "\n", + string.inspect(a), + "\nshould equal\n", + string.inspect(b), + ]) + } +} + +pub fn not_equal(a: t, b: t) -> Nil { + case a != b { + True -> Nil + _ -> + panic as string.concat([ + "\n", + string.inspect(a), + "\nshould not equal\n", + string.inspect(b), + ]) + } +} + +pub fn be_ok(a: Result(a, e)) -> a { + case a { + Ok(value) -> value + _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be ok"]) + } +} + +pub fn be_error(a: Result(a, e)) -> e { + case a { + Error(error) -> error + _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be error"]) + } +} + +pub fn be_some(a: Option(a)) -> a { + case a { + Some(value) -> value + _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be some"]) + } +} + +pub fn be_none(a: Option(a)) -> Nil { + case a { + None -> Nil + _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be none"]) + } +} + +pub fn be_true(actual: Bool) -> Nil { + actual + |> equal(True) +} + +pub fn be_false(actual: Bool) -> Nil { + actual + |> equal(False) +} + +pub fn fail() -> Nil { + be_true(False) +} diff --git a/build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl b/build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl new file mode 100644 index 0000000..f6dcb97 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl @@ -0,0 +1,56 @@ +-module(gleeunit@internal@gleam_panic). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleeunit/internal/gleam_panic.gleam"). +-export([from_dynamic/1]). +-export_type([gleam_panic/0, panic_kind/0, assert_kind/0, asserted_expression/0, expression_kind/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(false). + +-type gleam_panic() :: {gleam_panic, + binary(), + binary(), + binary(), + binary(), + integer(), + panic_kind()}. + +-type panic_kind() :: todo | + panic | + {let_assert, + integer(), + integer(), + integer(), + integer(), + gleam@dynamic:dynamic_()} | + {assert, integer(), integer(), integer(), assert_kind()}. + +-type assert_kind() :: {binary_operator, + binary(), + asserted_expression(), + asserted_expression()} | + {function_call, list(asserted_expression())} | + {other_expression, asserted_expression()}. + +-type asserted_expression() :: {asserted_expression, + integer(), + integer(), + expression_kind()}. + +-type expression_kind() :: {literal, gleam@dynamic:dynamic_()} | + {expression, gleam@dynamic:dynamic_()} | + unevaluated. + +-file("src/gleeunit/internal/gleam_panic.gleam", 49). +?DOC(false). +-spec from_dynamic(gleam@dynamic:dynamic_()) -> {ok, gleam_panic()} | + {error, nil}. +from_dynamic(Data) -> + gleeunit_gleam_panic_ffi:from_dynamic(Data). diff --git a/build/packages/gleeunit/src/gleeunit@internal@reporting.erl b/build/packages/gleeunit/src/gleeunit@internal@reporting.erl new file mode 100644 index 0000000..3801515 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit@internal@reporting.erl @@ -0,0 +1,328 @@ +-module(gleeunit@internal@reporting). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleeunit/internal/reporting.gleam"). +-export([new_state/0, test_skipped/3, test_passed/1, finished/1, test_failed/4]). +-export_type([state/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(false). + +-type state() :: {state, integer(), integer(), integer()}. + +-file("src/gleeunit/internal/reporting.gleam", 15). +?DOC(false). +-spec new_state() -> state(). +new_state() -> + {state, 0, 0, 0}. + +-file("src/gleeunit/internal/reporting.gleam", 194). +?DOC(false). +-spec bold(binary()) -> binary(). +bold(Text) -> + <<<<"\x{001b}[1m"/utf8, Text/binary>>/binary, "\x{001b}[22m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 198). +?DOC(false). +-spec cyan(binary()) -> binary(). +cyan(Text) -> + <<<<"\x{001b}[36m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 178). +?DOC(false). +-spec code_snippet(gleam@option:option(bitstring()), integer(), integer()) -> binary(). +code_snippet(Src, Start, End) -> + _pipe = begin + gleam@result:'try'( + gleam@option:to_result(Src, nil), + fun(Src@1) -> + gleam@result:'try'( + gleam_stdlib:bit_array_slice(Src@1, Start, End - Start), + fun(Snippet) -> + gleam@result:'try'( + gleam@bit_array:to_string(Snippet), + fun(Snippet@1) -> + Snippet@2 = <<<<<<(cyan(<<" code"/utf8>>))/binary, + ": "/utf8>>/binary, + Snippet@1/binary>>/binary, + "\n"/utf8>>, + {ok, Snippet@2} + end + ) + end + ) + end + ) + end, + gleam@result:unwrap(_pipe, <<""/utf8>>). + +-file("src/gleeunit/internal/reporting.gleam", 202). +?DOC(false). +-spec yellow(binary()) -> binary(). +yellow(Text) -> + <<<<"\x{001b}[33m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 189). +?DOC(false). +-spec test_skipped(state(), binary(), binary()) -> state(). +test_skipped(State, Module, Function) -> + gleam_stdlib:print( + <<<<<<<<"\n"/utf8, Module/binary>>/binary, "."/utf8>>/binary, + Function/binary>>/binary, + (yellow(<<" skipped"/utf8>>))/binary>> + ), + {state, + erlang:element(2, State), + erlang:element(3, State), + erlang:element(4, State) + 1}. + +-file("src/gleeunit/internal/reporting.gleam", 206). +?DOC(false). +-spec green(binary()) -> binary(). +green(Text) -> + <<<<"\x{001b}[32m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 64). +?DOC(false). +-spec test_passed(state()) -> state(). +test_passed(State) -> + gleam_stdlib:print(green(<<"."/utf8>>)), + {state, + erlang:element(2, State) + 1, + erlang:element(3, State), + erlang:element(4, State)}. + +-file("src/gleeunit/internal/reporting.gleam", 210). +?DOC(false). +-spec red(binary()) -> binary(). +red(Text) -> + <<<<"\x{001b}[31m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 19). +?DOC(false). +-spec finished(state()) -> integer(). +finished(State) -> + case State of + {state, 0, 0, 0} -> + gleam_stdlib:println(<<"\nNo tests found!"/utf8>>), + 1; + + {state, _, 0, 0} -> + Message = <<<<"\n"/utf8, + (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, + " tests, no failures"/utf8>>, + gleam_stdlib:println(green(Message)), + 0; + + {state, _, _, 0} -> + Message@1 = <<<<<<<<"\n"/utf8, + (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, + " tests, "/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, + " failures"/utf8>>, + gleam_stdlib:println(red(Message@1)), + 0; + + {state, _, 0, _} -> + Message@2 = <<<<<<<<"\n"/utf8, + (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, + " tests, 0 failures, "/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(4, State)))/binary>>/binary, + " skipped"/utf8>>, + gleam_stdlib:println(yellow(Message@2)), + 1; + + {state, _, _, _} -> + Message@3 = <<<<<<<<<<"\n"/utf8, + (erlang:integer_to_binary( + erlang:element(2, State) + ))/binary>>/binary, + " tests, "/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, + " failures, "/utf8>>/binary, + " skipped"/utf8>>, + gleam_stdlib:println(red(Message@3)), + 1 + end. + +-file("src/gleeunit/internal/reporting.gleam", 214). +?DOC(false). +-spec grey(binary()) -> binary(). +grey(Text) -> + <<<<"\x{001b}[90m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 87). +?DOC(false). +-spec format_unknown(binary(), binary(), gleam@dynamic:dynamic_()) -> binary(). +format_unknown(Module, Function, Error) -> + erlang:list_to_binary( + [<<(grey(<<<>/binary, Function/binary>>))/binary, + "\n"/utf8>>, + <<"An unexpected error occurred:\n"/utf8>>, + <<"\n"/utf8>>, + <<<<" "/utf8, (gleam@string:inspect(Error))/binary>>/binary, + "\n"/utf8>>] + ). + +-file("src/gleeunit/internal/reporting.gleam", 170). +?DOC(false). +-spec inspect_value(gleeunit@internal@gleam_panic:asserted_expression()) -> binary(). +inspect_value(Value) -> + case erlang:element(4, Value) of + unevaluated -> + grey(<<"unevaluated"/utf8>>); + + {literal, _} -> + grey(<<"literal"/utf8>>); + + {expression, Value@1} -> + gleam@string:inspect(Value@1) + end. + +-file("src/gleeunit/internal/reporting.gleam", 166). +?DOC(false). +-spec assert_value( + binary(), + gleeunit@internal@gleam_panic:asserted_expression() +) -> binary(). +assert_value(Name, Value) -> + <<<<<<(cyan(Name))/binary, ": "/utf8>>/binary, + (inspect_value(Value))/binary>>/binary, + "\n"/utf8>>. + +-file("src/gleeunit/internal/reporting.gleam", 147). +?DOC(false). +-spec assert_info(gleeunit@internal@gleam_panic:assert_kind()) -> binary(). +assert_info(Kind) -> + case Kind of + {binary_operator, _, Left, Right} -> + erlang:list_to_binary( + [assert_value(<<" left"/utf8>>, Left), + assert_value(<<"right"/utf8>>, Right)] + ); + + {function_call, Arguments} -> + _pipe = Arguments, + _pipe@1 = gleam@list:index_map( + _pipe, + fun(E, I) -> + Number = gleam@string:pad_start( + erlang:integer_to_binary(I), + 5, + <<" "/utf8>> + ), + assert_value(Number, E) + end + ), + erlang:list_to_binary(_pipe@1); + + {other_expression, _} -> + <<""/utf8>> + end. + +-file("src/gleeunit/internal/reporting.gleam", 100). +?DOC(false). +-spec format_gleam_error( + gleeunit@internal@gleam_panic:gleam_panic(), + binary(), + binary(), + gleam@option:option(bitstring()) +) -> binary(). +format_gleam_error(Error, Module, Function, Src) -> + Location = grey( + <<<<(erlang:element(3, Error))/binary, ":"/utf8>>/binary, + (erlang:integer_to_binary(erlang:element(6, Error)))/binary>> + ), + case erlang:element(7, Error) of + panic -> + erlang:list_to_binary( + [<<<<<<(bold(red(<<"panic"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ); + + todo -> + erlang:list_to_binary( + [<<<<<<(bold(yellow(<<"todo"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ); + + {assert, Start, End, _, Kind} -> + erlang:list_to_binary( + [<<<<<<(bold(red(<<"assert"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + code_snippet(Src, Start, End), + assert_info(Kind), + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ); + + {let_assert, Start@1, End@1, _, _, Value} -> + erlang:list_to_binary( + [<<<<<<(bold(red(<<"let assert"/utf8>>)))/binary, " "/utf8>>/binary, + Location/binary>>/binary, + "\n"/utf8>>, + <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, + Module/binary>>/binary, + "."/utf8>>/binary, + Function/binary>>/binary, + "\n"/utf8>>, + code_snippet(Src, Start@1, End@1), + <<<<<<(cyan(<<"value"/utf8>>))/binary, ": "/utf8>>/binary, + (gleam@string:inspect(Value))/binary>>/binary, + "\n"/utf8>>, + <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, + (erlang:element(2, Error))/binary>>/binary, + "\n"/utf8>>] + ) + end. + +-file("src/gleeunit/internal/reporting.gleam", 69). +?DOC(false). +-spec test_failed(state(), binary(), binary(), gleam@dynamic:dynamic_()) -> state(). +test_failed(State, Module, Function, Error) -> + Message = case gleeunit_gleam_panic_ffi:from_dynamic(Error) of + {ok, Error@1} -> + Src = gleam@option:from_result( + file:read_file(erlang:element(3, Error@1)) + ), + format_gleam_error(Error@1, Module, Function, Src); + + {error, _} -> + format_unknown(Module, Function, Error) + end, + gleam_stdlib:print(<<"\n"/utf8, Message/binary>>), + {state, + erlang:element(2, State), + erlang:element(3, State) + 1, + erlang:element(4, State)}. diff --git a/build/packages/gleeunit/src/gleeunit@should.erl b/build/packages/gleeunit/src/gleeunit@should.erl new file mode 100644 index 0000000..736f31a --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit@should.erl @@ -0,0 +1,153 @@ +-module(gleeunit@should). +-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). +-define(FILEPATH, "src/gleeunit/should.gleam"). +-export([equal/2, not_equal/2, be_ok/1, be_error/1, be_some/1, be_none/1, be_true/1, be_false/1, fail/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(" Use the `assert` keyword instead of this module.\n"). + +-file("src/gleeunit/should.gleam", 6). +-spec equal(DRY, DRY) -> nil. +equal(A, B) -> + case A =:= B of + true -> + nil; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould equal\n"/utf8>>, + gleam@string:inspect(B)] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"equal"/utf8>>, + line => 10}) + end. + +-file("src/gleeunit/should.gleam", 19). +-spec not_equal(DRZ, DRZ) -> nil. +not_equal(A, B) -> + case A /= B of + true -> + nil; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould not equal\n"/utf8>>, + gleam@string:inspect(B)] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"not_equal"/utf8>>, + line => 23}) + end. + +-file("src/gleeunit/should.gleam", 32). +-spec be_ok({ok, DSA} | {error, any()}) -> DSA. +be_ok(A) -> + case A of + {ok, Value} -> + Value; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be ok"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_ok"/utf8>>, + line => 35}) + end. + +-file("src/gleeunit/should.gleam", 39). +-spec be_error({ok, any()} | {error, DSF}) -> DSF. +be_error(A) -> + case A of + {error, Error} -> + Error; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be error"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_error"/utf8>>, + line => 42}) + end. + +-file("src/gleeunit/should.gleam", 46). +-spec be_some(gleam@option:option(DSI)) -> DSI. +be_some(A) -> + case A of + {some, Value} -> + Value; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be some"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_some"/utf8>>, + line => 49}) + end. + +-file("src/gleeunit/should.gleam", 53). +-spec be_none(gleam@option:option(any())) -> nil. +be_none(A) -> + case A of + none -> + nil; + + _ -> + erlang:error(#{gleam_error => panic, + message => erlang:list_to_binary( + [<<"\n"/utf8>>, + gleam@string:inspect(A), + <<"\nshould be none"/utf8>>] + ), + file => <>, + module => <<"gleeunit/should"/utf8>>, + function => <<"be_none"/utf8>>, + line => 56}) + end. + +-file("src/gleeunit/should.gleam", 60). +-spec be_true(boolean()) -> nil. +be_true(Actual) -> + _pipe = Actual, + equal(_pipe, true). + +-file("src/gleeunit/should.gleam", 65). +-spec be_false(boolean()) -> nil. +be_false(Actual) -> + _pipe = Actual, + equal(_pipe, false). + +-file("src/gleeunit/should.gleam", 70). +-spec fail() -> nil. +fail() -> + be_true(false). diff --git a/build/packages/gleeunit/src/gleeunit_ffi.erl b/build/packages/gleeunit/src/gleeunit_ffi.erl new file mode 100644 index 0000000..29b9553 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit_ffi.erl @@ -0,0 +1,14 @@ +-module(gleeunit_ffi). + +-export([find_files/2, run_eunit/2]). + +find_files(Pattern, In) -> + Results = filelib:wildcard(binary_to_list(Pattern), binary_to_list(In)), + lists:map(fun list_to_binary/1, Results). + +run_eunit(Tests, Options) -> + case eunit:test({timeout, 60, Tests}, Options) of + ok -> {ok, nil}; + error -> {error, nil}; + {error, Term} -> {error, Term} + end. diff --git a/build/packages/gleeunit/src/gleeunit_ffi.mjs b/build/packages/gleeunit/src/gleeunit_ffi.mjs new file mode 100644 index 0000000..ea7e301 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit_ffi.mjs @@ -0,0 +1,100 @@ +import { readFileSync } from "node:fs"; +import { Ok, Error as GleamError } from "./gleam.mjs"; +import * as reporting from "./gleeunit/internal/reporting.mjs"; + +export function read_file(path) { + try { + return new Ok(readFileSync(path)); + } catch { + return new GleamError(undefined); + } +} + +async function* gleamFiles(directory) { + for (let entry of await read_dir(directory)) { + let path = join_path(directory, entry); + if (path.endsWith(".gleam")) { + yield path; + } else { + try { + yield* gleamFiles(path); + } catch (error) { + // Could not read directory, assume it's a file + } + } + } +} + +async function readRootPackageName() { + let toml = await async_read_file("gleam.toml", "utf-8"); + for (let line of toml.split("\n")) { + let matches = line.match(/\s*name\s*=\s*"([a-z][a-z0-9_]*)"/); // Match regexp in compiler-cli/src/new.rs in validate_name() + if (matches) return matches[1]; + } + throw new Error("Could not determine package name from gleam.toml"); +} + +export async function main() { + let state = reporting.new_state(); + + let packageName = await readRootPackageName(); + let dist = `../${packageName}/`; + + for await (let path of await gleamFiles("test")) { + let js_path = path.slice("test/".length).replace(".gleam", ".mjs"); + let module = await import(join_path(dist, js_path)); + for (let fnName of Object.keys(module)) { + if (!fnName.endsWith("_test")) continue; + try { + await module[fnName](); + state = reporting.test_passed(state); + } catch (error) { + let moduleName = js_path.slice(0, -4); + state = reporting.test_failed(state, moduleName, fnName, error); + } + } + } + + const status = reporting.finished(state); + exit(status); +} + +export function crash(message) { + throw new Error(message); +} + +function exit(code) { + if (globalThis.Deno) { + Deno.exit(code); + } else { + process.exit(code); + } +} + +async function read_dir(path) { + if (globalThis.Deno) { + let items = []; + for await (let item of Deno.readDir(path, { withFileTypes: true })) { + items.push(item.name); + } + return items; + } else { + let { readdir } = await import("node:fs/promises"); + return readdir(path); + } +} + +function join_path(a, b) { + if (a.endsWith("/")) return a + b; + return a + "/" + b; +} + +async function async_read_file(path) { + if (globalThis.Deno) { + return Deno.readTextFile(path); + } else { + let { readFile } = await import("node:fs/promises"); + let contents = await readFile(path); + return contents.toString(); + } +} diff --git a/build/packages/gleeunit/src/gleeunit_progress.erl b/build/packages/gleeunit/src/gleeunit_progress.erl new file mode 100644 index 0000000..2883008 --- /dev/null +++ b/build/packages/gleeunit/src/gleeunit_progress.erl @@ -0,0 +1,74 @@ +%% A formatter adapted from Sean Cribb's https://github.com/seancribbs/eunit_formatters + +-module(gleeunit_progress). +-behaviour(eunit_listener). +-define(NOTEST, true). +-include_lib("eunit/include/eunit.hrl"). + +%% eunit_listener callbacks +-export([ + init/1, handle_begin/3, handle_end/3, handle_cancel/3, terminate/2, + start/0, start/1 +]). + +-define(reporting, gleeunit@internal@reporting). + +start() -> + start([]). + +start(Options) -> + eunit_listener:start(?MODULE, Options). + +init(_Options) -> + ?reporting:new_state(). + +handle_begin(_test_or_group, _data, State) -> + State. + +handle_end(group, _data, State) -> + State; +handle_end(test, Data, State) -> + {AtomModule, AtomFunction, _Arity} = proplists:get_value(source, Data), + Module = erlang:atom_to_binary(AtomModule), + Function = erlang:atom_to_binary(AtomFunction), + + % EUnit swallows stdout, so print it to make debugging easier. + case proplists:get_value(output, Data) of + undefined -> ok; + <<>> -> ok; + Out -> gleam@io:print(Out) + end, + + case proplists:get_value(status, Data) of + ok -> + ?reporting:test_passed(State); + {skipped, _Reason} -> + ?reporting:test_skipped(State, Module, Function); + {error, {_, Exception, _Stack}} -> + ?reporting:test_failed(State, Module, Function, Exception) + end. + + +handle_cancel(_test_or_group, Data, State) -> + ?reporting:test_failed(State, <<"gleeunit">>, <<"main">>, Data). + +terminate({ok, _Data}, State) -> + ?reporting:finished(State), + ok; +terminate({error, Reason}, State) -> + ?reporting:finished(State), + io:fwrite(" +Eunit failed: + +~80p + +This is probably a bug in gleeunit. Please report it. +", [Reason]), + sync_end(error). + +sync_end(Result) -> + receive + {stop, Reference, ReplyTo} -> + ReplyTo ! {result, Reference, Result}, + ok + end. diff --git a/build/packages/packages.toml b/build/packages/packages.toml new file mode 100644 index 0000000..ab102e0 --- /dev/null +++ b/build/packages/packages.toml @@ -0,0 +1,3 @@ +[packages] +gleam_stdlib = "0.62.0" +gleeunit = "1.6.0" diff --git a/gleam.toml b/gleam.toml new file mode 100644 index 0000000..b9812d0 --- /dev/null +++ b/gleam.toml @@ -0,0 +1,10 @@ +name = "aprsme" +version = "0.2.0" +description = "APRS packet display with type-safe Gleam modules" +licences = ["GPL-2.0"] + +[dependencies] +gleam_stdlib = ">= 0.60.0 and < 1.0.0" + +[dev-dependencies] +gleeunit = "~> 1.0" \ No newline at end of file diff --git a/lib/aprsme/encoding_utils.ex b/lib/aprsme/encoding_utils.ex index ff29805..142d7bd 100644 --- a/lib/aprsme/encoding_utils.ex +++ b/lib/aprsme/encoding_utils.ex @@ -1,14 +1,20 @@ defmodule Aprsme.EncodingUtils do @moduledoc """ - Utilities for handling encoding issues in APRS packet data. - - APRS packets can contain arbitrary bytes that may not be valid UTF-8, - which causes issues when trying to JSON encode the data for transmission - to web clients. + Elixir wrapper for the Gleam encoding utilities. + Provides a compatible API with the original EncodingUtils module. """ alias Aprs.Types.MicE + # The Gleam module is compiled with @ separator in the beam name + @gleam_module :aprsme@encoding + + # Optional compile-time check to suppress warnings + @compile {:no_warn_undefined, {@gleam_module, :sanitize_string, 1}} + @compile {:no_warn_undefined, {@gleam_module, :to_float_safe, 1}} + @compile {:no_warn_undefined, {@gleam_module, :to_hex, 1}} + @compile {:no_warn_undefined, {@gleam_module, :encoding_info, 1}} + @doc """ Sanitizes a binary to ensure it can be safely JSON encoded. @@ -20,64 +26,13 @@ defmodule Aprsme.EncodingUtils do iex> Aprsme.EncodingUtils.sanitize_string("Hello World") "Hello World" - + iex> Aprsme.EncodingUtils.sanitize_string(<<72, 101, 108, 108, 111, 211, 87, 111, 114, 108, 100>>) "HelloÓWorld" """ @spec sanitize_string(binary() | nil | any()) :: binary() | nil | any() def sanitize_string(binary) when is_binary(binary) do - # First, handle the encoding conversion - cleaned = - if String.valid?(binary) do - binary - else - case :unicode.characters_to_binary(binary, :latin1, :utf8) do - {:error, _, _} -> - # If conversion fails, try to extract valid parts - binary - |> :binary.bin_to_list() - |> Enum.filter(fn byte -> byte >= 32 and byte <= 126 end) - |> :binary.list_to_bin() - - {:incomplete, partial, _} -> - partial - - result when is_binary(result) -> - result - end - end - - # Remove control characters including null bytes - # We filter at the codepoint level to handle all Unicode control characters - cleaned - |> String.codepoints() - |> Enum.filter(fn cp -> - case :unicode.characters_to_list(cp) do - [codepoint] -> - # Allow printable characters and common whitespace - # Remove C0 controls (0x00-0x1F except tab, newline, carriage return) - # Remove C1 controls (0x80-0x9F) - # Remove DEL (0x7F) - cond do - # Tab - codepoint == 0x09 -> true - # Newline - codepoint == 0x0A -> true - # Carriage return - codepoint == 0x0D -> true - codepoint >= 0x00 and codepoint <= 0x1F -> false - codepoint == 0x7F -> false - codepoint >= 0x80 and codepoint <= 0x9F -> false - true -> true - end - - _ -> - # Multi-codepoint grapheme, keep it - true - end - end) - |> Enum.join() - |> String.trim() + @gleam_module.sanitize_string(binary) end def sanitize_string(nil), do: nil @@ -105,35 +60,26 @@ defmodule Aprsme.EncodingUtils do end def to_float(value) when is_integer(value) do - # Protect against integer overflow when converting to float if value >= -9.0e15 and value <= 9.0e15 do value * 1.0 end end + def to_float(value) when is_binary(value) do + # Sanitize and use Gleam's safe conversion + sanitized = value |> sanitize_string() |> to_string() + + case @gleam_module.to_float_safe(sanitized) do + {:some, f} -> f + :none -> nil + end + end + def to_float(%Decimal{} = value) do float = Decimal.to_float(value) if finite_float?(float), do: float end - def to_float(value) when is_binary(value) do - # Sanitize input first to prevent injection attacks - sanitized = - value - |> sanitize_string() - |> to_string() - # Reasonable max length for a number - |> String.slice(0, 30) - - case Float.parse(sanitized) do - {float, _} when is_float(float) -> - if finite_float?(float), do: float - - :error -> - nil - end - end - def to_float(_), do: nil # Helper to check if a float is finite (not infinity or NaN) @@ -383,8 +329,6 @@ defmodule Aprsme.EncodingUtils do defp sanitize_map_value(val) when is_binary(val), do: sanitize_string(val) defp sanitize_map_value(val), do: val - # Private helper functions - @doc """ Converts a binary to a hex string representation for debugging. @@ -395,11 +339,7 @@ defmodule Aprsme.EncodingUtils do """ @spec to_hex(binary()) :: String.t() def to_hex(binary) when is_binary(binary) do - binary - |> :binary.bin_to_list() - |> Enum.map(&Integer.to_string(&1, 16)) - |> Enum.map_join("", &String.pad_leading(&1, 2, "0")) - |> String.upcase() + @gleam_module.to_hex(binary) end @doc """ @@ -414,37 +354,27 @@ defmodule Aprsme.EncodingUtils do """ @spec encoding_info(binary()) :: map() def encoding_info(binary) when is_binary(binary) do - valid = String.valid?(binary) - byte_count = byte_size(binary) + # Call Gleam function and convert the result + case @gleam_module.encoding_info(binary) do + {:encoding_info, valid_utf8, byte_count, char_count, invalid_at} -> + base = %{ + valid_utf8: valid_utf8, + byte_count: byte_count + } - base_info = %{ - valid_utf8: valid, - byte_count: byte_count - } + base + |> maybe_add_field(:char_count, char_count) + |> maybe_add_field(:invalid_at, invalid_at) - add_encoding_details(base_info, binary, valid) - end - - defp add_encoding_details(base_info, binary, true) do - Map.put(base_info, :char_count, String.length(binary)) - end - - defp add_encoding_details(base_info, binary, false) do - # Try to find where the invalid sequence starts - invalid_at = find_invalid_byte_position(binary, 0) - Map.put(base_info, :invalid_at, invalid_at) - end - - @spec find_invalid_byte_position(binary(), non_neg_integer()) :: non_neg_integer() | nil - defp find_invalid_byte_position(<<>>, _pos), do: nil - - defp find_invalid_byte_position(<>, pos) do - if String.valid?(head) do - find_invalid_byte_position(tail, pos + 1) - else - pos + _ -> + # Fallback + %{ + valid_utf8: String.valid?(binary), + byte_count: byte_size(binary) + } end end - defp find_invalid_byte_position(_, pos), do: pos + defp maybe_add_field(map, _key, :none), do: map + defp maybe_add_field(map, key, {:some, value}), do: Map.put(map, key, value) end diff --git a/lib/mix/tasks/gleam_compile.ex b/lib/mix/tasks/gleam_compile.ex new file mode 100644 index 0000000..170360c --- /dev/null +++ b/lib/mix/tasks/gleam_compile.ex @@ -0,0 +1,99 @@ +defmodule Mix.Tasks.GleamCompile do + use Mix.Task + + @shortdoc "Compiles Gleam files and copies them to the correct location" + + def run(_args) do + env = Mix.env() + + # Check if compile.gleam task exists + task_exists = Code.ensure_loaded?(Mix.Tasks.Compile.Gleam) + + if task_exists do + # First run the gleam compiler + Mix.Task.run("compile.gleam") + + # Ensure output directory exists + ebin_dir = "_build/#{env}/lib/aprsme/ebin" + File.mkdir_p!(ebin_dir) + + # Copy beam files from Gleam build to Elixir build + gleam_output = "build/#{env}/erlang/aprsme/_gleam_artefacts" + + if File.exists?(gleam_output) do + gleam_output + |> File.ls!() + |> Enum.filter(&String.ends_with?(&1, ".beam")) + |> Enum.each(fn beam_file -> + src = Path.join(gleam_output, beam_file) + dest = Path.join(ebin_dir, beam_file) + File.copy!(src, dest) + Mix.shell().info("Copied #{beam_file}") + end) + end + else + Mix.shell().info("Gleam compiler not available, compiling manually") + + # Compile Gleam files manually using gleam binary if available + if System.find_executable("gleam") do + Mix.shell().info("Found gleam binary, compiling...") + {output, _exit_code} = System.cmd("gleam", ["build"], cd: File.cwd!()) + Mix.shell().info(output) + + # Copy from gleam build to elixir build + # Gleam always builds to dev directory regardless of MIX_ENV + # The compiled files go to the project's ebin directory + gleam_output = "build/dev/erlang/aprsme/ebin" + ebin_dir = "_build/#{env}/lib/aprsme/ebin" + File.mkdir_p!(ebin_dir) + + # First, check if compile.gleam already created the aprsme@encoding.beam + dev_ebin = "_build/dev/lib/aprsme/ebin" + if File.exists?(Path.join(dev_ebin, "aprsme@encoding.beam")) do + Mix.shell().info("Found pre-compiled aprsme@encoding.beam") + src = Path.join(dev_ebin, "aprsme@encoding.beam") + dest = Path.join(ebin_dir, "aprsme@encoding.beam") + File.copy!(src, dest) + Mix.shell().info("Copied aprsme@encoding.beam to test build") + end + + if File.exists?(gleam_output) do + Mix.shell().info("Checking #{gleam_output} for beam files...") + beam_files = gleam_output + |> File.ls!() + |> Enum.filter(&String.ends_with?(&1, ".beam")) + + Mix.shell().info("Found #{length(beam_files)} beam files") + + Enum.each(beam_files, fn beam_file -> + src = Path.join(gleam_output, beam_file) + dest = Path.join(ebin_dir, beam_file) + File.copy!(src, dest) + Mix.shell().info("Copied #{beam_file} to #{dest}") + end) + else + Mix.shell().info("Gleam output directory #{gleam_output} does not exist") + end + else + # Last resort: try to copy from dev build if available + dev_ebin = "_build/dev/lib/aprsme/ebin" + test_ebin = "_build/#{env}/lib/aprsme/ebin" + + if File.exists?(dev_ebin) and env != :dev do + File.mkdir_p!(test_ebin) + + dev_ebin + |> File.ls!() + |> Enum.filter(&String.starts_with?(&1, "aprs@")) + |> Enum.each(fn beam_file -> + src = Path.join(dev_ebin, beam_file) + dest = Path.join(test_ebin, beam_file) + File.copy!(src, dest) + end) + end + end + end + + :ok + end +end \ No newline at end of file diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000..aaba84d --- /dev/null +++ b/manifest.toml @@ -0,0 +1,11 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "gleam_stdlib", version = "0.62.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "DC8872BC0B8550F6E22F0F698CFE7F1E4BDA7312FDEB40D6C3F44C5B706C8310" }, + { name = "gleeunit", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "63022D81C12C17B7F1A60E029964E830A4CBD846BBC6740004FC1F1031AE0326" }, +] + +[requirements] +gleam_stdlib = { version = ">= 0.60.0 and < 1.0.0" } +gleeunit = { version = "~> 1.0" } diff --git a/mix.exs b/mix.exs index 3c7502a..1c06527 100644 --- a/mix.exs +++ b/mix.exs @@ -6,7 +6,11 @@ defmodule Aprsme.MixProject do app: :aprsme, version: "0.2.0", elixir: "~> 1.17", + archives: [mix_gleam: "~> 0.6"], + compilers: Mix.compilers(), elixirc_paths: elixirc_paths(Mix.env()), + erlc_paths: erlc_paths(Mix.env()), + erlc_include_path: "build/#{Mix.env()}/erlang/aprsme/include", start_permanent: Mix.env() == :prod, aliases: aliases(), deps: deps(), @@ -45,6 +49,11 @@ defmodule Aprsme.MixProject do defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] + # Specifies erlc paths per environment for Gleam compilation + defp erlc_paths(env) do + ["build/#{env}/erlang/aprsme/_gleam_artefacts", "src"] + end + # Specifies your project dependencies. # # Type `mix help deps` for examples and options. @@ -97,7 +106,10 @@ defmodule Aprsme.MixProject do {:httpoison, "~> 1.8"}, {:hammer, "~> 7.0"}, {:cachex, "~> 4.1"}, - {:gettext_pseudolocalize, "~> 0.1"} + {:gettext_pseudolocalize, "~> 0.1"}, + # Gleam dependencies + {:gleam_stdlib, ">= 0.60.0 and < 1.0.0", app: false, override: true}, + {:gleeunit, "~> 1.0", only: [:dev, :test], runtime: false, app: false} ] end @@ -109,10 +121,11 @@ defmodule Aprsme.MixProject do # See the documentation for `Mix` for more info on aliases. defp aliases do [ - setup: ["deps.get", "ecto.setup"], + setup: ["deps.get", "ecto.setup", "gleam_compile"], + compile: ["gleam_compile", "compile"], "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.reset": ["ecto.drop", "ecto.setup"], - test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"], + test: ["gleam_compile", "ecto.create --quiet", "ecto.migrate --quiet", "test"], "assets.deploy": [ "tailwind default --minify", "esbuild default --minify", @@ -129,4 +142,5 @@ defmodule Aprsme.MixProject do # {:aprs, github: "aprsme/aprs", branch: "main"} # end end + end diff --git a/mix.lock b/mix.lock index 1d6d27e..3865ca8 100644 --- a/mix.lock +++ b/mix.lock @@ -32,6 +32,8 @@ "geocalc": {:hex, :geocalc, "0.8.5", "b9886679e44c323e5b72dcd90a64f834d775d2600af0b656ea9f07ccdacaa5a6", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3870c25c78513ec0456b69324c2be1af2202961002e81fb659559e3db162c802"}, "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"}, "gettext_pseudolocalize": {:hex, :gettext_pseudolocalize, "0.1.1", "0bdc33fa12cb2297fe020a44f5548c10ac789e325638ba4ac206119f2aa78caa", [:mix], [{:expo, "~> 1.1", [hex: :expo, repo: "hexpm", optional: false]}, {:gettext, "~> 0.26", [hex: :gettext, repo: "hexpm", optional: false]}], "hexpm", "5a2d6e1732ae61d742a2ecddbf03776de3fe4a5394dce98611355b11a9f5cf49"}, + "gleam_stdlib": {:hex, :gleam_stdlib, "0.62.0", "fa055758934d307a3411a864e6afdbb14d46aff4fb1a8813a027d62f8877c506", [:gleam], [], "hexpm", "dc8872bc0b8550f6e22f0f698cfe7f1e4bda7312fdeb40d6c3f44c5b706c8310"}, + "gleeunit": {:hex, :gleeunit, "1.6.0", "b43dbd4b8ac3dbfbc7f5447166260dc11985c50d003deba02c72c3ea66a911f2", [:gleam], [{:gleam_stdlib, ">= 0.60.0 and < 1.0.0", [hex: :gleam_stdlib, repo: "hexpm", optional: false]}], "hexpm", "63022d81c12c17b7f1a60e029964e830a4cbd846bbc6740004fc1f1031ae0326"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, "gridsquare": {:hex, :gridsquare, "0.2.0", "c556a5b5101db89743264b0d728601023035863487bbe36e9e50e93839adb4d7", [:mix], [], "hexpm", "dbf0dbb484681a1e97819b0667bfeaa8c8a48cf06a54bf96a8f26ee4158ad31a"}, "hackney": {:hex, :hackney, "1.24.1", "f5205a125bba6ed4587f9db3cc7c729d11316fa8f215d3e57ed1c067a9703fa9", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "f4a7392a0b53d8bbc3eb855bdcc919cd677358e65b2afd3840b5b3690c4c8a39"}, diff --git a/priv/gleam/aprs.beam b/priv/gleam/aprs.beam new file mode 100644 index 0000000000000000000000000000000000000000..e9ae263ecd90f1df5cf5a722256315f2e57d3d14 GIT binary patch literal 716 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/aprs@encoding_simple.beam b/priv/gleam/aprs@encoding_simple.beam new file mode 100644 index 0000000000000000000000000000000000000000..5c6dcacb7f7418a4387e5936ccde71d0d9a4e27c GIT binary patch literal 3800 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 IG&1`98(}M21ONa4 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@bit_array.beam b/priv/gleam/gleam@bit_array.beam new file mode 100644 index 0000000000000000000000000000000000000000..8c245d1c481c35444018a730b6b7932ce9949463 GIT binary patch literal 13636 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 Nl4M{o{bEPP{{tzQXa4{I literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@bool.beam b/priv/gleam/gleam@bool.beam new file mode 100644 index 0000000000000000000000000000000000000000..9772739ac1805857ef755571cd2c0806ed7fb2fb GIT binary patch literal 8512 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 j6f7lcCus literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@dict.beam b/priv/gleam/gleam@dict.beam new file mode 100644 index 0000000000000000000000000000000000000000..111f01049ee17518f21fadbf70cd2cf4c6f753aa GIT binary patch literal 17092 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 Dw(H-_ literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@dynamic.beam b/priv/gleam/gleam@dynamic.beam new file mode 100644 index 0000000000000000000000000000000000000000..e937dd83baf416e33f901cc0afe3c080e3c94ed1 GIT binary patch literal 4840 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@dynamic@decode.beam b/priv/gleam/gleam@dynamic@decode.beam new file mode 100644 index 0000000000000000000000000000000000000000..abb9420f8dd97768283951efa9b22d362d166201 GIT binary patch literal 38460 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 f%93Lg9zgL4^TY3E$M`G*d7piqK?2l)96 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@function.beam b/priv/gleam/gleam@function.beam new file mode 100644 index 0000000000000000000000000000000000000000..7e99a7bbcc416a430031c7f8d7d94acf0e0c6d7f GIT binary patch literal 1816 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
s76J@)W>F@L8Ih5c{uEKgt( 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@io.beam b/priv/gleam/gleam@io.beam new file mode 100644 index 0000000000000000000000000000000000000000..a580e1b39b85102f08d6b4a4efba94d10ba8864a GIT binary patch literal 2772 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 Wrn1s+akuCn`FmZAJ|;OP=6?Yjr}Q}h literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@option.beam b/priv/gleam/gleam@option.beam new file mode 100644 index 0000000000000000000000000000000000000000..a908faca783fb588bddcc713e9143b824c5d204f GIT binary patch literal 10080 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 K3PJl53HLwDDK07i literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@order.beam b/priv/gleam/gleam@order.beam new file mode 100644 index 0000000000000000000000000000000000000000..f01954a0c5ab85d9045fb992985d09cca32122ab GIT binary patch literal 4808 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@pair.beam b/priv/gleam/gleam@pair.beam new file mode 100644 index 0000000000000000000000000000000000000000..206557e866ae760ac4f1f025f63c6c8e82174dd3 GIT binary patch literal 3668 zcmcIn2~-o;8lK6pBw=wNpml*>MFlJn#G-&GC`;wIpyKwlCQOn^GBHeIG9jV3g4TyU zTI)iMD^^g776q+4ilRk*RO<>>vDGNHh*)uf16ALh0hGFM-tnB5bN+Mh{M+2`%YXlS zCq8lFKm>6eGcs<(*b&U+Fa$wnLJu80Y(M;$CDTH3i zX@%^p)q>Ha*(pV*Flk9CMJsg(ZynEbABm$2 z!q;FCYcPNZ<1kdjy5wTr045TlE3C=TF~_RsxlaV>?(kDs#3>9o!N;w?@Z1dm z<-6g*pnVB^cPqkk&p=SVDB2wxhr@{nr@>LaXEeqs0gfR^5@VRe5|fakXUASpcu)jT zgiz29b6%W<^HD$@zfD-XXWJYOhzN=!6gGz&6oV^9hy zHX7t&uI4$7SZ1QM3eKUmj9YC|Bcsq#GO?8NloAGpR1$IqCVaJ9f}lSH94k{%5N`j> z@o;yovTVrv_L}Z`JpR)Um$KI#NLW`@ztCe}U5XMQY8@Xl(SYCGJ)2s=Z?yD`PqlQP#$4b&#f($3}OZbG~{JV-%0+7Dyyyeo3+n<7EEs1bbGY28!3^t z>^W(&405_!_E&jh%6zZnV|&*Rhh*2*pGdiO;_5y)1jprM-OyIUma%l6A!QTK(v<`q9kJ)AfZKbLH;C zJF551EIwSW=)EU>#=W!o#yHa#4PmEhs4;&Z!bBf4{R=(&->FcQ)0N zM~fTl zc@mfiyJDn%fT16xjY;7}COsQwYN>h0aWy?PwiMGEk42 zopg*|3S*?OjjAyMB@hB(+o^-vUX7XgN)s(-d!v~>p$Q&q;lZY8r=+y7C3?JWeC%N# z#C0-g=4*9wf(=vih)D!b!}Vuw9WaYuOyZ;f5R*9BU&Aed)$>T29rjNo;W0oP0Rf;R zU~>X9#i#+JCV`4dC22rv$rO@ij6qhRMFdD@moYE^g!qGD!+=lgG&x8p1U^0|a^fsRie5_^;bU@gGKWdX zuBX*a2*hF#IJ`ZI^I>ryZxGhucJo2J#dYM(^YvB9Z#-lr0K}WNs2_FQpdq;@Qt(E>B zkTcssvOVREJwd@{!gZZa!ExU*es97HdG9~h`VI6!xSTrTa%wFgcK^Tq-_7U<>z^h3 zKcQ;P{U)e^uR+0k=@^QJ-(E-@+wIzZUEt^f1$7s66?7By74#E?2nGp83StE@f(e2o b!9+pwyN?MNG$~Eb<`Y8Uz8AW@M3Dai^M}Yi literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@result.beam b/priv/gleam/gleam@result.beam new file mode 100644 index 0000000000000000000000000000000000000000..4d715681376e575caf9fd9beceff8d727e15ff78 GIT binary patch literal 15220 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@set.beam b/priv/gleam/gleam@set.beam new file mode 100644 index 0000000000000000000000000000000000000000..32dbb8fa14423ee71e277d758b2f1b3caa31b0bb GIT binary patch literal 13932 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%0D!2GawRvu=pk^!F~GHu|T{ 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleam@string.beam b/priv/gleam/gleam@string.beam new file mode 100644 index 0000000000000000000000000000000000000000..c7693e5e7b5ae993faf69f268a1abca9e0b09304 GIT binary patch literal 27684 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleeunit@internal@gleam_panic.beam b/priv/gleam/gleeunit@internal@gleam_panic.beam new file mode 100644 index 0000000000000000000000000000000000000000..0b31b711eb0d9479b66478bc890981498450a65a GIT binary patch literal 2380 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 aqHH1+5D0hz6raXrg(KN4 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleeunit_ffi.beam b/priv/gleam/gleeunit_ffi.beam new file mode 100644 index 0000000000000000000000000000000000000000..55ed2c002b90356e30386de82a06500f312db59c GIT binary patch literal 1760 zcmcgsiBl6-7~jn%giBb1h!+@-f)`1ss8~T05CJ8aTA&q6lTES-8*;hXaHwq^DIS9z z1T8ci9$r@yIv=p`PMX~+`eKWuPzW05<@7UeTo#&I03*o$br(1WmY5XZ4v;C8U0SW0cl@Y{g}tm6azVP0Q}O5R0@ScsZexN z&5Bvt%hv?j=HITMPyUu{xY1rxGCcJNj^t2I$x@Ob0N+1D51wceD-|b=gi=p}qev2r zl_o8AN2;@dNLP|_GR;iubbuOdQo&jy@B6+V3B%C9?)N?)mSQp5Qy6iiwrp@kDb@j} zgT-W}Rb(=v7RFgXs8CB2NrXYDCR2ojnYIWFq|idEgkaWy6|R18S=!GsC`TenoHrNA#SWXQmw=u9ihjFn~=ig4*mN0*6%hYEdaTjO=v zabC}B@^{aE-hQxa_jPu(D4Aa+{rT04V{2Ky+uGOkU42^kLL*!5)mv0?TDrWjM4Boe z$TR1iONex{MOV-F`{}%<`uCD&BKFLMiK(jy(UyhlIOLx%9?e<#jmx?4svcQr@qKlE zLta){!SqeqOPfb$>ZY$w-Sr?uGHR2ibp8J11JSL!e_-YBmsMYEiOSlvm>L{z&&bF+ zb#>7)Gu4*8?HAwNCAacccsI`U-tOFWzub*4?wrzJP~(M^&HB1-#wp*OHHLPJoGczV z*7Rl0*zp-Lcv!$?!Kp>vAypT;%VS6*~+{P!a?DqU>Z^C+q;3eC=JtzCMN7N;>IlR0Z zTRXEfwBSJA(Q9D`btO-OucyDRY+g{!T`^5I@kkrTOi%{}LkUsQ4fyQ|wdWsqbgT=C zzi1AvYwfS`=yjSi4c#zleq!9O`R*ML{u1^+8|b;z6LwgSjv{O*@xpj`vxr@ zb)8!qj^Dr~fvdyVo$<35T!uun!D-&aw8 zH7F_llSqkfUeWR4D-|F8;e9RPTw%z!ti?qWy|Q~9E`?}TG`_M9=Kk~jMRV32mmaIN zG2Yd^Y(jr?(uQ$?yXJBeTgN)rZ$5ebLelW$%GW4Do<0iajWWW!cO$^af_D(Smr&lP a#M+#F|IYx#rki0Ot^n{}W4XU^ME(URh)lBp literal 0 HcmV?d00001 diff --git a/priv/gleam/gleeunit_gleam_panic_ffi.beam b/priv/gleam/gleeunit_gleam_panic_ffi.beam new file mode 100644 index 0000000000000000000000000000000000000000..267a597d02c222bd898c57856e077a2232f9fd09 GIT binary patch literal 3352 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 literal 0 HcmV?d00001 diff --git a/priv/gleam/gleeunit_progress.beam b/priv/gleam/gleeunit_progress.beam new file mode 100644 index 0000000000000000000000000000000000000000..b718bf694bd8e0b850c4cda2d5c78a2a21d55df2 GIT binary patch literal 3664 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 literal 0 HcmV?d00001 diff --git a/src/aprsme/encoding.gleam b/src/aprsme/encoding.gleam new file mode 100644 index 0000000..0e37631 --- /dev/null +++ b/src/aprsme/encoding.gleam @@ -0,0 +1,212 @@ +import gleam/string +import gleam/list +import gleam/option.{type Option, None, Some} +import gleam/int +import gleam/float +import gleam/bit_array + +/// Sanitizes a binary to ensure it can be safely JSON encoded +/// Handles latin1 conversion and removes control characters +pub fn sanitize_string(input: BitArray) -> String { + // First try direct UTF-8 conversion + case bit_array.to_string(input) { + Ok(s) -> clean_control_characters(s) + Error(_) -> { + // Try latin1 to UTF-8 conversion + input + |> latin1_to_utf8_string + |> clean_control_characters + } + } +} + +/// Convert BitArray to list of bytes +fn bit_array_to_list(input: BitArray) -> List(Int) { + do_bit_array_to_list(input, []) + |> list.reverse +} + +fn do_bit_array_to_list(input: BitArray, acc: List(Int)) -> List(Int) { + case bit_array.byte_size(input) { + 0 -> acc + _ -> { + case bit_array.slice(input, at: 0, take: 1) { + Ok(<>) -> { + case bit_array.slice(input, at: 1, take: bit_array.byte_size(input) - 1) { + Ok(rest) -> do_bit_array_to_list(rest, [byte, ..acc]) + Error(_) -> [byte, ..acc] + } + } + _ -> acc + } + } + } +} + + +/// Convert latin1 encoded bytes to UTF-8 string +fn latin1_to_utf8_string(input: BitArray) -> String { + input + |> bit_array_to_list + |> list.filter_map(fn(byte) { + case byte { + // ASCII range (0-127) maps directly + b if b <= 127 -> { + case bit_array.to_string(<>) { + Ok(s) -> Ok(s) + Error(_) -> Error(Nil) + } + } + // Latin1 range (128-255) needs UTF-8 encoding + b -> { + // For Latin1, values 128-255 map to Unicode U+0080 to U+00FF + // In UTF-8, these become 2-byte sequences: 110xxxxx 10xxxxxx + let byte1 = 192 + b / 64 // 192 = 0xC0, equivalent to b >>> 6 + let byte2 = 128 + b % 64 // 128 = 0x80, equivalent to b & 0x3F + case bit_array.to_string(<>) { + Ok(s) -> Ok(s) + Error(_) -> Error(Nil) + } + } + } + }) + |> string.join("") +} + +/// Remove control characters from a string +fn clean_control_characters(s: String) -> String { + s + |> string.to_graphemes + |> list.filter(fn(grapheme) { + case string.to_utf_codepoints(grapheme) { + [codepoint] -> { + let cp = string.utf_codepoint_to_int(codepoint) + // Allow tab (0x09), newline (0x0A), carriage return (0x0D) + // Remove other control characters + case cp { + 9 -> True + 10 -> True + 13 -> True + c if c >= 0 && c <= 31 -> False + 127 -> False + c if c >= 128 && c <= 159 -> False + _ -> True + } + } + _ -> True // Multi-codepoint grapheme, keep it + } + }) + |> string.join("") + |> string.trim +} + +/// Type-safe float conversion with validation +pub fn to_float_safe(value: String) -> Option(Float) { + let sanitized = value + |> string.trim + |> string.slice(0, 30) // Reasonable max length for a number + + case float.parse(sanitized) { + Ok(f) -> { + // Check for reasonable bounds + case f { + x if x >. -9.0e15 && x <. 9.0e15 -> Some(f) + _ -> None + } + } + Error(_) -> None + } +} + +/// Convert binary to hex string +pub fn to_hex(input: BitArray) -> String { + do_to_hex(input, []) + |> list.reverse + |> string.join("") + |> string.uppercase +} + +fn do_to_hex(input: BitArray, acc: List(String)) -> List(String) { + case bit_array.slice(input, at: 0, take: 1) { + Ok(<>) -> { + let rest = case bit_array.slice(input, at: 1, take: bit_array.byte_size(input) - 1) { + Ok(r) -> r + Error(_) -> <<>> + } + let hex = int.to_base16(byte) + let padded = case string.length(hex) { + 1 -> "0" <> hex + _ -> hex + } + do_to_hex(rest, [padded, ..acc]) + } + _ -> acc + } +} + +/// Check if a value looks like it has weather data +pub fn has_weather_data(temperature: Option(Float), humidity: Option(Float), + wind_speed: Option(Float), pressure: Option(Float)) -> Bool { + case temperature, humidity, wind_speed, pressure { + Some(_), _, _, _ -> True + _, Some(_), _, _ -> True + _, _, Some(_), _ -> True + _, _, _, Some(_) -> True + _, _, _, _ -> False + } +} + +/// Encoding info for debugging +pub type EncodingInfo { + EncodingInfo( + valid_utf8: Bool, + byte_count: Int, + char_count: Option(Int), + invalid_at: Option(Int) + ) +} + +/// Get encoding information about a binary +pub fn encoding_info(input: BitArray) -> EncodingInfo { + let byte_count = bit_array.byte_size(input) + + case bit_array.to_string(input) { + Ok(s) -> EncodingInfo( + valid_utf8: True, + byte_count: byte_count, + char_count: Some(string.length(s)), + invalid_at: None + ) + Error(_) -> { + let invalid_pos = find_invalid_byte_position(input, 0) + EncodingInfo( + valid_utf8: False, + byte_count: byte_count, + char_count: None, + invalid_at: invalid_pos + ) + } + } +} + +fn find_invalid_byte_position(input: BitArray, pos: Int) -> Option(Int) { + case bit_array.byte_size(input) { + 0 -> None + _ -> { + case bit_array.slice(input, at: 0, take: 1) { + Ok(byte_slice) -> { + case bit_array.to_string(byte_slice) { + Ok(_) -> { + case bit_array.slice(input, at: 1, take: bit_array.byte_size(input) - 1) { + Ok(rest) -> find_invalid_byte_position(rest, pos + 1) + Error(_) -> Some(pos) + } + } + Error(_) -> Some(pos) + } + } + Error(_) -> Some(pos) + } + } + } +} \ No newline at end of file