aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-08-18 23:31:36 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-08-18 23:31:36 -0400
commit9e07c6adc7a0616eec40e78024a8501ec7d96559 (patch)
tree92542ba27e13152a8305deb6f0cda3a952ac8835
parent1f16d63ac783d9b1bb1d4a65676476d14f0af713 (diff)
Add Channel:peek()
-rw-r--r--api/channels.md26
-rw-r--r--builtins/channel.c10
-rw-r--r--builtins/channel.h2
-rw-r--r--compile.c4
-rw-r--r--test/threads.tm5
-rw-r--r--typecheck.c1
6 files changed, 47 insertions, 1 deletions
diff --git a/api/channels.md b/api/channels.md
index dbb6707a..ca7ce17e 100644
--- a/api/channels.md
+++ b/api/channels.md
@@ -93,6 +93,32 @@ The item removed from the channel.
**Example:**
```markdown
+>> channel:peek()
+= "Hello"
+```
+
+---
+
+### `peek`
+
+**Description:**
+Returns the next item that will come out of the channel, but without removing
+it. If the channel is empty, it waits until an item is available.
+
+**Usage:**
+```markdown
+peek(channel:|T|) -> T
+```
+
+**Parameters:**
+
+- `channel`: The channel from which to remove an item.
+
+**Returns:**
+The item removed from the channel.
+
+**Example:**
+```markdown
>> channel:get()
= "Hello"
```
diff --git a/builtins/channel.c b/builtins/channel.c
index f47a0b11..9360bcfc 100644
--- a/builtins/channel.c
+++ b/builtins/channel.c
@@ -68,6 +68,16 @@ public void Channel$get(channel_t *channel, void *out, int64_t item_size, int64_
(void)pthread_cond_signal(&channel->cond);
}
+public void Channel$peek(channel_t *channel, void *out, int64_t item_size)
+{
+ (void)pthread_mutex_lock(&channel->mutex);
+ while (channel->items.length == 0)
+ pthread_cond_wait(&channel->cond, &channel->mutex);
+ memcpy(out, channel->items.data, item_size);
+ (void)pthread_mutex_unlock(&channel->mutex);
+ (void)pthread_cond_signal(&channel->cond);
+}
+
public array_t Channel$view(channel_t *channel)
{
(void)pthread_mutex_lock(&channel->mutex);
diff --git a/builtins/channel.h b/builtins/channel.h
index 3b2d2c16..b8282374 100644
--- a/builtins/channel.h
+++ b/builtins/channel.h
@@ -15,6 +15,8 @@ void Channel$give(channel_t *channel, const void *item, int64_t padded_item_size
void Channel$give_all(channel_t *channel, array_t to_give, int64_t padded_item_size);
void Channel$get(channel_t *channel, void *out, int64_t item_size, int64_t padded_item_size);
#define Channel$get_value(channel, t, padded_item_size) ({ t _val; Channel$get(channel, &_val, sizeof(t), padded_item_size); _val; })
+void Channel$peek(channel_t *channel, void *out, int64_t item_size);
+#define Channel$peek_value(channel, t) ({ t _val; Channel$peek(channel, &_val, sizeof(t)); _val; })
void Channel$clear(channel_t *channel);
array_t Channel$view(channel_t *channel);
uint32_t Channel$hash(const channel_t **channel, const TypeInfo *type);
diff --git a/compile.c b/compile.c
index 08b56938..477913c7 100644
--- a/compile.c
+++ b/compile.c
@@ -2377,6 +2377,10 @@ CORD compile(env_t *env, ast_t *ast)
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
(void)compile_arguments(env, ast, NULL, call->args);
return CORD_all("Channel$get_value(", self, ", ", compile_type(item_t), ", ", padded_item_size, ")");
+ } else if (streq(call->name, "peek")) {
+ CORD self = compile_to_pointer_depth(env, call->self, 0, false);
+ (void)compile_arguments(env, ast, NULL, call->args);
+ return CORD_all("Channel$peek_value(", self, ", ", compile_type(item_t), ")");
} else if (streq(call->name, "clear")) {
CORD self = compile_to_pointer_depth(env, call->self, 0, false);
(void)compile_arguments(env, ast, NULL, call->args);
diff --git a/test/threads.tm b/test/threads.tm
index e8d83f4a..f7acd013 100644
--- a/test/threads.tm
+++ b/test/threads.tm
@@ -2,6 +2,10 @@ enum Job(Increment(x:Int), Decrement(x:Int))
func main():
jobs := |:Job; max_size=2|
+ >> jobs:give(Increment(5))
+ >> jobs:peek()
+ = Job.Increment(x=5)
+
results := |:Int; max_size|
>> thread := Thread.new(func():
//! In another thread!
@@ -13,7 +17,6 @@ func main():
>> results:give(x-1)
)
- >> jobs:give(Increment(5))
>> jobs:give(Decrement(100))
>> jobs:give(Decrement(100))
>> jobs:give(Decrement(100))
diff --git a/typecheck.c b/typecheck.c
index 805f83e0..2fb8556d 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -774,6 +774,7 @@ type_t *get_type(env_t *env, ast_t *ast)
else if (streq(call->name, "get")) return Match(self_value_t, ChannelType)->item_type;
else if (streq(call->name, "give")) return Type(VoidType);
else if (streq(call->name, "give_all")) return Type(VoidType);
+ else if (streq(call->name, "peek")) return Match(self_value_t, ChannelType)->item_type;
else if (streq(call->name, "view")) return Type(ArrayType, .item_type=Match(self_value_t, ChannelType)->item_type);
else code_err(ast, "There is no '%s' method for arrays", call->name);
}