Skip to content

Commit 6dae414

Browse files
authored
add support for 0 capacity to Mailbox (#3972)
1 parent 4dca30c commit 6dae414

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

.changeset/silent-chefs-sit.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
add support for 0 capacity to Mailbox

packages/effect/src/internal/mailbox.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
8585
private messagesChunk = Chunk.empty<A>()
8686
constructor(
8787
readonly scheduler: Scheduler,
88-
readonly capacity: number,
88+
private capacity: number,
8989
readonly strategy: "suspend" | "dropping" | "sliding"
9090
) {
9191
super()
@@ -100,6 +100,11 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
100100
case "dropping":
101101
return exitFalse
102102
case "suspend":
103+
if (this.capacity <= 0 && this.state.takers.size > 0) {
104+
this.messages.push(message)
105+
this.releaseTaker()
106+
return exitTrue
107+
}
103108
return this.offerRemainingSingle(message)
104109
case "sliding":
105110
this.unsafeTake()
@@ -120,6 +125,10 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
120125
this.unsafeTake()
121126
this.messages.push(message)
122127
return true
128+
} else if (this.capacity <= 0 && this.state.takers.size > 0) {
129+
this.messages.push(message)
130+
this.releaseTaker()
131+
return true
123132
}
124133
return false
125134
}
@@ -164,7 +173,9 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
164173
this.scheduleReleaseTaker()
165174
return []
166175
}
167-
const free = this.capacity - this.messages.length - this.messagesChunk.length
176+
const free = this.capacity <= 0
177+
? this.state.takers.size
178+
: this.capacity - this.messages.length - this.messagesChunk.length
168179
if (free === 0) {
169180
return Arr.fromIterable(messages)
170181
}
@@ -274,6 +285,11 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
274285
message = this.messages[0]
275286
this.messagesChunk = Chunk.drop(Chunk.unsafeFromArray(this.messages), 1)
276287
this.messages = []
288+
} else if (this.capacity <= 0 && this.state.offers.size > 0) {
289+
this.capacity = 1
290+
this.releaseCapacity()
291+
this.capacity = 0
292+
return this.messages.length > 0 ? core.exitSucceed(this.messages.pop()!) : undefined
277293
} else {
278294
return undefined
279295
}
@@ -422,6 +438,11 @@ class MailboxImpl<A, E> extends Effectable.Class<readonly [messages: Chunk.Chunk
422438
const messages = Chunk.unsafeFromArray(this.messages)
423439
this.messages = []
424440
return messages
441+
} else if (this.state._tag !== "Done" && this.state.offers.size > 0) {
442+
this.capacity = 1
443+
this.releaseCapacity()
444+
this.capacity = 0
445+
return Chunk.of(this.messages.pop()!)
425446
}
426447
return empty
427448
}

packages/effect/test/Mailbox.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,17 @@ describe("Mailbox", () => {
168168
yield* Effect.yieldNow()
169169
assert.isNotNull(fiber.unsafePoll())
170170
}))
171+
172+
it.effect("bounded 0 capacity", () =>
173+
Effect.gen(function*() {
174+
const mailbox = yield* Mailbox.make<number>(0)
175+
yield* mailbox.offer(1).pipe(Effect.fork)
176+
let result = yield* mailbox.take
177+
assert.strictEqual(result, 1)
178+
179+
const fiber = yield* mailbox.take.pipe(Effect.fork)
180+
yield* mailbox.offer(2)
181+
result = yield* Fiber.join(fiber)
182+
assert.strictEqual(result, 2)
183+
}))
171184
})

0 commit comments

Comments
 (0)