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
2 changes: 2 additions & 0 deletions docs/superpowers/plans/2026-07-28-rust-async-course.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Para cada capítulo, antes de pasar al siguiente:
- [x] #28 Escribir capítulo, diagrama, ejemplos y ejercicios.
- [ ] Capítulo 09: canales y sincronización asíncrona.
- [x] #29 Especificar backpressure, cierre y sincronización.
- [x] #30 Implementar y probar modelos de coordinación.
- [ ] #32 Escribir capítulo, diagrama, ejemplos y ejercicios.

### Milestone 4: Composición avanzada

Expand Down
36 changes: 36 additions & 0 deletions src/async_channels.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Modelos mínimos de canales acotados con Tokio.

use tokio::sync::mpsc;

/// Comprueba que un canal acotado comunica la falta de capacidad.
///
/// La función usa `try_send` para observar presión de cola sin introducir una
/// espera temporal: el segundo mensaje no cabe mientras nadie reciba el primero.
pub fn bounded_channel_applies_backpressure() -> bool {
let (sender, _receiver) = mpsc::channel(1);

sender.try_send(1).is_ok() && sender.try_send(2).is_err()
}

/// Envía mensajes, cierra todos los emisores y drena la cola en orden FIFO.
pub async fn drain_after_senders_close() -> Vec<u8> {
let (sender, mut receiver) = mpsc::channel(2);
sender.send(1).await.expect("el receptor sigue abierto");
sender.send(2).await.expect("el receptor sigue abierto");
drop(sender);

let mut received = Vec::new();
while let Some(message) = receiver.recv().await {
received.push(message);
}

received
}

/// Indica que un emisor no puede confirmar entrega tras el cierre del receptor.
pub async fn receiver_closure_rejects_send() -> bool {
let (sender, receiver) = mpsc::channel(1);
drop(receiver);

sender.send(1).await.is_err()
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#![forbid(unsafe_code)]

pub mod async_channels;
pub mod cooperative;
pub mod coordination;
pub mod educational_future;
Expand Down
18 changes: 18 additions & 0 deletions tests/async_channels_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use rust_async::async_channels::{
bounded_channel_applies_backpressure, drain_after_senders_close, receiver_closure_rejects_send,
};

#[tokio::test]
async fn bounded_channel_reports_full_queue() {
assert!(bounded_channel_applies_backpressure());
}

#[tokio::test]
async fn receiver_drains_messages_before_observing_sender_closure() {
assert_eq!(drain_after_senders_close().await, vec![1, 2]);
}

#[tokio::test]
async fn closed_receiver_rejects_new_messages() {
assert!(receiver_closure_rejects_send().await);
}
Loading