use std::future::Future;
use crate::executor;
pub struct RuntimeBuilder {
num_workers: usize,
}
impl RuntimeBuilder {
fn new() -> Self {
Self { num_workers: 1 }
}
pub fn thread_per_core(self) -> Self {
Self { num_workers: 1 }
}
pub fn worker_threads(self, n: usize) -> Self {
assert!(n > 0, "worker_threads must be at least 1");
Self { num_workers: n }
}
pub fn enable_io(self) -> Self {
self
}
pub fn enable_time(self) -> Self {
self
}
pub fn build(self) -> std::io::Result<Runtime> {
Ok(Runtime {
num_workers: self.num_workers,
})
}
}
pub struct Runtime {
num_workers: usize,
}
impl Runtime {
pub fn builder() -> RuntimeBuilder {
RuntimeBuilder::new()
}
pub fn block_on<F>(&self, future: F) -> F::Output
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
if self.num_workers <= 1 {
executor::block_on_with_spawn(future)
} else {
executor::block_on_multi(future, self.num_workers)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_creates_runtime() {
let rt = Runtime::builder()
.thread_per_core()
.enable_io()
.enable_time()
.build()
.unwrap();
let v = rt.block_on(async { 42u32 });
assert_eq!(v, 42);
}
#[test]
fn runtime_spawn_works() {
let rt = Runtime::builder().build().unwrap();
let result = rt.block_on(async {
let jh = crate::spawn(async { 100u32 });
jh.await.unwrap()
});
assert_eq!(result, 100);
}
#[test]
fn runtime_worker_threads_api() {
let rt = Runtime::builder()
.worker_threads(2)
.build()
.unwrap();
let v = rt.block_on(async { 7u32 });
assert_eq!(v, 7);
}
#[test]
fn runtime_multi_thread_spawn() {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
let rt = Runtime::builder().worker_threads(4).build().unwrap();
let counter = Arc::new(AtomicUsize::new(0));
let c = counter.clone();
rt.block_on(async move {
let mut handles = Vec::new();
for _ in 0..50 {
let cc = c.clone();
handles.push(crate::spawn(async move {
cc.fetch_add(1, Ordering::SeqCst);
}));
}
for h in handles {
h.await.unwrap();
}
});
assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 50);
}
#[test]
#[should_panic(expected = "worker_threads must be at least 1")]
fn runtime_zero_workers_panics() {
Runtime::builder().worker_threads(0).build().unwrap();
}
}