Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v0.33.0 - 2024-12-03

- The `gleam/erlang/process` module gains the `receive_forever` function.

## v0.32.0 - 2024-11-28

- The `gleam/os` environment functions have been deprecated in favour of the
Expand Down
13 changes: 8 additions & 5 deletions src/gleam/erlang/process.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,17 @@ pub fn send(subject: Subject(message), message: message) -> Nil {
///
/// The `within` parameter specifies the timeout duration in milliseconds.
///
@external(erlang, "gleam_erlang_ffi", "receive")
pub fn receive(
from subject: Subject(message),
within timeout: Int,
) -> Result(message, Nil) {
new_selector()
|> selecting(subject, fn(x) { x })
|> select(within: timeout)
}
) -> Result(message, Nil)

/// Receive a message that has been sent to current process using the `Subject`.
///
/// Same as `receive` but waits forever and returns the message as is.
@external(erlang, "gleam_erlang_ffi", "receive")
pub fn receive_forever(from subject: Subject(message)) -> message

/// A type that enables a process to wait for messages from multiple `Subject`s
/// at the same time, returning whichever message arrives first.
Expand Down
16 changes: 15 additions & 1 deletion src/gleam_erlang_ffi.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
map_selector/2, merge_selector/2, flush_messages/0,
priv_directory/1, connect_node/1, register_process/2, unregister_process/1,
process_named/1, identity/1, pid_from_dynamic/1, reference_from_dynamic/1,
port_from_dynamic/1
port_from_dynamic/1, 'receive'/1, 'receive'/2
]).

-spec atom_from_string(binary()) -> {ok, atom()} | {error, atom_not_loaded}.
Expand Down Expand Up @@ -147,6 +147,20 @@ select({selector, Handlers}, Timeout) ->
{error, nil}
end.

'receive'({subject, _Pid, Ref}) ->
receive
{Ref, Message} ->
Message
end.

'receive'({subject, _Pid, Ref}, Timeout) ->
receive
{Ref, Message} ->
{ok, Message}
after Timeout ->
{error, nil}
end.

demonitor({_, Reference}) ->
erlang:demonitor(Reference, [flush]).

Expand Down
21 changes: 21 additions & 0 deletions test/gleam/erlang/process_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ pub fn receive_test() {
let assert Error(Nil) = process.receive(subject, 0)
}

pub fn receive_forever_test() {
let subject = process.new_subject()

// Send message from self
process.send(subject, 0)

// Send message from another process
process.start(
fn() {
process.send(subject, 1)
process.send(subject, 2)
},
linked: True,
)

// Assert all the messages arrived
let assert 0 = process.receive_forever(subject)
let assert 1 = process.receive_forever(subject)
let assert 2 = process.receive_forever(subject)
}

pub fn is_alive_test() {
let pid = process.start(fn() { Nil }, False)
process.sleep(5)
Expand Down
Loading