aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/gleam_otp
diff options
context:
space:
mode:
Diffstat (limited to 'aoc2023/build/packages/gleam_otp')
-rw-r--r--aoc2023/build/packages/gleam_otp/LICENCE191
-rw-r--r--aoc2023/build/packages/gleam_otp/README.md91
-rw-r--r--aoc2023/build/packages/gleam_otp/gleam.toml19
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Continue.hrl4
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Ready.hrl1
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Spec.hrl5
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@intensity_tracker_IntensityTracker.hrl5
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_ChildSpec.hrl5
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_Spec.hrl6
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@system_StatusInfo.hrl7
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Exit.hrl1
-rw-r--r--aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Task.hrl6
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam/otp/actor.gleam504
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam/otp/intensity_tracker.gleam46
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam/otp/port.gleam9
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam/otp/supervisor.gleam410
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam/otp/system.gleam89
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam/otp/task.gleam151
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam@otp@actor.erl273
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam@otp@intensity_tracker.erl53
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam@otp@port.erl8
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam@otp@supervisor.erl322
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam@otp@system.erl43
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam@otp@task.erl111
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam_otp.app.src15
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam_otp.erl28
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam_otp.gleam27
-rw-r--r--aoc2023/build/packages/gleam_otp/src/gleam_otp_external.erl43
28 files changed, 0 insertions, 2473 deletions
diff --git a/aoc2023/build/packages/gleam_otp/LICENCE b/aoc2023/build/packages/gleam_otp/LICENCE
deleted file mode 100644
index 619ec77..0000000
--- a/aoc2023/build/packages/gleam_otp/LICENCE
+++ /dev/null
@@ -1,191 +0,0 @@
- 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 2019, Louis Pilfold <louis@lpil.uk>.
-
- 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/aoc2023/build/packages/gleam_otp/README.md b/aoc2023/build/packages/gleam_otp/README.md
deleted file mode 100644
index 3c313a1..0000000
--- a/aoc2023/build/packages/gleam_otp/README.md
+++ /dev/null
@@ -1,91 +0,0 @@
-# Gleam OTP
-
-<a href="https://github.com/gleam-lang/otp/releases"><img src="https://img.shields.io/github/release/gleam-lang/otp" alt="GitHub release"></a>
-<a href="https://discord.gg/Fm8Pwmy"><img src="https://img.shields.io/discord/768594524158427167?color=blue" alt="Discord chat"></a>
-![CI](https://github.com/gleam-lang/otp/workflows/test/badge.svg?branch=main)
-
-A Gleam library for building fault tolerant multi-core programs using the
-actor model. It is compatible with Erlang's OTP framework.
-
-This library is experimental and will likely have many breaking changes in the
-future!
-
-Gleam’s actor system is built with a few primary goals:
-
-- Full type safety of actors and messages.
-- Be compatible with Erlang’s OTP actor framework.
-- Provide fault tolerance and self-healing through supervisors.
-- Have equivalent performance to Erlang’s OTP.
-
-This library documents its abstractions and functionality, but you may also wish
-to read the documentation or other material on Erlang’s OTP framework to get a
-fuller understanding of OTP, the problems it solves, and and the motivations for
-its design.
-
-## Usage
-
-Add this library to your Gleam project.
-
-```shell
-gleam add gleam_otp
-```
-
-## Actor hierarchy
-
-This library provides several different types of actor that can be used in
-Gleam programs.
-
-### Process
-
-The process is the lowest level building block of OTP, all other actors are
-built on top of processes either directly or indirectly. Typically this
-abstraction would be not be used very often in Gleam applications, favour
-other actor types that provide more functionality.
-
-Gleam's process module is defined in the `gleam_erlang` library.
-
-[[Documentation]](https://hexdocs.pm/gleam_erlang/gleam/erlang/process.html)
-
-### Actor
-
-The `actor` is the most commonly used process type in Gleam and serves as a good
-building block for other abstractions. Like Erlang's `gen_server` it handles
-OTP's system messages automatically to enable OTP's debugging and tracing
-functionality.
-
-[[Documentation]](https://hexdocs.pm/gleam_otp/gleam/otp/actor.html)
-
-### Task
-
-A task is a kind of process that performs a single task and then shuts down.
-Commonly tasks are used to convert sequential code into concurrent code by
-performing computation in another process.
-
-[[Documentation]](https://hexdocs.pm/gleam_otp/gleam/otp/task.html)
-
-### Supervisor
-
-Supervisors is a process that starts and then supervises a group of processes,
-restarting them if they crash. Supervisors can start other supervisors,
-resulting in a hierarchical process structure called a supervision tree,
-providing fault tolerance to a Gleam application.
-
-[[Documentation]](https://hexdocs.pm/gleam_otp/gleam/otp/supervisor.html)
-
-## Limitations and known issues
-
-This library is experimental there are some limitations that not yet been resolved.
-
-- There is no support for named processes. They are untyped global mutable
- variables which may be uninitialized, more research is needed to find a
- suitable type safe alternative.
-- There are relatively few actor abstractions provided by this library. More
- will be added in the future.
-- Actors do not yet support all OTP system messages. Unsupported messages are
- dropped.
-- Supervisors do not yet support different shutdown periods per child. In
- practice this means that children that are supervisors do not get an
- unlimited amount of time to shut down, as is expected in Erlang or Elixir.
-- This library has not seen much testing compared to the Erlang OTP
- libraries, both in terms of unit tests and real world testing in
- applications.
diff --git a/aoc2023/build/packages/gleam_otp/gleam.toml b/aoc2023/build/packages/gleam_otp/gleam.toml
deleted file mode 100644
index 26e451b..0000000
--- a/aoc2023/build/packages/gleam_otp/gleam.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-name = "gleam_otp"
-version = "0.8.0"
-licences = ["Apache-2.0"]
-description = "Fault tolerant multicore Gleam programs with OTP"
-
-gleam = ">= 0.32.0"
-
-repository = { type = "github", user = "gleam-lang", repo = "otp" }
-links = [
- { title = "Website", href = "https://gleam.run" },
- { title = "Sponsor", href = "https://github.com/sponsors/lpil" },
-]
-
-[dependencies]
-gleam_stdlib = "~> 0.32"
-gleam_erlang = "~> 0.22"
-
-[dev-dependencies]
-gleeunit = "~> 1.0"
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Continue.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Continue.hrl
deleted file mode 100644
index 85677d1..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Continue.hrl
+++ /dev/null
@@ -1,4 +0,0 @@
--record(continue, {
- state :: any(),
- selector :: gleam@option:option(gleam@erlang@process:selector(any()))
-}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Ready.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Ready.hrl
deleted file mode 100644
index 75faa95..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Ready.hrl
+++ /dev/null
@@ -1 +0,0 @@
--record(ready, {state :: any(), selector :: gleam@erlang@process:selector(any())}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Spec.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Spec.hrl
deleted file mode 100644
index 5287439..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@actor_Spec.hrl
+++ /dev/null
@@ -1,5 +0,0 @@
--record(spec, {
- init :: fun(() -> gleam@otp@actor:init_result(any(), any())),
- init_timeout :: integer(),
- loop :: fun((any(), any()) -> gleam@otp@actor:next(any(), any()))
-}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@intensity_tracker_IntensityTracker.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@intensity_tracker_IntensityTracker.hrl
deleted file mode 100644
index 3ed0b01..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@intensity_tracker_IntensityTracker.hrl
+++ /dev/null
@@ -1,5 +0,0 @@
--record(intensity_tracker, {
- limit :: integer(),
- period :: integer(),
- events :: list(integer())
-}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_ChildSpec.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_ChildSpec.hrl
deleted file mode 100644
index 7afd07f..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_ChildSpec.hrl
+++ /dev/null
@@ -1,5 +0,0 @@
--record(child_spec, {
- start :: fun((any()) -> {ok, gleam@erlang@process:subject(any())} |
- {error, gleam@otp@actor:start_error()}),
- returning :: fun((any(), gleam@erlang@process:subject(any())) -> any())
-}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_Spec.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_Spec.hrl
deleted file mode 100644
index b10bd9f..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@supervisor_Spec.hrl
+++ /dev/null
@@ -1,6 +0,0 @@
--record(spec, {
- argument :: any(),
- max_frequency :: integer(),
- frequency_period :: integer(),
- init :: fun((gleam@otp@supervisor:children(any())) -> gleam@otp@supervisor:children(any()))
-}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@system_StatusInfo.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@system_StatusInfo.hrl
deleted file mode 100644
index 99ab4cb..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@system_StatusInfo.hrl
+++ /dev/null
@@ -1,7 +0,0 @@
--record(status_info, {
- module :: gleam@erlang@atom:atom_(),
- parent :: gleam@erlang@process:pid_(),
- mode :: gleam@otp@system:mode(),
- debug_state :: gleam@otp@system:debug_state(),
- state :: gleam@dynamic:dynamic_()
-}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Exit.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Exit.hrl
deleted file mode 100644
index 7c83874..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Exit.hrl
+++ /dev/null
@@ -1 +0,0 @@
--record(exit, {reason :: gleam@dynamic:dynamic_()}).
diff --git a/aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Task.hrl b/aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Task.hrl
deleted file mode 100644
index 959bea8..0000000
--- a/aoc2023/build/packages/gleam_otp/include/gleam@otp@task_Task.hrl
+++ /dev/null
@@ -1,6 +0,0 @@
--record(task, {
- owner :: gleam@erlang@process:pid_(),
- pid :: gleam@erlang@process:pid_(),
- monitor :: gleam@erlang@process:process_monitor(),
- selector :: gleam@erlang@process:selector(gleam@otp@task:message(any()))
-}).
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam/otp/actor.gleam b/aoc2023/build/packages/gleam_otp/src/gleam/otp/actor.gleam
deleted file mode 100644
index 9f6a6c4..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam/otp/actor.gleam
+++ /dev/null
@@ -1,504 +0,0 @@
-//// This module provides the _Actor_ abstraction, one of the most common
-//// building blocks of Gleam OTP programs.
-////
-//// An Actor is a process like any other BEAM process and can be be used to hold
-//// state, execute code, and communicate with other processes by sending and
-//// receiving messages. The advantage of using the actor abstraction over a bare
-//// process is that it provides a single interface for commonly needed
-//// functionality, including support for the [tracing and debugging
-//// features in OTP](erlang-sys).
-////
-//// Gleam's Actor is similar to Erlang's `gen_server` and Elixir's `GenServer`
-//// but differs in that it offers a fully typed interface. This different API is
-//// why Gleam uses the name Actor rather than some variation of generic-server.
-////
-//// [erlang-sys]: https://www.erlang.org/doc/man/sys.html
-////
-//// ## Example
-////
-//// An Actor can be used to create a client-server interaction between an Actor
-//// (the server) and other processes (the clients). In this example we have an
-//// Actor that works as a stack, allowing clients to push and pop elements.
-////
-//// ```gleam
-//// pub fn main() {
-//// // Start the actor with initial state of an empty list, and the
-//// // `handle_message` callback function (defined below).
-//// // We assert that it starts successfully.
-//// //
-//// // In real-world Gleam OTP programs we would likely write a wrapper functions
-//// // called `start`, `push` `pop`, `shutdown` to start and interact with the
-//// // Actor. We are not doing that here for the sake of showing how the Actor
-//// // API works.
-//// let assert Ok(actor) = actor.start([], handle_message)
-////
-//// // We can send a message to the actor to push elements onto the stack.
-//// process.send(actor, Push("Joe"))
-//// process.send(actor, Push("Mike"))
-//// process.send(actor, Push("Robert"))
-////
-//// // The `Push` message expects no response, these messages are sent purely for
-//// // the side effect of mutating the state held by the actor.
-//// //
-//// // We can also send the `Pop` message to take a value off of the actor's
-//// // stack. This message expects a response, so we use `process.call` to send a
-//// // message and wait until a reply is received.
-//// //
-//// // In this instance we are giving the actor 10 milliseconds to reply, if the
-//// // `call` function doesn't get a reply within this time it will panic and
-//// // crash the client process.
-//// let assert Ok("Robert") = process.call(actor, Pop, 10)
-//// let assert Ok("Mike") = process.call(actor, Pop, 10)
-//// let assert Ok("Joe") = process.call(actor, Pop, 10)
-////
-//// // The stack is now empty, so if we pop again the actor replies with an error.
-//// let assert Error(Nil) = process.call(actor, Pop, 10)
-////
-//// // Lastly, we can send a message to the actor asking it to shut down.
-//// process.send(actor, Shutdown)
-//// }
-//// ```
-////
-//// Here is the code that is used to implement this actor:
-////
-//// ```gleam
-//// // First step of implementing the stack Actor is to define the message type that
-//// // it can receive.
-//// //
-//// // The type of the elements in the stack is no fixed so a type parameter is used
-//// // for it instead of a concrete type such as `String` or `Int`.
-//// pub type Message(element) {
-//// // The `Shutdown` message is used to tell the actor to stop.
-//// // It is the simplest message type, it contains no data.
-//// Shutdown
-////
-//// // The `Push` message is used to add a new element to the stack.
-//// // It contains the item to add, the type of which is the `element`
-//// // parameterised type.
-//// Push(push: element)
-////
-//// // The `Pop` message is used to remove an element from the stack.
-//// // It contains a `Subject`, which is used to send the response back to the
-//// // message sender. In this case the reply is of type `Result(element, Nil)`.
-//// Pop(reply_with: Subject(Result(element, Nil)))
-//// }
-////
-//// // The last part is to implement the `handle_message` callback function.
-//// //
-//// // This function is called by the Actor each for each message it receives.
-//// // Actor is single threaded only does one thing at a time, so it handles
-//// // messages sequentially and one at a time, in the order they are received.
-//// //
-//// // The function takes the message and the current state, and returns a data
-//// // structure that indicates what to do next, along with the new state.
-//// fn handle_message(
-//// message: Message(e),
-//// stack: List(e),
-//// ) -> actor.Next(Message(e), List(e)) {
-//// case message {
-//// // For the `Shutdown` message we return the `actor.Stop` value, which causes
-//// // the actor to discard any remaining messages and stop.
-//// Shutdown -> actor.Stop(process.Normal)
-////
-//// // For the `Push` message we add the new element to the stack and return
-//// // `actor.continue` with this new stack, causing the actor to process any
-//// // queued messages or wait for more.
-//// Push(value) -> {
-//// let new_state = [value, ..stack]
-//// actor.continue(new_state)
-//// }
-////
-//// // For the `Pop` message we attempt to remove an element from the stack,
-//// // sending it or an error back to the caller, before continuing.
-//// Pop(client) ->
-//// case stack {
-//// [] -> {
-//// // When the stack is empty we can't pop an element, so we send an
-//// // error back.
-//// process.send(client, Error(Nil))
-//// actor.continue([])
-//// }
-////
-//// [first, ..rest] -> {
-//// // Otherwise we send the first element back and use the remaining
-//// // elements as the new state.
-//// process.send(client, Ok(first))
-//// actor.continue(rest)
-//// }
-//// }
-//// }
-//// }
-//// ```
-
-import gleam/erlang/process.{
- type ExitReason, type Pid, type Selector, type Subject, Abnormal,
-}
-import gleam/erlang/charlist.{type Charlist}
-import gleam/otp/system.{
- type DebugState, type Mode, type StatusInfo, type SystemMessage, GetState,
- GetStatus, Resume, Running, StatusInfo, Suspend, Suspended,
-}
-import gleam/string
-import gleam/dynamic.{type Dynamic}
-import gleam/erlang/atom
-import gleam/option.{type Option, None, Some}
-
-type Message(message) {
- /// A regular message excepted by the process
- Message(message)
-
- /// An OTP system message, for debugging or maintenance
- System(SystemMessage)
-
- /// An unexpected message
- Unexpected(Dynamic)
-}
-
-/// The type used to indicate what to do after handling a message.
-///
-pub type Next(message, state) {
- /// Continue handling messages.
- ///
- Continue(state: state, selector: Option(Selector(message)))
-
- /// Stop handling messages and shut down.
- ///
- Stop(ExitReason)
-}
-
-pub fn continue(state: state) -> Next(message, state) {
- Continue(state, None)
-}
-
-pub fn with_selector(
- value: Next(message, state),
- selector: Selector(message),
-) -> Next(message, state) {
- case value {
- Continue(state, _) -> Continue(state, Some(selector))
- _ -> value
- }
-}
-
-/// The type used to indicate whether an actor has started successfully or not.
-///
-pub type InitResult(state, message) {
- /// The actor has successfully initialised. The actor can start handling
- /// messages and actor's channel sender can be returned to the parent
- /// process.
- ///
- Ready(state: state, selector: Selector(message))
-
- /// The actor has failed to initialise. The actor shuts down and an error is
- /// returned to the parent process.
- ///
- Failed(String)
-}
-
-type Self(state, msg) {
- Self(
- mode: Mode,
- parent: Pid,
- state: state,
- subject: Subject(msg),
- selector: Selector(Message(msg)),
- debug_state: DebugState,
- message_handler: fn(msg, state) -> Next(msg, state),
- )
-}
-
-/// This data structure holds all the values required by the `start_spec`
-/// function in order to create an actor.
-///
-/// If you do not need to configure the initialisation behaviour of your actor
-/// consider using the `start` function.
-///
-pub type Spec(state, msg) {
- Spec(
- /// The initialisation functionality for the actor. This function is called
- /// just after the actor starts but before the channel sender is returned
- /// to the parent.
- ///
- /// This function is used to ensure that any required data or state is
- /// correct. If this function returns an error it means that the actor has
- /// failed to start and an error is returned to the parent.
- ///
- init: fn() -> InitResult(state, msg),
- /// How many milliseconds the `init` function has to return before it is
- /// considered to have taken too long and failed.
- ///
- init_timeout: Int,
- /// This function is called to handle each message that the actor receives.
- ///
- loop: fn(msg, state) -> Next(msg, state),
- )
-}
-
-// TODO: Check needed functionality here to be OTP compatible
-fn exit_process(reason: ExitReason) -> ExitReason {
- // TODO
- reason
-}
-
-fn receive_message(self: Self(state, msg)) -> Message(msg) {
- let selector = case self.mode {
- // When suspended we only respond to system messages
- Suspended ->
- process.new_selector()
- |> selecting_system_messages
-
- // When running we respond to all messages
- Running ->
- // We add the handler for unexpected messages first so that the user
- // supplied selector can override it if desired
- process.new_selector()
- |> process.selecting_anything(Unexpected)
- |> process.merge_selector(self.selector)
- |> selecting_system_messages
- }
-
- process.select_forever(selector)
-}
-
-fn selecting_system_messages(
- selector: Selector(Message(msg)),
-) -> Selector(Message(msg)) {
- selector
- |> process.selecting_record3(
- atom.create_from_string("system"),
- convert_system_message,
- )
-}
-
-@external(erlang, "gleam_otp_external", "convert_system_message")
-fn convert_system_message(a: Dynamic, b: Dynamic) -> Message(msg)
-
-fn process_status_info(self: Self(state, msg)) -> StatusInfo {
- StatusInfo(
- module: atom.create_from_string("gleam@otp@actor"),
- parent: self.parent,
- mode: self.mode,
- debug_state: self.debug_state,
- state: dynamic.from(self.state),
- )
-}
-
-fn loop(self: Self(state, msg)) -> ExitReason {
- case receive_message(self) {
- System(system) ->
- case system {
- GetState(callback) -> {
- callback(dynamic.from(self.state))
- loop(self)
- }
- Resume(callback) -> {
- callback()
- loop(Self(..self, mode: Running))
- }
- Suspend(callback) -> {
- callback()
- loop(Self(..self, mode: Suspended))
- }
- GetStatus(callback) -> {
- callback(process_status_info(self))
- loop(self)
- }
- }
-
- Unexpected(message) -> {
- log_warning(
- charlist.from_string("Actor discarding unexpected message: ~s"),
- [charlist.from_string(string.inspect(message))],
- )
- loop(self)
- }
-
- Message(msg) ->
- case self.message_handler(msg, self.state) {
- Stop(reason) -> exit_process(reason)
- Continue(state: state, selector: new_selector) -> {
- let selector =
- new_selector
- |> option.map(init_selector(self.subject, _))
- |> option.unwrap(self.selector)
- loop(Self(..self, state: state, selector: selector))
- }
- }
- }
-}
-
-// TODO: replace this when we have Gleam bindings to the logger
-@external(erlang, "logger", "warning")
-fn log_warning(a: Charlist, b: List(Charlist)) -> Nil
-
-fn initialise_actor(
- spec: Spec(state, msg),
- ack: Subject(Result(Subject(msg), ExitReason)),
-) {
- let subject = process.new_subject()
- case spec.init() {
- Ready(state, selector) -> {
- let selector = init_selector(subject, selector)
- // Signal to parent that the process has initialised successfully
- process.send(ack, Ok(subject))
- // Start message receive loop
- let self =
- Self(
- state: state,
- parent: process.subject_owner(ack),
- subject: subject,
- selector: selector,
- message_handler: spec.loop,
- debug_state: system.debug_state([]),
- mode: Running,
- )
- loop(self)
- }
-
- Failed(reason) -> {
- process.send(ack, Error(Abnormal(reason)))
- exit_process(Abnormal(reason))
- }
- }
-}
-
-fn init_selector(subject, selector) {
- process.new_selector()
- |> process.selecting(subject, Message)
- |> process.merge_selector(process.map_selector(selector, Message))
-}
-
-pub type StartError {
- InitTimeout
- InitFailed(ExitReason)
- InitCrashed(Dynamic)
-}
-
-/// The result of starting a Gleam actor.
-///
-/// This type is compatible with Gleam supervisors. If you wish to convert it
-/// to a type compatible with Erlang supervisors see the `ErlangStartResult`
-/// type and `erlang_start_result` function.
-///
-pub type StartResult(msg) =
- Result(Subject(msg), StartError)
-
-/// An Erlang supervisor compatible process start result.
-///
-/// If you wish to convert this into a `StartResult` compatible with Gleam
-/// supervisors see the `from_erlang_start_result` and `wrap_erlang_starter`
-/// functions.
-///
-pub type ErlangStartResult =
- Result(Pid, Dynamic)
-
-/// Convert a Gleam actor start result into an Erlang supervisor compatible
-/// process start result.
-///
-pub fn to_erlang_start_result(res: StartResult(msg)) -> ErlangStartResult {
- case res {
- Ok(x) -> Ok(process.subject_owner(x))
- Error(x) -> Error(dynamic.from(x))
- }
-}
-
-type StartInitMessage(msg) {
- Ack(Result(Subject(msg), ExitReason))
- Mon(process.ProcessDown)
-}
-
-// TODO: test init_timeout. Currently if we test it eunit prints an error from
-// the process death. How do we avoid this?
-//
-/// Start an actor from a given specification. If the actor's `init` function
-/// returns an error or does not return within `init_timeout` then an error is
-/// returned.
-///
-/// If you do not need to specify the initialisation behaviour of your actor
-/// consider using the `start` function.
-///
-pub fn start_spec(spec: Spec(state, msg)) -> Result(Subject(msg), StartError) {
- let ack_subject = process.new_subject()
-
- let child =
- process.start(
- linked: True,
- running: fn() { initialise_actor(spec, ack_subject) },
- )
-
- let monitor = process.monitor_process(child)
- let selector =
- process.new_selector()
- |> process.selecting(ack_subject, Ack)
- |> process.selecting_process_down(monitor, Mon)
-
- let result = case process.select(selector, spec.init_timeout) {
- // Child started OK
- Ok(Ack(Ok(channel))) -> Ok(channel)
-
- // Child initialiser returned an error
- Ok(Ack(Error(reason))) -> Error(InitFailed(reason))
-
- // Child went down while initialising
- Ok(Mon(down)) -> Error(InitCrashed(down.reason))
-
- // Child did not finish initialising in time
- Error(Nil) -> {
- process.kill(child)
- Error(InitTimeout)
- }
- }
-
- // Remove the monitor used for the starting of the actor as to avoid an extra
- // message arriving at the parent if the child dies later.
- process.demonitor_process(monitor)
-
- result
-}
-
-/// Start an actor with a given initial state and message handling loop
-/// function.
-///
-/// This function returns a `Result` but it will always be `Ok` so it is safe
-/// to use with `assert` if you are not starting this actor as part of a
-/// supervision tree.
-///
-/// If you wish to configure the initialisation behaviour of a new actor see
-/// the `Spec` record and the `start_spec` function.
-///
-pub fn start(
- state: state,
- loop: fn(msg, state) -> Next(msg, state),
-) -> Result(Subject(msg), StartError) {
- start_spec(Spec(
- init: fn() { Ready(state, process.new_selector()) },
- loop: loop,
- init_timeout: 5000,
- ))
-}
-
-/// Send a message over a given channel.
-///
-/// This is a re-export of `process.send`, for the sake of convenience.
-///
-pub fn send(subject: Subject(msg), msg: msg) -> Nil {
- process.send(subject, msg)
-}
-
-// TODO: test
-/// Send a synchronous message and wait for a response from the receiving
-/// process.
-///
-/// If a reply is not received within the given timeout then the sender process
-/// crashes. If you wish receive a `Result` rather than crashing see the
-/// `process.try_call` function.
-///
-/// This is a re-export of `process.call`, for the sake of convenience.
-///
-pub fn call(
- selector: Subject(message),
- make_message: fn(Subject(reply)) -> message,
- timeout: Int,
-) -> reply {
- process.call(selector, make_message, timeout)
-}
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam/otp/intensity_tracker.gleam b/aoc2023/build/packages/gleam_otp/src/gleam/otp/intensity_tracker.gleam
deleted file mode 100644
index 2044be0..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam/otp/intensity_tracker.gleam
+++ /dev/null
@@ -1,46 +0,0 @@
-//// The intensity tracker is used to monitor how frequently an event happens,
-//// erroring if it happens too many times within a period of time.
-
-import gleam/list
-
-// TODO: test
-pub opaque type IntensityTracker {
- IntensityTracker(limit: Int, period: Int, events: List(Int))
-}
-
-pub type TooIntense {
- TooIntense
-}
-
-pub fn new(limit limit: Int, period period: Int) -> IntensityTracker {
- IntensityTracker(limit: limit, period: period, events: [])
-}
-
-@external(erlang, "erlang", "monotonic_time")
-fn monotonic_time(a: Int) -> Int
-
-fn now_seconds() -> Int {
- monotonic_time(1)
-}
-
-pub fn trim_window(events: List(Int), now: Int, period: Int) -> List(Int) {
- case events {
- [] -> []
- [event, ..events] ->
- case now >= event + period {
- True -> [event, ..trim_window(events, now, period)]
- False -> []
- }
- }
-}
-
-pub fn add_event(
- tracker: IntensityTracker,
-) -> Result(IntensityTracker, TooIntense) {
- let now = now_seconds()
- let events = trim_window([now, ..tracker.events], now, tracker.period)
- case list.length(events) >= tracker.limit {
- True -> Error(TooIntense)
- False -> Ok(IntensityTracker(..tracker, events: events))
- }
-}
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam/otp/port.gleam b/aoc2023/build/packages/gleam_otp/src/gleam/otp/port.gleam
deleted file mode 100644
index 4e1b4d8..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam/otp/port.gleam
+++ /dev/null
@@ -1,9 +0,0 @@
-/// Ports are how code running on the Erlang virtual machine interacts with
-/// the outside world. Bytes of data can be sent to and read from ports,
-/// providing a form of message passing to an external program or resource.
-///
-/// For more information on ports see the [Erlang ports documentation][1].
-///
-/// [1]: https://erlang.org/doc/reference_manual/ports.html
-///
-pub type Port
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam/otp/supervisor.gleam b/aoc2023/build/packages/gleam_otp/src/gleam/otp/supervisor.gleam
deleted file mode 100644
index b99ad8e..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam/otp/supervisor.gleam
+++ /dev/null
@@ -1,410 +0,0 @@
-// TODO: specify amount of time permitted for shut-down
-import gleam/result
-import gleam/string
-import gleam/option.{type Option, None, Some}
-import gleam/erlang/process.{type Pid, type Subject}
-import gleam/otp/actor.{type StartError}
-import gleam/otp/intensity_tracker.{type IntensityTracker}
-import gleam/erlang/node.{type Node}
-
-/// This data structure holds all the values required by the `start_spec`
-/// function in order to create an supervisor.
-///
-/// If you do not need to configure the behaviour of your supervisor consider
-/// using the `start` function.
-///
-pub type Spec(argument, return) {
- Spec(
- argument: argument,
- max_frequency: Int,
- frequency_period: Int,
- init: fn(Children(argument)) -> Children(return),
- )
-}
-
-/// This type represents the starting children of a supervisor within the
-/// `init` function.
-///
-pub opaque type Children(argument) {
- Ready(Starter(argument))
- Failed(ChildStartError)
-}
-
-/// This type contains all the information required to start a new child and
-/// add it to the `Children`.
-///
-/// This is typically created with the `worker` function.
-///
-pub opaque type ChildSpec(msg, argument, returning) {
- ChildSpec(
- // TODO: merge this into one field
- start: fn(argument) -> Result(Subject(msg), StartError),
- returning: fn(argument, Subject(msg)) -> returning,
- )
-}
-
-type ChildStartError {
- ChildStartError(previous_pid: Option(Pid), error: StartError)
-}
-
-pub opaque type Message {
- Exit(process.ExitMessage)
- RetryRestart(Pid)
-}
-
-type Instruction {
- StartAll
- StartFrom(Pid)
-}
-
-type State(a) {
- State(
- restarts: IntensityTracker,
- starter: Starter(a),
- retry_restarts: Subject(Pid),
- )
-}
-
-type Starter(argument) {
- Starter(
- argument: argument,
- exec: Option(
- fn(Instruction) ->
- Result(#(Starter(argument), Instruction), ChildStartError),
- ),
- )
-}
-
-type Child(argument) {
- Child(pid: Pid, argument: argument)
-}
-
-fn start_child(
- child_spec: ChildSpec(msg, argument_in, argument_out),
- argument: argument_in,
-) -> Result(Child(argument_out), ChildStartError) {
- use subject <- result.then(
- child_spec.start(argument)
- |> result.map_error(ChildStartError(None, _)),
- )
-
- Ok(Child(
- pid: process.subject_owner(subject),
- // Merge the new child's pid into the argument to produce the new argument
- // used to start any remaining children.
- argument: child_spec.returning(argument, subject),
- ))
-}
-
-// TODO: more sophsiticated stopping of processes. i.e. give supervisors
-// more time to shut down.
-fn shutdown_child(pid: Pid, _spec: ChildSpec(msg, arg_1, arg_2)) -> Nil {
- process.send_exit(pid)
-}
-
-fn perform_instruction_for_child(
- argument: argument_in,
- instruction: Instruction,
- child_spec: ChildSpec(msg, argument_in, argument_out),
- child: Child(argument_out),
-) -> Result(#(Child(argument_out), Instruction), ChildStartError) {
- let current = child.pid
- case instruction {
- // This child is older than the StartFrom target, we don't need to
- // restart it
- StartFrom(target) if target != current -> Ok(#(child, instruction))
-
- // This pid either is the cause of the problem, or we have the StartAll
- // instruction. Either way it and its younger siblings need to be restarted.
- _ -> {
- shutdown_child(current, child_spec)
- use child <- result.then(start_child(child_spec, argument))
- Ok(#(child, StartAll))
- }
- }
-}
-
-fn add_child_to_starter(
- starter: Starter(argument_in),
- child_spec: ChildSpec(msg, argument_in, argument_out),
- child: Child(argument_out),
-) -> Starter(argument_out) {
- let starter = fn(instruction) {
- // Restart the older children. We use `try` to return early if the older
- // children failed to start
- use #(starter, instruction) <- result.then(case starter.exec {
- Some(start) -> start(instruction)
- None -> Ok(#(starter, instruction))
- })
-
- // Perform the instruction, restarting the child as required
- use #(child, instruction) <- result.then(perform_instruction_for_child(
- starter.argument,
- instruction,
- child_spec,
- child,
- ))
-
- // Create a new starter for the next time the supervisor needs to restart
- let starter = add_child_to_starter(starter, child_spec, child)
-
- Ok(#(starter, instruction))
- }
-
- Starter(exec: Some(starter), argument: child.argument)
-}
-
-fn start_and_add_child(
- state: Starter(argument_0),
- child_spec: ChildSpec(msg, argument_0, argument_1),
-) -> Children(argument_1) {
- case start_child(child_spec, state.argument) {
- Ok(child) -> Ready(add_child_to_starter(state, child_spec, child))
- Error(reason) -> Failed(reason)
- }
-}
-
-/// Add a child to the collection of children of the supervisor
-///
-/// This function starts the child from the child spec.
-///
-pub fn add(
- children: Children(argument),
- child_spec: ChildSpec(msg, argument, new_argument),
-) -> Children(new_argument) {
- case children {
- // If one of the previous children has failed then we cannot continue
- Failed(fail) -> Failed(fail)
-
- // If everything is OK so far then we can add the child
- Ready(state) -> start_and_add_child(state, child_spec)
- }
-}
-
-// TODO: test
-// TODO: unlimitd shut down duration
-/// Prepare a new supervisor type child.
-///
-/// If you wish to prepare a new non-supervisor type child see the `worker`
-/// function.
-///
-/// If you wish to change the type of the argument for later children see the
-/// `returning` function.
-///
-/// Note: Gleam supervisors do not yet support different shutdown periods per
-/// child so this function is currently identical in behaviour to `worker`. It is
-/// recommended to use this function for supervisor children nevertheless so the
-/// correct shut down behaviour is used in later releases of this library.
-///
-pub fn supervisor(
- start: fn(argument) -> Result(Subject(msg), StartError),
-) -> ChildSpec(msg, argument, argument) {
- ChildSpec(start: start, returning: fn(argument, _channel) { argument })
-}
-
-/// Prepare a new worker type child.
-///
-/// If you wish to prepare a new supervisor type child see the `supervisor`
-/// function.
-///
-/// If you wish to change the type of the argument for later children see the
-/// `returning` function.
-///
-pub fn worker(
- start: fn(argument) -> Result(Subject(msg), StartError),
-) -> ChildSpec(msg, argument, argument) {
- ChildSpec(start: start, returning: fn(argument, _channel) { argument })
-}
-
-// TODO: test
-/// As each child is added to a supervisors children a new argument is prepared
-/// with which to start the next child. By default argument is the same as the
-/// previous argument, but this function can be used to change it to something
-/// else by passing a function that takes the previous argument and the sender
-/// of the previous child.
-///
-pub fn returning(
- child: ChildSpec(msg, argument_a, argument_b),
- updater: fn(argument_a, Subject(msg)) -> argument_c,
-) -> ChildSpec(msg, argument_a, argument_c) {
- ChildSpec(start: child.start, returning: updater)
-}
-
-fn init(
- spec: Spec(argument, return),
-) -> actor.InitResult(State(return), Message) {
- // Create a subject so that we can asynchronously retry restarting when we
- // fail to bring an exited child
- let retry = process.new_subject()
-
- // Trap exits so that we get a message when a child crashes
- process.trap_exits(True)
-
- // Combine selectors
- let selector =
- process.new_selector()
- |> process.selecting(retry, RetryRestart)
- |> process.selecting_trapped_exits(Exit)
-
- // Start any children
- let result =
- Starter(argument: spec.argument, exec: None)
- |> Ready
- |> spec.init
-
- // Pass back up the result
- case result {
- Ready(starter) -> {
- let restarts =
- intensity_tracker.new(
- limit: spec.max_frequency,
- period: spec.frequency_period,
- )
- let state =
- State(starter: starter, restarts: restarts, retry_restarts: retry)
- actor.Ready(state, selector)
- }
-
- Failed(error) ->
- actor.Failed(case error.error {
- actor.InitTimeout -> "Child initialisation timed out"
- actor.InitCrashed(reason) ->
- string.append(
- "Child crashed during initialisation: ",
- string.inspect(reason),
- )
- actor.InitFailed(reason) ->
- string.append(
- "Child failed to start during initialisation: ",
- string.inspect(reason),
- )
- })
- }
-}
-
-type HandleExitError {
- RestartFailed(pid: Pid, restarts: IntensityTracker)
- TooManyRestarts
-}
-
-fn handle_exit(pid: Pid, state: State(a)) -> actor.Next(Message, State(a)) {
- let outcome = {
- // If we are handling an exit then we must have some children
- let assert Some(start) = state.starter.exec
-
- // Check to see if there has been too many restarts in this period
- use restarts <- result.then(
- state.restarts
- |> intensity_tracker.add_event
- |> result.map_error(fn(_) { TooManyRestarts }),
- )
-
- // Restart the exited child and any following children
- use #(starter, _) <- result.then(
- start(StartFrom(pid))
- |> result.map_error(fn(e: ChildStartError) {
- RestartFailed(option.unwrap(e.previous_pid, pid), restarts)
- }),
- )
-
- Ok(State(..state, starter: starter, restarts: restarts))
- }
-
- case outcome {
- Ok(state) -> actor.continue(state)
- Error(RestartFailed(failed_child, restarts)) -> {
- // Asynchronously enqueue the restarting of this child again as we were
- // unable to restart them this time. We do this asynchronously as we want
- // to have a chance to handle any system messages that have come in.
- process.send(state.retry_restarts, failed_child)
- let state = State(..state, restarts: restarts)
- actor.continue(state)
- }
- Error(TooManyRestarts) ->
- actor.Stop(process.Abnormal(
- "Child processes restarted too many times within allowed period",
- ))
- }
-}
-
-fn loop(
- message: Message,
- state: State(argument),
-) -> actor.Next(Message, State(argument)) {
- case message {
- Exit(exit_message) -> handle_exit(exit_message.pid, state)
- RetryRestart(pid) -> handle_exit(pid, state)
- }
-}
-
-/// Start a supervisor from a given specification.
-///
-pub fn start_spec(spec: Spec(a, b)) -> Result(Subject(Message), StartError) {
- actor.start_spec(actor.Spec(
- init: fn() { init(spec) },
- loop: loop,
- init_timeout: 60_000,
- ))
-}
-
-/// Start a supervisor from a given `init` function.
-///
-/// The init argument passed to children will be `Nil` and the maximum restart
-/// intensity will be 1 restart per 5 seconds (the same as the default for
-/// [Erlang supervisors][erl-sup]). If you wish to specify these values, see
-/// the `start_spec` function and the `Spec` type.
-///
-/// [erl-sup]: https://www.erlang.org/doc/design_principles/sup_princ.html#maximum-restart-intensity
-///
-pub fn start(
- init: fn(Children(Nil)) -> Children(a),
-) -> Result(Subject(Message), StartError) {
- start_spec(Spec(
- init: init,
- argument: Nil,
- max_frequency: 1,
- frequency_period: 5,
- ))
-}
-
-/// A type used to describe the situation in which an Erlang based application
-/// is starting.
-///
-/// For more information see the [Erlang distributed application
-/// documentation][1] and the Learn Your Some Erlang chapter on [distributed
-/// applications][2].
-///
-/// [1]: https://erlang.org/doc/design_principles/distributed_applications.html
-/// [2]: https://learnyousomeerlang.com/distributed-otp-applications
-///
-pub type ApplicationStartMode {
- Normal
- Takeover(Node)
- Failover(Node)
-}
-
-pub type ApplicationStop
-
-@external(erlang, "gleam_otp_external", "application_stopped")
-pub fn application_stopped() -> ApplicationStop
-
-/// The result of starting a Gleam actor.
-///
-/// This type is compatible with Gleam supervisors. If you wish to convert it
-/// to a type compatible with Erlang supervisors see the `ErlangStartResult`
-/// type and `erlang_start_result` function.
-///
-pub type StartResult(msg) =
- actor.StartResult(msg)
-
-/// An Erlang supervisor compatible process start result.
-///
-pub type ErlangStartResult =
- actor.ErlangStartResult
-
-/// Convert a Gleam actor start result into an Erlang supervisor compatible
-/// process start result.
-///
-pub fn to_erlang_start_result(res: StartResult(msg)) -> ErlangStartResult {
- actor.to_erlang_start_result(res)
-}
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam/otp/system.gleam b/aoc2023/build/packages/gleam_otp/src/gleam/otp/system.gleam
deleted file mode 100644
index c05646b..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam/otp/system.gleam
+++ /dev/null
@@ -1,89 +0,0 @@
-import gleam/dynamic.{type Dynamic}
-import gleam/erlang/atom.{type Atom}
-import gleam/erlang/process.{type Pid}
-
-pub type Mode {
- Running
- Suspended
-}
-
-pub type DebugOption {
- NoDebug
-}
-
-pub type DebugState
-
-@external(erlang, "sys", "debug_options")
-pub fn debug_state(a: List(DebugOption)) -> DebugState
-
-pub type StatusInfo {
- StatusInfo(
- module: Atom,
- parent: Pid,
- mode: Mode,
- debug_state: DebugState,
- state: Dynamic,
- )
-}
-
-// TODO: document
-// TODO: implement remaining messages
-pub type SystemMessage {
- // {replace_state, StateFn}
- // {change_code, Mod, Vsn, Extra}
- // {terminate, Reason}
- // {debug, {log, Flag}}
- // {debug, {trace, Flag}}
- // {debug, {log_to_file, FileName}}
- // {debug, {statistics, Flag}}
- // {debug, no_debug}
- // {debug, {install, {Func, FuncState}}}
- // {debug, {install, {FuncId, Func, FuncState}}}
- // {debug, {remove, FuncOrId}}
- Resume(fn() -> Nil)
- Suspend(fn() -> Nil)
- GetState(fn(Dynamic) -> Nil)
- GetStatus(fn(StatusInfo) -> Nil)
-}
-
-type DoNotLeak
-
-/// Get the state of a given OTP compatible process. This function is only
-/// intended for debugging.
-///
-/// For more information see the [Erlang documentation][1].
-///
-/// [1]: https://erlang.org/doc/man/sys.html#get_state-1
-///
-@external(erlang, "sys", "get_state")
-pub fn get_state(from from: Pid) -> Dynamic
-
-@external(erlang, "sys", "suspend")
-fn erl_suspend(a: Pid) -> DoNotLeak
-
-/// Request an OTP compatible process to suspend, causing it to only handle
-/// system messages.
-///
-/// For more information see the [Erlang documentation][1].
-///
-/// [1]: https://erlang.org/doc/man/sys.html#suspend-1
-///
-pub fn suspend(pid: Pid) -> Nil {
- erl_suspend(pid)
- Nil
-}
-
-@external(erlang, "sys", "resume")
-fn erl_resume(from from: Pid) -> DoNotLeak
-
-/// Request a suspended OTP compatible process to result, causing it to handle
-/// all messages rather than only system messages.
-///
-/// For more information see the [Erlang documentation][1].
-///
-/// [1]: https://erlang.org/doc/man/sys.html#resume-1
-///
-pub fn resume(pid: Pid) -> Nil {
- erl_resume(pid)
- Nil
-}
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam/otp/task.gleam b/aoc2023/build/packages/gleam_otp/src/gleam/otp/task.gleam
deleted file mode 100644
index b2b2c5c..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam/otp/task.gleam
+++ /dev/null
@@ -1,151 +0,0 @@
-//// A task is a kind of process that performs a single task and then shuts
-//// down. Commonly tasks are used to convert sequential code into concurrent
-//// code by performing computation in another process.
-////
-//// let task = task.async(fn() { do_some_work() })
-//// let value = do_some_other_work()
-//// value + task.await(task, 100)
-////
-//// Tasks spawned with async can be awaited on by their caller process (and
-//// only their caller) as shown in the example above. They are implemented by
-//// spawning a process that sends a message to the caller once the given
-//// computation is performed.
-////
-//// There are two important things to consider when using `async`:
-////
-//// 1. If you are using async tasks, you must await a reply as they are always
-//// sent.
-////
-//// 2. async tasks link the caller and the spawned process. This means that,
-//// if the caller crashes, the task will crash too and vice-versa. This is
-//// on purpose: if the process meant to receive the result no longer
-//// exists, there is no purpose in completing the computation.
-////
-//// This module is inspired by Elixir's [Task module][1].
-////
-//// [1]: https://hexdocs.pm/elixir/master/Task.html
-////
-
-// TODO: await_many
-import gleam/erlang/process.{type Pid, type ProcessMonitor, type Selector}
-import gleam/dynamic.{type Dynamic}
-
-pub opaque type Task(value) {
- Task(
- owner: Pid,
- pid: Pid,
- monitor: ProcessMonitor,
- selector: Selector(Message(value)),
- )
-}
-
-// TODO: test
-/// Spawn a task process that calls a given function in order to perform some
-/// work. The result of this function is send back to the parent and can be
-/// received using the `await` function.
-///
-/// See the top level module documentation for more information on async/await.
-///
-pub fn async(work: fn() -> value) -> Task(value) {
- let owner = process.self()
- let subject = process.new_subject()
- let pid =
- process.start(linked: True, running: fn() { process.send(subject, work()) })
- let monitor = process.monitor_process(pid)
- let selector =
- process.new_selector()
- |> process.selecting_process_down(monitor, FromMonitor)
- |> process.selecting(subject, FromSubject)
- Task(owner: owner, pid: pid, monitor: monitor, selector: selector)
-}
-
-pub type AwaitError {
- Timeout
- Exit(reason: Dynamic)
-}
-
-// We can only wait on a task if we are the owner of it so crash if we are
-// waiting on a task we don't own.
-fn assert_owner(task: Task(a)) -> Nil {
- let self = process.self()
- case task.owner == self {
- True -> Nil
- False ->
- process.send_abnormal_exit(
- self,
- "awaited on a task that does not belong to this process",
- )
- }
-}
-
-type Message(value) {
- FromMonitor(process.ProcessDown)
- FromSubject(value)
-}
-
-// TODO: test
-/// Wait for the value computed by a task.
-///
-/// If the a value is not received before the timeout has elapsed or if the
-/// task process crashes then an error is returned.
-///
-pub fn try_await(task: Task(value), timeout: Int) -> Result(value, AwaitError) {
- assert_owner(task)
- case process.select(task.selector, timeout) {
- // The task process has sent back a value
- Ok(FromSubject(x)) -> {
- process.demonitor_process(task.monitor)
- Ok(x)
- }
-
- // The task process crashed without sending a value
- Ok(FromMonitor(process.ProcessDown(reason: reason, ..))) ->
- Error(Exit(reason))
-
- // The task process is alive but has not sent a value yet
- Error(Nil) -> Error(Timeout)
- }
-}
-
-// TODO: test
-/// Wait for the value computed by a task.
-///
-/// If the a value is not received before the timeout has elapsed or if the
-/// task process crashes then this function crashes.
-///
-pub fn await(task: Task(value), timeout: Int) -> value {
- let assert Ok(value) = try_await(task, timeout)
- value
-}
-
-/// Wait endlessly for the value computed by a task.
-///
-/// Be Careful! This function does not return until there is a value to
-/// receive. If a value is not received then the process will be stuck waiting
-/// forever.
-///
-pub fn try_await_forever(task: Task(value)) -> Result(value, AwaitError) {
- assert_owner(task)
- case process.select_forever(task.selector) {
- // The task process has sent back a value
- FromSubject(x) -> {
- process.demonitor_process(task.monitor)
- Ok(x)
- }
-
- // The task process crashed without sending a value
- FromMonitor(process.ProcessDown(reason: reason, ..)) -> Error(Exit(reason))
- }
-}
-
-/// Wait endlessly for the value computed by a task.
-///
-/// Be Careful! Like `try_await_forever`, this function does not return until there is a value to
-/// receive.
-///
-/// If the task process crashes then this function crashes.
-///
-pub fn await_forever(task: Task(value)) -> value {
- let assert Ok(value) = try_await_forever(task)
- value
-}
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam@otp@actor.erl b/aoc2023/build/packages/gleam_otp/src/gleam@otp@actor.erl
deleted file mode 100644
index 0606147..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam@otp@actor.erl
+++ /dev/null
@@ -1,273 +0,0 @@
--module(gleam@otp@actor).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export([continue/1, with_selector/2, to_erlang_start_result/1, start_spec/1, start/2, send/2, call/3]).
--export_type([message/1, next/2, init_result/2, self/2, spec/2, start_error/0, start_init_message/1]).
-
--type message(GAS) :: {message, GAS} |
- {system, gleam@otp@system:system_message()} |
- {unexpected, gleam@dynamic:dynamic_()}.
-
--type next(GAT, GAU) :: {continue,
- GAU,
- gleam@option:option(gleam@erlang@process:selector(GAT))} |
- {stop, gleam@erlang@process:exit_reason()}.
-
--type init_result(GAV, GAW) :: {ready, GAV, gleam@erlang@process:selector(GAW)} |
- {failed, binary()}.
-
--type self(GAX, GAY) :: {self,
- gleam@otp@system:mode(),
- gleam@erlang@process:pid_(),
- GAX,
- gleam@erlang@process:subject(GAY),
- gleam@erlang@process:selector(message(GAY)),
- gleam@otp@system:debug_state(),
- fun((GAY, GAX) -> next(GAY, GAX))}.
-
--type spec(GAZ, GBA) :: {spec,
- fun(() -> init_result(GAZ, GBA)),
- integer(),
- fun((GBA, GAZ) -> next(GBA, GAZ))}.
-
--type start_error() :: init_timeout |
- {init_failed, gleam@erlang@process:exit_reason()} |
- {init_crashed, gleam@dynamic:dynamic_()}.
-
--type start_init_message(GBB) :: {ack,
- {ok, gleam@erlang@process:subject(GBB)} |
- {error, gleam@erlang@process:exit_reason()}} |
- {mon, gleam@erlang@process:process_down()}.
-
--spec continue(GBI) -> next(any(), GBI).
-continue(State) ->
- {continue, State, none}.
-
--spec with_selector(next(GBM, GBN), gleam@erlang@process:selector(GBM)) -> next(GBM, GBN).
-with_selector(Value, Selector) ->
- case Value of
- {continue, State, _} ->
- {continue, State, {some, Selector}};
-
- _ ->
- Value
- end.
-
--spec exit_process(gleam@erlang@process:exit_reason()) -> gleam@erlang@process:exit_reason().
-exit_process(Reason) ->
- Reason.
-
--spec selecting_system_messages(gleam@erlang@process:selector(message(GBY))) -> gleam@erlang@process:selector(message(GBY)).
-selecting_system_messages(Selector) ->
- _pipe = Selector,
- gleam@erlang@process:selecting_record3(
- _pipe,
- erlang:binary_to_atom(<<"system"/utf8>>),
- fun gleam_otp_external:convert_system_message/2
- ).
-
--spec receive_message(self(any(), GBU)) -> message(GBU).
-receive_message(Self) ->
- Selector = case erlang:element(2, Self) of
- suspended ->
- _pipe = gleam_erlang_ffi:new_selector(),
- selecting_system_messages(_pipe);
-
- running ->
- _pipe@1 = gleam_erlang_ffi:new_selector(),
- _pipe@2 = gleam@erlang@process:selecting_anything(
- _pipe@1,
- fun(Field@0) -> {unexpected, Field@0} end
- ),
- _pipe@3 = gleam_erlang_ffi:merge_selector(
- _pipe@2,
- erlang:element(6, Self)
- ),
- selecting_system_messages(_pipe@3)
- end,
- gleam_erlang_ffi:select(Selector).
-
--spec process_status_info(self(any(), any())) -> gleam@otp@system:status_info().
-process_status_info(Self) ->
- {status_info,
- erlang:binary_to_atom(<<"gleam@otp@actor"/utf8>>),
- erlang:element(3, Self),
- erlang:element(2, Self),
- erlang:element(7, Self),
- gleam@dynamic:from(erlang:element(4, Self))}.
-
--spec init_selector(
- gleam@erlang@process:subject(GGN),
- gleam@erlang@process:selector(GGN)
-) -> gleam@erlang@process:selector(message(GGN)).
-init_selector(Subject, Selector) ->
- _pipe = gleam_erlang_ffi:new_selector(),
- _pipe@1 = gleam@erlang@process:selecting(
- _pipe,
- Subject,
- fun(Field@0) -> {message, Field@0} end
- ),
- gleam_erlang_ffi:merge_selector(
- _pipe@1,
- gleam_erlang_ffi:map_selector(
- Selector,
- fun(Field@0) -> {message, Field@0} end
- )
- ).
-
--spec loop(self(any(), any())) -> gleam@erlang@process:exit_reason().
-loop(Self) ->
- case receive_message(Self) of
- {system, System} ->
- case System of
- {get_state, Callback} ->
- Callback(gleam@dynamic:from(erlang:element(4, Self))),
- loop(Self);
-
- {resume, Callback@1} ->
- Callback@1(),
- loop(erlang:setelement(2, Self, running));
-
- {suspend, Callback@2} ->
- Callback@2(),
- loop(erlang:setelement(2, Self, suspended));
-
- {get_status, Callback@3} ->
- Callback@3(process_status_info(Self)),
- loop(Self)
- end;
-
- {unexpected, Message} ->
- logger:warning(
- unicode:characters_to_list(
- <<"Actor discarding unexpected message: ~s"/utf8>>
- ),
- [unicode:characters_to_list(gleam@string:inspect(Message))]
- ),
- loop(Self);
-
- {message, Msg} ->
- case (erlang:element(8, Self))(Msg, erlang:element(4, Self)) of
- {stop, Reason} ->
- exit_process(Reason);
-
- {continue, State, New_selector} ->
- Selector = begin
- _pipe = New_selector,
- _pipe@1 = gleam@option:map(
- _pipe,
- fun(_capture) ->
- init_selector(erlang:element(5, Self), _capture)
- end
- ),
- gleam@option:unwrap(_pipe@1, erlang:element(6, Self))
- end,
- loop(
- erlang:setelement(
- 6,
- erlang:setelement(4, Self, State),
- Selector
- )
- )
- end
- end.
-
--spec initialise_actor(
- spec(any(), GCP),
- gleam@erlang@process:subject({ok, gleam@erlang@process:subject(GCP)} |
- {error, gleam@erlang@process:exit_reason()})
-) -> gleam@erlang@process:exit_reason().
-initialise_actor(Spec, Ack) ->
- Subject = gleam@erlang@process:new_subject(),
- case (erlang:element(2, Spec))() of
- {ready, State, Selector} ->
- Selector@1 = init_selector(Subject, Selector),
- gleam@erlang@process:send(Ack, {ok, Subject}),
- Self = {self,
- running,
- gleam@erlang@process:subject_owner(Ack),
- State,
- Subject,
- Selector@1,
- sys:debug_options([]),
- erlang:element(4, Spec)},
- loop(Self);
-
- {failed, Reason} ->
- gleam@erlang@process:send(Ack, {error, {abnormal, Reason}}),
- exit_process({abnormal, Reason})
- end.
-
--spec to_erlang_start_result(
- {ok, gleam@erlang@process:subject(any())} | {error, start_error()}
-) -> {ok, gleam@erlang@process:pid_()} | {error, gleam@dynamic:dynamic_()}.
-to_erlang_start_result(Res) ->
- case Res of
- {ok, X} ->
- {ok, gleam@erlang@process:subject_owner(X)};
-
- {error, X@1} ->
- {error, gleam@dynamic:from(X@1)}
- end.
-
--spec start_spec(spec(any(), GDD)) -> {ok, gleam@erlang@process:subject(GDD)} |
- {error, start_error()}.
-start_spec(Spec) ->
- Ack_subject = gleam@erlang@process:new_subject(),
- Child = gleam@erlang@process:start(
- fun() -> initialise_actor(Spec, Ack_subject) end,
- true
- ),
- Monitor = gleam@erlang@process:monitor_process(Child),
- Selector = begin
- _pipe = gleam_erlang_ffi:new_selector(),
- _pipe@1 = gleam@erlang@process:selecting(
- _pipe,
- Ack_subject,
- fun(Field@0) -> {ack, Field@0} end
- ),
- gleam@erlang@process:selecting_process_down(
- _pipe@1,
- Monitor,
- fun(Field@0) -> {mon, Field@0} end
- )
- end,
- Result = case gleam_erlang_ffi:select(Selector, erlang:element(3, Spec)) of
- {ok, {ack, {ok, Channel}}} ->
- {ok, Channel};
-
- {ok, {ack, {error, Reason}}} ->
- {error, {init_failed, Reason}};
-
- {ok, {mon, Down}} ->
- {error, {init_crashed, erlang:element(3, Down)}};
-
- {error, nil} ->
- gleam@erlang@process:kill(Child),
- {error, init_timeout}
- end,
- gleam_erlang_ffi:demonitor(Monitor),
- Result.
-
--spec start(GDJ, fun((GDK, GDJ) -> next(GDK, GDJ))) -> {ok,
- gleam@erlang@process:subject(GDK)} |
- {error, start_error()}.
-start(State, Loop) ->
- start_spec(
- {spec,
- fun() -> {ready, State, gleam_erlang_ffi:new_selector()} end,
- 5000,
- Loop}
- ).
-
--spec send(gleam@erlang@process:subject(GDQ), GDQ) -> nil.
-send(Subject, Msg) ->
- gleam@erlang@process:send(Subject, Msg).
-
--spec call(
- gleam@erlang@process:subject(GDS),
- fun((gleam@erlang@process:subject(GDU)) -> GDS),
- integer()
-) -> GDU.
-call(Selector, Make_message, Timeout) ->
- gleam@erlang@process:call(Selector, Make_message, Timeout).
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam@otp@intensity_tracker.erl b/aoc2023/build/packages/gleam_otp/src/gleam@otp@intensity_tracker.erl
deleted file mode 100644
index 8792f14..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam@otp@intensity_tracker.erl
+++ /dev/null
@@ -1,53 +0,0 @@
--module(gleam@otp@intensity_tracker).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export([new/2, trim_window/3, add_event/1]).
--export_type([intensity_tracker/0, too_intense/0]).
-
--opaque intensity_tracker() :: {intensity_tracker,
- integer(),
- integer(),
- list(integer())}.
-
--type too_intense() :: too_intense.
-
--spec new(integer(), integer()) -> intensity_tracker().
-new(Limit, Period) ->
- {intensity_tracker, Limit, Period, []}.
-
--spec now_seconds() -> integer().
-now_seconds() ->
- erlang:monotonic_time(1).
-
--spec trim_window(list(integer()), integer(), integer()) -> list(integer()).
-trim_window(Events, Now, Period) ->
- case Events of
- [] ->
- [];
-
- [Event | Events@1] ->
- case Now >= (Event + Period) of
- true ->
- [Event | trim_window(Events@1, Now, Period)];
-
- false ->
- []
- end
- end.
-
--spec add_event(intensity_tracker()) -> {ok, intensity_tracker()} |
- {error, too_intense()}.
-add_event(Tracker) ->
- Now = now_seconds(),
- Events = trim_window(
- [Now | erlang:element(4, Tracker)],
- Now,
- erlang:element(3, Tracker)
- ),
- case gleam@list:length(Events) >= erlang:element(2, Tracker) of
- true ->
- {error, too_intense};
-
- false ->
- {ok, erlang:setelement(4, Tracker, Events)}
- end.
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam@otp@port.erl b/aoc2023/build/packages/gleam_otp/src/gleam@otp@port.erl
deleted file mode 100644
index b205739..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam@otp@port.erl
+++ /dev/null
@@ -1,8 +0,0 @@
--module(gleam@otp@port).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export_type([port_/0]).
-
--type port_() :: any().
-
-
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam@otp@supervisor.erl b/aoc2023/build/packages/gleam_otp/src/gleam@otp@supervisor.erl
deleted file mode 100644
index 39118f1..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam@otp@supervisor.erl
+++ /dev/null
@@ -1,322 +0,0 @@
--module(gleam@otp@supervisor).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export([add/2, supervisor/1, worker/1, returning/2, start_spec/1, start/1, application_stopped/0, to_erlang_start_result/1]).
--export_type([spec/2, children/1, child_spec/3, child_start_error/0, message/0, instruction/0, state/1, starter/1, child/1, handle_exit_error/0, application_start_mode/0, application_stop/0]).
-
--type spec(GLS, GLT) :: {spec,
- GLS,
- integer(),
- integer(),
- fun((children(GLS)) -> children(GLT))}.
-
--opaque children(GLU) :: {ready, starter(GLU)} | {failed, child_start_error()}.
-
--opaque child_spec(GLV, GLW, GLX) :: {child_spec,
- fun((GLW) -> {ok, gleam@erlang@process:subject(GLV)} |
- {error, gleam@otp@actor:start_error()}),
- fun((GLW, gleam@erlang@process:subject(GLV)) -> GLX)}.
-
--type child_start_error() :: {child_start_error,
- gleam@option:option(gleam@erlang@process:pid_()),
- gleam@otp@actor:start_error()}.
-
--opaque message() :: {exit, gleam@erlang@process:exit_message()} |
- {retry_restart, gleam@erlang@process:pid_()}.
-
--type instruction() :: start_all | {start_from, gleam@erlang@process:pid_()}.
-
--type state(GLY) :: {state,
- gleam@otp@intensity_tracker:intensity_tracker(),
- starter(GLY),
- gleam@erlang@process:subject(gleam@erlang@process:pid_())}.
-
--type starter(GLZ) :: {starter,
- GLZ,
- gleam@option:option(fun((instruction()) -> {ok,
- {starter(GLZ), instruction()}} |
- {error, child_start_error()}))}.
-
--type child(GMA) :: {child, gleam@erlang@process:pid_(), GMA}.
-
--type handle_exit_error() :: {restart_failed,
- gleam@erlang@process:pid_(),
- gleam@otp@intensity_tracker:intensity_tracker()} |
- too_many_restarts.
-
--type application_start_mode() :: normal |
- {takeover, gleam@erlang@node:node_()} |
- {failover, gleam@erlang@node:node_()}.
-
--type application_stop() :: any().
-
--spec start_child(child_spec(any(), GME, GMF), GME) -> {ok, child(GMF)} |
- {error, child_start_error()}.
-start_child(Child_spec, Argument) ->
- gleam@result:then(
- begin
- _pipe = (erlang:element(2, Child_spec))(Argument),
- gleam@result:map_error(
- _pipe,
- fun(_capture) -> {child_start_error, none, _capture} end
- )
- end,
- fun(Subject) ->
- {ok,
- {child,
- gleam@erlang@process:subject_owner(Subject),
- (erlang:element(3, Child_spec))(Argument, Subject)}}
- end
- ).
-
--spec shutdown_child(
- gleam@erlang@process:pid_(),
- child_spec(any(), any(), any())
-) -> nil.
-shutdown_child(Pid, _) ->
- gleam@erlang@process:send_exit(Pid).
-
--spec perform_instruction_for_child(
- GMS,
- instruction(),
- child_spec(any(), GMS, GMU),
- child(GMU)
-) -> {ok, {child(GMU), instruction()}} | {error, child_start_error()}.
-perform_instruction_for_child(Argument, Instruction, Child_spec, Child) ->
- Current = erlang:element(2, Child),
- case Instruction of
- {start_from, Target} when Target =/= Current ->
- {ok, {Child, Instruction}};
-
- _ ->
- shutdown_child(Current, Child_spec),
- gleam@result:then(
- start_child(Child_spec, Argument),
- fun(Child@1) -> {ok, {Child@1, start_all}} end
- )
- end.
-
--spec add_child_to_starter(
- starter(GNC),
- child_spec(any(), GNC, GNF),
- child(GNF)
-) -> starter(GNF).
-add_child_to_starter(Starter, Child_spec, Child) ->
- Starter@3 = fun(Instruction) ->
- gleam@result:then(case erlang:element(3, Starter) of
- {some, Start} ->
- Start(Instruction);
-
- none ->
- {ok, {Starter, Instruction}}
- end, fun(_use0) ->
- {Starter@1, Instruction@1} = _use0,
- gleam@result:then(
- perform_instruction_for_child(
- erlang:element(2, Starter@1),
- Instruction@1,
- Child_spec,
- Child
- ),
- fun(_use0@1) ->
- {Child@1, Instruction@2} = _use0@1,
- Starter@2 = add_child_to_starter(
- Starter@1,
- Child_spec,
- Child@1
- ),
- {ok, {Starter@2, Instruction@2}}
- end
- )
- end)
- end,
- {starter, erlang:element(3, Child), {some, Starter@3}}.
-
--spec start_and_add_child(starter(GNL), child_spec(any(), GNL, GNO)) -> children(GNO).
-start_and_add_child(State, Child_spec) ->
- case start_child(Child_spec, erlang:element(2, State)) of
- {ok, Child} ->
- {ready, add_child_to_starter(State, Child_spec, Child)};
-
- {error, Reason} ->
- {failed, Reason}
- end.
-
--spec add(children(GNT), child_spec(any(), GNT, GNW)) -> children(GNW).
-add(Children, Child_spec) ->
- case Children of
- {failed, Fail} ->
- {failed, Fail};
-
- {ready, State} ->
- start_and_add_child(State, Child_spec)
- end.
-
--spec supervisor(
- fun((GOB) -> {ok, gleam@erlang@process:subject(GOC)} |
- {error, gleam@otp@actor:start_error()})
-) -> child_spec(GOC, GOB, GOB).
-supervisor(Start) ->
- {child_spec, Start, fun(Argument, _) -> Argument end}.
-
--spec worker(
- fun((GOJ) -> {ok, gleam@erlang@process:subject(GOK)} |
- {error, gleam@otp@actor:start_error()})
-) -> child_spec(GOK, GOJ, GOJ).
-worker(Start) ->
- {child_spec, Start, fun(Argument, _) -> Argument end}.
-
--spec returning(
- child_spec(GOR, GOS, any()),
- fun((GOS, gleam@erlang@process:subject(GOR)) -> GOY)
-) -> child_spec(GOR, GOS, GOY).
-returning(Child, Updater) ->
- {child_spec, erlang:element(2, Child), Updater}.
-
--spec init(spec(any(), GPD)) -> gleam@otp@actor:init_result(state(GPD), message()).
-init(Spec) ->
- Retry = gleam@erlang@process:new_subject(),
- gleam_erlang_ffi:trap_exits(true),
- Selector = begin
- _pipe = gleam_erlang_ffi:new_selector(),
- _pipe@1 = gleam@erlang@process:selecting(
- _pipe,
- Retry,
- fun(Field@0) -> {retry_restart, Field@0} end
- ),
- gleam@erlang@process:selecting_trapped_exits(
- _pipe@1,
- fun(Field@0) -> {exit, Field@0} end
- )
- end,
- Result = begin
- _pipe@2 = {starter, erlang:element(2, Spec), none},
- _pipe@3 = {ready, _pipe@2},
- (erlang:element(5, Spec))(_pipe@3)
- end,
- case Result of
- {ready, Starter} ->
- Restarts = gleam@otp@intensity_tracker:new(
- erlang:element(3, Spec),
- erlang:element(4, Spec)
- ),
- State = {state, Restarts, Starter, Retry},
- {ready, State, Selector};
-
- {failed, Error} ->
- {failed, case erlang:element(3, Error) of
- init_timeout ->
- <<"Child initialisation timed out"/utf8>>;
-
- {init_crashed, Reason} ->
- gleam@string:append(
- <<"Child crashed during initialisation: "/utf8>>,
- gleam@string:inspect(Reason)
- );
-
- {init_failed, Reason@1} ->
- gleam@string:append(
- <<"Child failed to start during initialisation: "/utf8>>,
- gleam@string:inspect(Reason@1)
- )
- end}
- end.
-
--spec handle_exit(gleam@erlang@process:pid_(), state(GPJ)) -> gleam@otp@actor:next(message(), state(GPJ)).
-handle_exit(Pid, State) ->
- Outcome = begin
- _assert_subject = erlang:element(3, erlang:element(3, State)),
- {some, Start} = case _assert_subject of
- {some, _} -> _assert_subject;
- _assert_fail ->
- erlang:error(#{gleam_error => let_assert,
- message => <<"Assertion pattern match failed"/utf8>>,
- value => _assert_fail,
- module => <<"gleam/otp/supervisor"/utf8>>,
- function => <<"handle_exit"/utf8>>,
- line => 293})
- end,
- gleam@result:then(
- begin
- _pipe = erlang:element(2, State),
- _pipe@1 = gleam@otp@intensity_tracker:add_event(_pipe),
- gleam@result:map_error(_pipe@1, fun(_) -> too_many_restarts end)
- end,
- fun(Restarts) ->
- gleam@result:then(
- begin
- _pipe@2 = Start({start_from, Pid}),
- gleam@result:map_error(
- _pipe@2,
- fun(E) ->
- {restart_failed,
- gleam@option:unwrap(
- erlang:element(2, E),
- Pid
- ),
- Restarts}
- end
- )
- end,
- fun(_use0) ->
- {Starter, _} = _use0,
- {ok,
- erlang:setelement(
- 2,
- erlang:setelement(3, State, Starter),
- Restarts
- )}
- end
- )
- end
- )
- end,
- case Outcome of
- {ok, State@1} ->
- gleam@otp@actor:continue(State@1);
-
- {error, {restart_failed, Failed_child, Restarts@1}} ->
- gleam@erlang@process:send(erlang:element(4, State), Failed_child),
- State@2 = erlang:setelement(2, State, Restarts@1),
- gleam@otp@actor:continue(State@2);
-
- {error, too_many_restarts} ->
- {stop,
- {abnormal,
- <<"Child processes restarted too many times within allowed period"/utf8>>}}
- end.
-
--spec loop(message(), state(GPO)) -> gleam@otp@actor:next(message(), state(GPO)).
-loop(Message, State) ->
- case Message of
- {exit, Exit_message} ->
- handle_exit(erlang:element(2, Exit_message), State);
-
- {retry_restart, Pid} ->
- handle_exit(Pid, State)
- end.
-
--spec start_spec(spec(any(), any())) -> {ok,
- gleam@erlang@process:subject(message())} |
- {error, gleam@otp@actor:start_error()}.
-start_spec(Spec) ->
- gleam@otp@actor:start_spec(
- {spec, fun() -> init(Spec) end, 60000, fun loop/2}
- ).
-
--spec start(fun((children(nil)) -> children(any()))) -> {ok,
- gleam@erlang@process:subject(message())} |
- {error, gleam@otp@actor:start_error()}.
-start(Init) ->
- start_spec({spec, nil, 1, 5, Init}).
-
--spec application_stopped() -> application_stop().
-application_stopped() ->
- gleam_otp_external:application_stopped().
-
--spec to_erlang_start_result(
- {ok, gleam@erlang@process:subject(any())} |
- {error, gleam@otp@actor:start_error()}
-) -> {ok, gleam@erlang@process:pid_()} | {error, gleam@dynamic:dynamic_()}.
-to_erlang_start_result(Res) ->
- gleam@otp@actor:to_erlang_start_result(Res).
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam@otp@system.erl b/aoc2023/build/packages/gleam_otp/src/gleam@otp@system.erl
deleted file mode 100644
index 622e5ea..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam@otp@system.erl
+++ /dev/null
@@ -1,43 +0,0 @@
--module(gleam@otp@system).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export([debug_state/1, get_state/1, suspend/1, resume/1]).
--export_type([mode/0, debug_option/0, debug_state/0, status_info/0, system_message/0, do_not_leak/0]).
-
--type mode() :: running | suspended.
-
--type debug_option() :: no_debug.
-
--type debug_state() :: any().
-
--type status_info() :: {status_info,
- gleam@erlang@atom:atom_(),
- gleam@erlang@process:pid_(),
- mode(),
- debug_state(),
- gleam@dynamic:dynamic_()}.
-
--type system_message() :: {resume, fun(() -> nil)} |
- {suspend, fun(() -> nil)} |
- {get_state, fun((gleam@dynamic:dynamic_()) -> nil)} |
- {get_status, fun((status_info()) -> nil)}.
-
--type do_not_leak() :: any().
-
--spec debug_state(list(debug_option())) -> debug_state().
-debug_state(A) ->
- sys:debug_options(A).
-
--spec get_state(gleam@erlang@process:pid_()) -> gleam@dynamic:dynamic_().
-get_state(From) ->
- sys:get_state(From).
-
--spec suspend(gleam@erlang@process:pid_()) -> nil.
-suspend(Pid) ->
- sys:suspend(Pid),
- nil.
-
--spec resume(gleam@erlang@process:pid_()) -> nil.
-resume(Pid) ->
- sys:resume(Pid),
- nil.
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam@otp@task.erl b/aoc2023/build/packages/gleam_otp/src/gleam@otp@task.erl
deleted file mode 100644
index e004284..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam@otp@task.erl
+++ /dev/null
@@ -1,111 +0,0 @@
--module(gleam@otp@task).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export([async/1, try_await/2, await/2, try_await_forever/1, await_forever/1]).
--export_type([task/1, await_error/0, message/1]).
-
--opaque task(FWJ) :: {task,
- gleam@erlang@process:pid_(),
- gleam@erlang@process:pid_(),
- gleam@erlang@process:process_monitor(),
- gleam@erlang@process:selector(message(FWJ))}.
-
--type await_error() :: timeout | {exit, gleam@dynamic:dynamic_()}.
-
--type message(FWK) :: {from_monitor, gleam@erlang@process:process_down()} |
- {from_subject, FWK}.
-
--spec async(fun(() -> FWL)) -> task(FWL).
-async(Work) ->
- Owner = erlang:self(),
- Subject = gleam@erlang@process:new_subject(),
- Pid = gleam@erlang@process:start(
- fun() -> gleam@erlang@process:send(Subject, Work()) end,
- true
- ),
- Monitor = gleam@erlang@process:monitor_process(Pid),
- Selector = begin
- _pipe = gleam_erlang_ffi:new_selector(),
- _pipe@1 = gleam@erlang@process:selecting_process_down(
- _pipe,
- Monitor,
- fun(Field@0) -> {from_monitor, Field@0} end
- ),
- gleam@erlang@process:selecting(
- _pipe@1,
- Subject,
- fun(Field@0) -> {from_subject, Field@0} end
- )
- end,
- {task, Owner, Pid, Monitor, Selector}.
-
--spec assert_owner(task(any())) -> nil.
-assert_owner(Task) ->
- Self = erlang:self(),
- case erlang:element(2, Task) =:= Self of
- true ->
- nil;
-
- false ->
- gleam@erlang@process:send_abnormal_exit(
- Self,
- <<"awaited on a task that does not belong to this process"/utf8>>
- )
- end.
-
--spec try_await(task(FWP), integer()) -> {ok, FWP} | {error, await_error()}.
-try_await(Task, Timeout) ->
- assert_owner(Task),
- case gleam_erlang_ffi:select(erlang:element(5, Task), Timeout) of
- {ok, {from_subject, X}} ->
- gleam_erlang_ffi:demonitor(erlang:element(4, Task)),
- {ok, X};
-
- {ok, {from_monitor, {process_down, _, Reason}}} ->
- {error, {exit, Reason}};
-
- {error, nil} ->
- {error, timeout}
- end.
-
--spec await(task(FWT), integer()) -> FWT.
-await(Task, Timeout) ->
- _assert_subject = try_await(Task, Timeout),
- {ok, Value} = case _assert_subject of
- {ok, _} -> _assert_subject;
- _assert_fail ->
- erlang:error(#{gleam_error => let_assert,
- message => <<"Assertion pattern match failed"/utf8>>,
- value => _assert_fail,
- module => <<"gleam/otp/task"/utf8>>,
- function => <<"await"/utf8>>,
- line => 117})
- end,
- Value.
-
--spec try_await_forever(task(FWV)) -> {ok, FWV} | {error, await_error()}.
-try_await_forever(Task) ->
- assert_owner(Task),
- case gleam_erlang_ffi:select(erlang:element(5, Task)) of
- {from_subject, X} ->
- gleam_erlang_ffi:demonitor(erlang:element(4, Task)),
- {ok, X};
-
- {from_monitor, {process_down, _, Reason}} ->
- {error, {exit, Reason}}
- end.
-
--spec await_forever(task(FWZ)) -> FWZ.
-await_forever(Task) ->
- _assert_subject = try_await_forever(Task),
- {ok, Value} = case _assert_subject of
- {ok, _} -> _assert_subject;
- _assert_fail ->
- erlang:error(#{gleam_error => let_assert,
- message => <<"Assertion pattern match failed"/utf8>>,
- value => _assert_fail,
- module => <<"gleam/otp/task"/utf8>>,
- function => <<"await_forever"/utf8>>,
- line => 149})
- end,
- Value.
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam_otp.app.src b/aoc2023/build/packages/gleam_otp/src/gleam_otp.app.src
deleted file mode 100644
index 5c52295..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam_otp.app.src
+++ /dev/null
@@ -1,15 +0,0 @@
-{application, gleam_otp, [
- {vsn, "0.8.0"},
- {applications, [gleam_erlang,
- gleam_stdlib,
- gleeunit]},
- {description, "Fault tolerant multicore Gleam programs with OTP"},
- {modules, [gleam@otp@actor,
- gleam@otp@intensity_tracker,
- gleam@otp@port,
- gleam@otp@supervisor,
- gleam@otp@system,
- gleam@otp@task,
- gleam_otp]},
- {registered, []}
-]}.
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam_otp.erl b/aoc2023/build/packages/gleam_otp/src/gleam_otp.erl
deleted file mode 100644
index 9381ad2..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam_otp.erl
+++ /dev/null
@@ -1,28 +0,0 @@
--module(gleam_otp).
--compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]).
-
--export([main/0]).
-
--spec spawn_task(integer()) -> gleam@otp@task:task(nil).
-spawn_task(I) ->
- gleam@otp@task:async(fun() -> case (I rem 500) =:= 0 of
- true ->
- gleam@io:println(
- <<"Hello from "/utf8, (gleam@int:to_string(I))/binary>>
- );
-
- false ->
- nil
- end end).
-
--spec main() -> integer().
-main() ->
- gleam@io:debug(
- gleam_otp_test_external:get_message_queue_length(erlang:self())
- ),
- _pipe = gleam@list:range(0, 1000000),
- _pipe@1 = gleam@list:map(_pipe, fun spawn_task/1),
- gleam@list:each(_pipe@1, fun gleam@otp@task:await_forever/1),
- gleam@io:debug(
- gleam_otp_test_external:get_message_queue_length(erlang:self())
- ).
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam_otp.gleam b/aoc2023/build/packages/gleam_otp/src/gleam_otp.gleam
deleted file mode 100644
index 69cdd5b..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam_otp.gleam
+++ /dev/null
@@ -1,27 +0,0 @@
-import gleam/io
-import gleam/int
-import gleam/list
-import gleam/otp/task
-import gleam/erlang/process.{type Pid}
-
-@external(erlang, "gleam_otp_test_external", "get_message_queue_length")
-fn get_message_queue_length(pid pid: Pid) -> Int
-
-fn spawn_task(i) {
- task.async(fn() {
- case i % 500 == 0 {
- True -> io.println("Hello from " <> int.to_string(i))
- False -> Nil
- }
- })
-}
-
-pub fn main() {
- io.debug(get_message_queue_length(process.self()))
-
- list.range(0, 1_000_000)
- |> list.map(spawn_task)
- |> list.each(task.await_forever)
-
- io.debug(get_message_queue_length(process.self()))
-}
diff --git a/aoc2023/build/packages/gleam_otp/src/gleam_otp_external.erl b/aoc2023/build/packages/gleam_otp/src/gleam_otp_external.erl
deleted file mode 100644
index 8910a67..0000000
--- a/aoc2023/build/packages/gleam_otp/src/gleam_otp_external.erl
+++ /dev/null
@@ -1,43 +0,0 @@
--module(gleam_otp_external).
-
--export([application_stopped/0, convert_system_message/2]).
-
-% TODO: support other system messages
-% {replace_state, StateFn}
-% {change_code, Mod, Vsn, Extra}
-% {terminate, Reason}
-% {debug, {log, Flag}}
-% {debug, {trace, Flag}}
-% {debug, {log_to_file, FileName}}
-% {debug, {statistics, Flag}}
-% {debug, no_debug}
-% {debug, {install, {Func, FuncState}}}
-% {debug, {install, {FuncId, Func, FuncState}}}
-% {debug, {remove, FuncOrId}}
-% GetStatus(Subject(StatusInfo))
-convert_system_message({From, Ref}, Request) when is_pid(From) ->
- Reply = fun(Msg) ->
- erlang:send(From, {Ref, Msg}),
- nil
- end,
- System = fun(Callback) ->
- {system, {Request, Callback}}
- end,
- case Request of
- get_status -> System(fun(Status) -> Reply(process_status(Status)) end);
- get_state -> System(Reply);
- suspend -> System(fun() -> Reply(ok) end);
- resume -> System(fun() -> Reply(ok) end);
- Other -> {unexpeceted, Other}
- end.
-
-process_status({status_info, Module, Parent, Mode, DebugState, State}) ->
- Data = [
- get(), Mode, Parent, DebugState,
- [{header, "Status for Gleam process " ++ pid_to_list(self())},
- {data, [{'Status', Mode}, {'Parent', Parent}, {'State', State}]}]
- ],
- {status, self(), {module, Module}, Data}.
-
-application_stopped() ->
- ok.