Expand description
dewit is a library that allows the caller to control how code is scheduled and executed separately from how data flows through it.
dewit is #![no_std], no alloc, and #![forbid(unsafe_code)] by
default.
§Notes
Most of this is… at best semi-functional. I’m writing it on a private git forge. You should probably not use this. Hopefully a future version will be more fleshed out and less actively in flux. This is pretty heavily inspired by chumsky’s approach to… everything. They do it much better.
§Motivating example
dewit makes it possible to define code as a Task
with defined inputs and outputs, then request a specific execution mode.
use dewit::prelude::*;
use std::{fs::File, io, path::Path};
fn recursively_count_files<'a>() -> impl Task<'a, &'a Path, io::Result<usize>> {
// TODO: actually write this example :)
io(async move |path: &Path| {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
Ok(path.as_os_str().len())
})
}
#[tokio::main]
async fn main() -> io::Result<()> {
let (combinator_count, mode_count) =
// TODO: try_join
join(
recursively_count_files(),
recursively_count_files(),
)
.run_async((Path::new("./src/combinators"), Path::new("./src/mode")))
.await;
assert_eq!(combinator_count?, 17);
assert_eq!(mode_count?, 10);
Ok(())
}Code which embeds a requirement to use a dependency, e.g.
rayon as part of its execution
“leaks” the usage of rayon into its environment, when the motivation of
the author may just be to execute more quickly. That can cause headaches
when a consumer doesn’t want to potentially use all of their CPU.
Similarly, when writing code that consumes an async API, it can be a
headache to write an API for both the async and non-async versions of
the function when all the author wants is to block until the result is
available.
§Anti-motivation
An effort is made to be relatively efficient, but a hand-written implementation that uses the underlying concurrency primitives in a well-reasoned and careful way will likely be faster and use fewer resources.
§Recommendations
Library dependents should avoid depending on any Mode
providing features unless strictly necessary, to avoid pulling in unnecessary
dependencies in client code.
§Feature flags
-
alloc: Support for combinators which require allocation. -
std: Support for standard library features in combinators and modes. -
async(enablesalloc): Provides an implementation of an asyncMode,Async. -
blocking(enablesalloc,std): Provides an implementation of a blockingMode,Blocking. -
rayon(enablesalloc,std): Provides implementations of work-stealing,ScopedRayonandRayon. Whenblockingis enabled, additional blocking versions of these will be available.
Modules§
- combinators
- Reified execution flow.
- mode
- The way in which a task is executed.
- prelude
- Commonly used features of dewit.
- prelude_
no_ combinators - The prelude without exported combinators to avoid cluttering the global namespace.
- task
- A Task is a strategy by which data is transformed. It is not entirely unlike
an even-more-restrictive function definition with annotations for use by
Modeimplementations for scheduling.