3 unstable releases
0.2.1 | Apr 22, 2022 |
---|---|
0.2.0 | Feb 25, 2022 |
0.1.0 | Feb 7, 2022 |
#571 in Game dev
87KB
1K
SLoC
cosync
This crate provides a single-threaded, sequential, parameterized async runtime. In other words, this creates coroutines, specifically targeting video game logic, though cosync
is suitable for creating any sequences of directions which take time.
Here's a basic Cosync
example:
use cosync::{Cosync, CosyncInput};
fn main() {
// the type parameter is the *value* which other functions will get.
let mut cosync: Cosync<i32> = Cosync::new();
let example_move = 20;
// there are a few ways to queue tasks, but here's a simple one:
cosync.queue(move |mut input: CosyncInput<i32>| async move {
// set our input to `example_move`...
*input.get() = example_move;
});
let mut value = 0;
cosync.run_until_stall(&mut value);
// okay, we ran our future, and since it has no awaits, we know
// it will have completed!
assert_eq!(value, example_move);
}
Additionally, Cosync
can handle unsized Ts, including dynamic dispatch:
use cosync::Cosync;
// unsized type
let mut cosync: Cosync<str> = Cosync::new();
cosync.queue(|mut input| async move {
let input_guard = input.get();
let inner_str: &str = &input_guard;
println!("inner str = {}", inner_str);
});
// dynamic dispatch
trait DynDispatch {
fn test(&self);
}
let mut cosync_dyn: Cosync<dyn DynDispatch> = Cosync::new();
cosync_dyn.queue(|mut input| async move {
let inner: &mut dyn DynDispatch = &mut *input.get();
});
Cosync
is not multithreaded, nor parallel -- it works entirely sequentially. Think of it as a useful way of expressing code that is multistaged and takes time to complete, that you want to do later. Moving cameras, staging actors, and performing animations often work well with Cosync
. Loading asset files, doing mathematical computations, or doing IO should be done by more easily multithreaded runtimes such as switchyard.
This crate exposes two methods for driving the runtime: run_until_stall
and run_blocking
. You generally want run_until_stall
, which attempts process as much of the queue as it can, until it cannot (ie, a future returns Poll::Pending
), at which point control is returned to the caller.
There are three ways to make new tasks. First, the Cosync
struct itself has a queue
method on it. Secondly, each task gets a CosyncInput<T>
as a parameter, which has get
(to get access to your &mut T
) and queue
to queue another task (which is at the end of the queue, not necessarily after the task which added it). Lastly, you can create a CosyncQueueHandle
with Cosync::create_queue_handle
which is Send
and can be given to other threads to create new tasks for the Cosync
.
This crate depends on only std
. It is in an early state of development, but is in production ready state right now.