future_form 0.3.1

Abstractions over Send and !Send futures
Documentation
#![allow(missing_docs, clippy::missing_const_for_fn, clippy::future_not_send)]

use core::marker::PhantomData;
use future_form::{FromFuture, FutureForm, Local, Sendable, future_form};
use futures::future::{BoxFuture, LocalBoxFuture};
use std::collections::HashMap;

// Shared types used by multiple test modules

trait Counter<K: FutureForm> {
    fn next(&self) -> K::Future<'_, u32>;
}

struct Memory<K> {
    val: u32,
    _marker: PhantomData<K>,
}

impl<K> Memory<K> {
    fn new(val: u32) -> Self {
        Self {
            val,
            _marker: PhantomData,
        }
    }
}

#[future_form(Sendable, Local)]
impl<K: FutureForm> Counter<K> for Memory<K> {
    fn next(&self) -> K::Future<'_, u32> {
        let val = self.val;
        K::from_future(async move { val + 1 })
    }
}

#[tokio::test]
async fn test_macro_impl_with_sendable() {
    let memory: Memory<Sendable> = Memory::new(41);
    let result = <Memory<Sendable> as Counter<Sendable>>::next(&memory).await;
    assert_eq!(result, 42);
}

#[tokio::test]
async fn test_macro_impl_with_local() {
    let memory: Memory<Local> = Memory::new(41);
    let result = <Memory<Local> as Counter<Local>>::next(&memory).await;
    assert_eq!(result, 42);
}

trait Database<K: FutureForm> {
    fn get(&self, key: &str) -> K::Future<'_, Option<String>>;
    fn count(&self) -> K::Future<'_, usize>;
}

struct InMemoryDb<K> {
    data: std::collections::HashMap<String, String>,
    _marker: PhantomData<K>,
}

#[future_form(Sendable, Local)]
impl<K: FutureForm> Database<K> for InMemoryDb<K> {
    fn get(&self, key: &str) -> K::Future<'_, Option<String>> {
        let key = key.to_string();
        K::from_future(async move { self.data.get(&key).cloned() })
    }

    fn count(&self) -> K::Future<'_, usize> {
        K::from_future(async move { self.data.len() })
    }
}

#[tokio::test]
async fn test_database_sendable() {
    let mut data = std::collections::HashMap::new();
    data.insert("foo".to_string(), "bar".to_string());
    let db: InMemoryDb<Sendable> = InMemoryDb {
        data,
        _marker: PhantomData,
    };

    assert_eq!(
        <InMemoryDb<Sendable> as Database<Sendable>>::get(&db, "foo").await,
        Some("bar".to_string())
    );
    assert_eq!(
        <InMemoryDb<Sendable> as Database<Sendable>>::get(&db, "missing").await,
        None
    );
    assert_eq!(
        <InMemoryDb<Sendable> as Database<Sendable>>::count(&db).await,
        1
    );
}

#[tokio::test]
async fn test_database_local() {
    let mut data = std::collections::HashMap::new();
    data.insert("foo".to_string(), "bar".to_string());
    let db: InMemoryDb<Local> = InMemoryDb {
        data,
        _marker: PhantomData,
    };

    assert_eq!(
        <InMemoryDb<Local> as Database<Local>>::get(&db, "foo").await,
        Some("bar".to_string())
    );
    assert_eq!(
        <InMemoryDb<Local> as Database<Local>>::get(&db, "missing").await,
        None
    );
    assert_eq!(<InMemoryDb<Local> as Database<Local>>::count(&db).await, 1);
}

// Test modules — one file per module under macro_tests/
#[path = "macro_tests/alternative_param_names.rs"]
mod alternative_param_names;
#[path = "macro_tests/angle_brackets_in_attr_where.rs"]
mod angle_brackets_in_attr_where;
#[path = "macro_tests/complex_bounds.rs"]
mod complex_bounds;
#[path = "macro_tests/complex_return_types.rs"]
mod complex_return_types;
#[path = "macro_tests/concrete_self_type.rs"]
mod concrete_self_type;
#[path = "macro_tests/conditional_bounds.rs"]
mod conditional_bounds;
#[path = "macro_tests/from_future_trait.rs"]
mod from_future_trait;
#[path = "macro_tests/future_form_with_question_sized.rs"]
mod future_form_with_question_sized;
#[path = "macro_tests/generic_consumers.rs"]
mod generic_consumers;
#[path = "macro_tests/identifier_collision.rs"]
mod identifier_collision;
#[path = "macro_tests/inline_k_bounds.rs"]
mod inline_k_bounds;
#[path = "macro_tests/k_in_associated_types.rs"]
mod k_in_associated_types;
#[path = "macro_tests/k_in_method_params.rs"]
mod k_in_method_params;
#[path = "macro_tests/k_referencing_where_clauses.rs"]
mod k_referencing_where_clauses;
#[path = "macro_tests/lifetime_params.rs"]
mod lifetime_params;
#[path = "macro_tests/method_attributes.rs"]
mod method_attributes;
#[path = "macro_tests/method_generics.rs"]
mod method_generics;
#[path = "macro_tests/multiple_generics.rs"]
mod multiple_generics;
#[path = "macro_tests/selective_generation.rs"]
mod selective_generation;
#[path = "macro_tests/where_clause_future_form_bound.rs"]
mod where_clause_future_form_bound;
#[path = "macro_tests/where_clauses.rs"]
mod where_clauses;