Skip to content
Open
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
35 changes: 29 additions & 6 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,35 @@ env:

jobs:
build:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy

- name: Clippy
run: cargo clippy --all --all-features --all-targets --examples
- name: Tests
run: cargo test --all

wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Clippy
run: cargo clippy --all --all-features --all-targets --examples
- name: Tests
run: cargo test --all
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
components: clippy

- name: Clippy (wasm32)
run: cargo clippy --all --all-features --all-targets --examples --target wasm32-unknown-unknown

- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0

- name: Tests (wasm32, node)
# doctests aren't run here: rustdoc's doctest harness doesn't integrate
# cleanly with wasm-bindgen-test-runner (should_panic detection breaks).
# Doctests are still covered by the native `build` job above so it should be safe.
run: wasm-pack test --node --lib
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Support for the trailing comma in the `deps` macro ([PR #37](https://github.com/teloxide/dptree/pull/37)).
- Support for the `wasm32-unknown-unknown` target via `MaybeSend`/`MaybeSync` traits and a conditional `BoxFuture` alias ([PR #38](https://github.com/teloxide/dptree/issues/38)).

## 0.5.1 - 2025-07-10

Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ futures = { version = "0.3", default-features = false, features = ["alloc"] }
colored = "3"

[dev-dependencies]
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "sync"] }
tokio = { version = "1", features = ["rt", "macros", "sync"] }
maplit = "1"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs", "-Znormalize-docs"]
Expand Down
2 changes: 1 addition & 1 deletion examples/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct C;
#[derive(Clone)]
struct D;

#[tokio::main]
#[tokio::main(flavor = "current_thread")]
Comment thread
YouKnow-sys marked this conversation as resolved.
async fn main() {
let h: Handler<D> = dptree::entry().map(|_: A| B).inspect(|_: C| ()).endpoint(|| async { D });

Expand Down
2 changes: 1 addition & 1 deletion examples/simple_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::{

use dptree::prelude::*;

#[tokio::main]
#[tokio::main(flavor = "current_thread")]
async fn main() {
let store = Arc::new(AtomicI32::new(0));

Expand Down
2 changes: 1 addition & 1 deletion examples/state_machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{

use dptree::prelude::*;

#[tokio::main]
#[tokio::main(flavor = "current_thread")]
async fn main() {
let state = CommandState::Inactive;

Expand Down
20 changes: 13 additions & 7 deletions examples/storage.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use dptree::prelude::*;
use std::net::Ipv4Addr;
#[cfg(target_arch = "wasm32")]
fn main() {
// This example uses tokio::spawn/multithreading, which isn't
// supported on wasm32-unknown-unknown.
}

#[cfg(not(target_arch = "wasm32"))]
fn assert_num_string_handler(
expected_num: u32,
expected_string: &'static str,
) -> Endpoint<'static, ()> {
) -> dptree::Endpoint<'static, ()> {
// The handler requires `u32` and `String` types from the input storage.
dptree::endpoint(move |num: u32, string: String| async move {
assert_eq!(num, expected_num);
assert_eq!(string, expected_string);
})
}

#[tokio::main]
#[cfg(not(target_arch = "wasm32"))]
#[tokio::main(flavor = "current_thread")]
async fn main() {
// Init the storage with `u32` and `String` values.
let store = dptree::deps![10u32, "Hello".to_owned()];
Expand All @@ -23,9 +28,10 @@ async fn main() {

// This will cause a panic because we do not store `Ipv4Addr` in out store.
let handle = tokio::spawn(async move {
let ip_handler: Endpoint<_> = dptree::endpoint(|ip: Ipv4Addr| async move {
assert_eq!(ip, Ipv4Addr::new(0, 0, 0, 0));
});
let ip_handler: dptree::Endpoint<_> =
dptree::endpoint(|ip: std::net::Ipv4Addr| async move {
assert_eq!(ip, std::net::Ipv4Addr::new(0, 0, 0, 0));
});
let _ = ip_handler.dispatch(store).await;
});
let result = handle.await;
Expand Down
2 changes: 1 addition & 1 deletion examples/web_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use dptree::prelude::*;
type WebHandler = Endpoint<'static, String>;

#[rustfmt::skip]
#[tokio::main]
#[tokio::main(flavor = "current_thread")]
async fn main() {
let web_server = dptree::entry()
.branch(smiles_handler())
Expand Down
72 changes: 38 additions & 34 deletions src/di.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
//! [dependency injection]: https://en.wikipedia.org/wiki/Dependency_injection
//! [this discussion on StackOverflow]: https://stackoverflow.com/questions/130794/what-is-dependency-injection

use futures::future::{ready, BoxFuture};
use futures::future::ready;

use crate::send::{BoxFuture, MaybeSend, MaybeSync};

use std::{
any::{Any, TypeId},
Expand Down Expand Up @@ -93,7 +95,7 @@ impl PartialEq for DependencyMap {
fn eq(&self, other: &Self) -> bool {
let keys1 = self.map.keys();
let keys2 = other.map.keys();
keys1.len() == keys2.len() && keys1.zip(keys2).map(|(k1, k2)| k1 == k2).all(|x| x)
keys1.len() == keys2.len() && keys1.zip(keys2).all(|(k1, k2)| k1 == k2)
}
}

Expand Down Expand Up @@ -201,7 +203,10 @@ where
}

/// A function with all dependencies satisfied.
#[cfg(not(target_arch = "wasm32"))]
pub type CompiledFn<'a, Output> = Arc<dyn Fn() -> BoxFuture<'a, Output> + Send + Sync + 'a>;
#[cfg(target_arch = "wasm32")]
pub type CompiledFn<'a, Output> = Arc<dyn Fn() -> BoxFuture<'a, Output> + 'a>;

/// Turns a synchronous function into a type that implements [`Injectable`].
pub struct Asyncify<F>(pub F);
Expand All @@ -210,8 +215,8 @@ macro_rules! impl_into_di {
($($generic:ident),*) => {
impl<Func, Output, Fut, $($generic),*> Injectable<Output, ($($generic,)*)> for Func
where
Func: Fn($($generic),*) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Output> + Send + 'static,
Func: Fn($($generic),*) -> Fut + MaybeSend + MaybeSync + 'static,
Fut: Future<Output = Output> + MaybeSend + 'static,
Output: 'static,
$($generic: Clone + Send + Sync + 'static),*
{
Expand All @@ -234,8 +239,8 @@ macro_rules! impl_into_di {

impl<Func, Output, $($generic),*> Injectable<Output, ($($generic,)*)> for Asyncify<Func>
where
Func: Fn($($generic),*) -> Output + Send + Sync + 'static,
Output: Send + 'static,
Func: Fn($($generic),*) -> Output + MaybeSend + MaybeSync + 'static,
Output: MaybeSend + 'static,
$($generic: Clone + Send + Sync + 'static),*
{
#[allow(non_snake_case)]
Expand Down Expand Up @@ -306,38 +311,37 @@ macro_rules! deps {
mod tests {
use super::*;

#[test]
fn get() {
let mut map = DependencyMap::new();
map.insert(42i32);
map.insert("hello world");
map.insert_container(deps![true]);
crate::cross_test! {
fn get() {
let mut map = DependencyMap::new();
map.insert(42i32);
map.insert("hello world");
map.insert_container(deps![true]);

assert_eq!(map.get(), Arc::new(42i32));
assert_eq!(map.get(), Arc::new("hello world"));
assert_eq!(map.get(), Arc::new(true));
}
assert_eq!(map.get(), Arc::new(42i32));
assert_eq!(map.get(), Arc::new("hello world"));
assert_eq!(map.get(), Arc::new(true));
}

#[test]
fn try_get() {
let mut map = DependencyMap::new();
assert_eq!(map.try_get::<i32>(), None);
map.insert(42i32);
assert_eq!(map.try_get(), Some(Arc::new(42i32)));
assert_eq!(map.try_get::<f32>(), None);
}
fn try_get() {
let mut map = DependencyMap::new();
assert_eq!(map.try_get::<i32>(), None);
map.insert(42i32);
assert_eq!(map.try_get(), Some(Arc::new(42i32)));
assert_eq!(map.try_get::<f32>(), None);
}

#[test]
fn same_keys() {
let mut map_bool1 = DependencyMap::new();
let mut map_bool2 = DependencyMap::new();
let map_empty = DependencyMap::new();
fn same_keys() {
let mut map_bool1 = DependencyMap::new();
let mut map_bool2 = DependencyMap::new();
let map_empty = DependencyMap::new();

map_bool1.insert(false);
map_bool2.insert(true);
map_bool1.insert(false);
map_bool2.insert(true);

assert_eq!(map_bool1, map_bool2);
assert_ne!(map_bool1, map_empty);
assert_ne!(map_bool2, map_empty);
assert_eq!(map_bool1, map_bool2);
assert_ne!(map_bool1, map_empty);
assert_ne!(map_bool2, map_empty);
}
}
}
Loading
Loading