Skip to content

Commit

Permalink
v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lpil committed Jan 2, 2024
1 parent 82d9dd3 commit 62bf1b1
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 69 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## v1.0.0 - 2024-01-02

- Initial release.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,25 @@
[![Package Version](https://img.shields.io/hexpm/v/process_waiter)](https://hex.pm/packages/process_waiter)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/process_waiter/)

## Quick start

```sh
gleam run # Run the project
gleam test # Run the tests
gleam shell # Run an Erlang shell
gleam add process_waiter
```
```gleam
import gleam/erlang/process
import process_waiter
## Installation
pub fn main() {
// Start some processes
let pid1 = process.spawn(fn() { process.sleep(500) })
let pid2 = process.spawn(fn() { process.sleep(500) })
let pid3 = process.spawn(fn() { process.sleep(500) })
If available on Hex this package can be added to your Gleam project:
// Wait for them to exit
process_waiter.wait([pid1, pid2, pid3])
```sh
gleam add process_waiter
// The processes have now finished
process.is_alive(pid1) // -> False
}
```

and its documentation can be found at <https://hexdocs.pm/process_waiter>.
Documentation can be found at <https://hexdocs.pm/process_waiter>.
14 changes: 7 additions & 7 deletions gleam.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name = "process_waiter"
version = "1.0.0"
description = "Wait for Erlang processes to exit"

# Fill out these fields if you intend to generate HTML documentation or publish
# your project to the Hex package manager.
#
# description = ""
# licences = ["Apache-2.0"]
# repository = { type = "github", user = "username", repo = "project" }
# links = [{ title = "Website", href = "https://gleam.run" }]
licences = ["Apache-2.0"]
repository = { type = "github", user = "lpil", repo = "process-waiter" }
links = [
{ title = "Website", href = "https://gleam.run" },
{ title = "Sponsor", href = "https://github.com/sponsors/lpil" },
]

[dependencies]
gleam_stdlib = "~> 0.32"
Expand Down
65 changes: 17 additions & 48 deletions src/process_waiter.gleam
Original file line number Diff line number Diff line change
@@ -1,64 +1,33 @@
import gleam/erlang/process.{
type Pid, type ProcessMonitor, type Selector, type Subject,
}
import gleam/erlang/process.{type Pid, type ProcessMonitor, type Selector}
import gleam/dict.{type Dict}
import gleam/list

// TODO: document
pub opaque type ProcessWaiter {
ProcessWaiter(pids: List(Pid), monitors: Dict(Pid, ProcessMonitor))
}

// TODO: document
pub fn new() -> ProcessWaiter {
ProcessWaiter([], dict.new())
}

// TODO: document
pub fn add_pid(waiter: ProcessWaiter, pid: Pid) -> ProcessWaiter {
ProcessWaiter(..waiter, pids: [pid, ..waiter.pids])
}

// TODO: document
pub fn add_subject(waiter: ProcessWaiter, subject: Subject(a)) -> ProcessWaiter {
add_pid(waiter, process.subject_owner(subject))
}

// TODO: document
pub fn wait_forever(waiter: ProcessWaiter) -> Result(Nil, ProcessWaiter) {
let waiter = convert_pids_to_monitors(waiter)
let selector = selector_for_monitors(waiter.monitors)
wait_forever_loop(waiter, selector)
/// Wait for a list of processes to exit.
///
pub fn await_forever(pids: List(Pid)) -> Nil {
let monitors =
pids
|> list.map(fn(pid) { #(pid, process.monitor_process(pid)) })
|> dict.from_list
let selector = selector_for_monitors(monitors)
await_forever_loop(monitors, selector)
}

fn wait_forever_loop(
waiter: ProcessWaiter,
fn await_forever_loop(
pids: Dict(Pid, ProcessMonitor),
selector: Selector(Pid),
) -> Result(Nil, ProcessWaiter) {
) -> Nil {
let pid = process.select_forever(selector)
let waiter = remove_monitor(waiter, pid)
case dict.size(waiter.monitors) {
0 -> Ok(Nil)
_ -> wait_forever_loop(waiter, selector)
let pids = dict.delete(pids, pid)
case dict.size(pids) {
0 -> Nil
_ -> await_forever_loop(pids, selector)
}
}

fn remove_monitor(waiter: ProcessWaiter, pid: Pid) -> ProcessWaiter {
let monitors = dict.delete(waiter.monitors, pid)
ProcessWaiter(..waiter, monitors: monitors)
}

fn selector_for_monitors(monitors: Dict(Pid, ProcessMonitor)) -> Selector(Pid) {
dict.values(monitors)
|> list.fold(process.new_selector(), fn(selector, monitor) {
process.selecting_process_down(selector, monitor, fn(msg) { msg.pid })
})
}

fn convert_pids_to_monitors(waiter: ProcessWaiter) -> ProcessWaiter {
let monitors =
waiter.pids
|> list.map(fn(pid) { #(pid, process.monitor_process(pid)) })
|> dict.from_list
ProcessWaiter(monitors: monitors, pids: [])
}
5 changes: 1 addition & 4 deletions test/process_waiter_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ pub fn wait_forever_test() {
let pid1 = process.start(fn() { process.sleep(500) }, True)
let pid2 = process.start(fn() { process.sleep(500) }, True)

process_waiter.new()
|> process_waiter.add_pid(pid1)
|> process_waiter.add_pid(pid2)
|> process_waiter.wait_forever
process_waiter.await_forever([pid1, pid2])

let assert False = process.is_alive(pid1)
let assert False = process.is_alive(pid1)
Expand Down

0 comments on commit 62bf1b1

Please sign in to comment.