A coroutine is a pausable computation: it can yield values to its caller, suspend, then resume or finish with a return value. Rust’s coroutine feature is experimental and nightly-only. section 8.2
Rust coroutines make it possible to:
- Separate values yielded during execution from the final return value. section 8.2
- Express stream iteration, cooperative multitasking, and event loops without relying on threads or callbacks. section 8.2
Listing 8.5 std::ops::Coroutine trait definition from Rust standard library
pub trait Coroutine<R = ()> { #1
type Yield; #2
type Return; #3
// Required method
fn resume(
self: Pin<&mut Self>, #4
arg: R
) -> CoroutineState<Self::Yield, Self::Return>;
}
The Coroutine trait’s resume method takes a pinned mutable reference and reports either a yielded value or completion. section 8.2
Listing 8.6 A basic coroutine in Rust
#![feature(coroutines, #1
coroutine_trait, #1
stmt_expr_attributes)] #1
use core::f64::consts::PI;
use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;
fn main() {
let mut yield_pi = #[coroutine] #2
|| { #3
yield PI; #4
"Coroutine complete!" #5
};
loop {
match Pin::new(&mut yield_pi).resume(()) { #6
CoroutineState::Yielded(val) => { #7
dbg!(&val);
}
CoroutineState::Complete(val) => { #8
dbg!(&val);
break;
}
}
}
}
A feature-gated coroutine yields π, then completes with a string, showing the two value paths in a small example. section 8.2
Listing 8.7 Implementing Iterator atop a coroutine
struct CargoTomlReader {
coroutine:
Pin<Box<dyn Coroutine< #1
Yield = (usize, String), #1
Return = () #1
>>>, #1
}
impl CargoTomlReader {
fn new() -> io::Result<Self> {
let file = File::open("Cargo.toml")?;
let mut reader = BufReader::new(file);
let mut line_number: usize = 0; #2
let coroutine = Box::pin(
#[coroutine] #3
move || loop { #4
let mut line = String::new();
line_number += 1; #5
match reader.read_line(&mut line) {
Ok(0) => return, #6
Ok(_) => yield (line_number, line), #7
_ => return, #8
}
}
);
let coroutine = Box::pin(
#[coroutine]
move || loop {
let mut line = String::new();
line_number += 1;
match reader.read_line(&mut line) {
Ok(0) => return,
Ok(_) => yield (line_number, line),
_ => return,
}
},
);
Ok(Self { coroutine })
}
}
impl Iterator for CargoTomlReader {
type Item = (usize, String);
fn next(&mut self) -> Option<Self::Item> {
match self.coroutine.as_mut().resume(()) { #9
CoroutineState::Yielded(val) => Some(val),
CoroutineState::Complete(()) => None,
}
}
}
A coroutine-backed reader yields numbered lines from Cargo.toml and is used as an iterator. section 8.2







