future_form 0.3.1

Abstractions over Send and !Send futures
Documentation
use super::*;

trait Processor<K: FutureForm> {
    fn process(&self) -> K::Future<'_, String>;
}

struct Container<T> {
    value: T,
}

#[future_form(Sendable where T: Send, Local)]
impl<K: FutureForm, T: Clone + ToString> Processor<K> for Container<T> {
    fn process(&self) -> K::Future<'_, String> {
        let value = self.value.clone();
        K::from_future(async move { value.to_string() })
    }
}

#[tokio::test]
async fn test_conditional_bounds_sendable() {
    let container = Container {
        value: "hello".to_string(),
    };
    let result = <Container<String> as Processor<Sendable>>::process(&container).await;
    assert_eq!(result, "hello");
}

#[tokio::test]
async fn test_conditional_bounds_local() {
    use std::rc::Rc;
    let container = Container {
        value: Rc::<str>::from("world"),
    };
    let result = <Container<Rc<str>> as Processor<Local>>::process(&container).await;
    assert_eq!(result, "world");
}

trait Debugger<K: FutureForm> {
    fn debug(&self) -> K::Future<'_, String>;
}

struct Wrapper<T>(T);

#[future_form(Sendable where T: Send, Local where T: core::fmt::Debug)]
impl<K: FutureForm, T: Clone> Debugger<K> for Wrapper<T> {
    fn debug(&self) -> K::Future<'_, String> {
        K::from_future(async move { "debugged".to_string() })
    }
}

#[tokio::test]
async fn test_local_conditional_bounds() {
    let wrapper = Wrapper(42i32);
    let result = <Wrapper<i32> as Debugger<Local>>::debug(&wrapper).await;
    assert_eq!(result, "debugged");
}

#[tokio::test]
async fn test_sendable_conditional_bounds_separate() {
    let wrapper = Wrapper(42i32);
    let result = <Wrapper<i32> as Debugger<Sendable>>::debug(&wrapper).await;
    assert_eq!(result, "debugged");
}

// Multi-letter type params should not be mistaken for variant names
trait MultiLetterParams<K: FutureForm> {
    fn process(&self) -> K::Future<'_, String>;
}

struct MultiLetterContainer<Conn, Sig> {
    conn: Conn,
    sig: Sig,
}

#[future_form(
    Sendable where
        Conn: Clone + Send,
        Sig: Clone + Send,
    Local where
        Conn: Clone,
        Sig: Clone
)]
impl<K: FutureForm, Conn: ToString, Sig: ToString> MultiLetterParams<K>
    for MultiLetterContainer<Conn, Sig>
{
    fn process(&self) -> K::Future<'_, String> {
        let conn = self.conn.to_string();
        let sig = self.sig.to_string();
        K::from_future(async move { format!("{conn}:{sig}") })
    }
}

#[tokio::test]
async fn test_multi_letter_type_params_sendable() {
    let container = MultiLetterContainer {
        conn: "localhost",
        sig: "abc123",
    };
    let result =
        <MultiLetterContainer<&str, &str> as MultiLetterParams<Sendable>>::process(&container)
            .await;
    assert_eq!(result, "localhost:abc123");
}

#[tokio::test]
async fn test_multi_letter_type_params_local() {
    use std::rc::Rc;
    let container = MultiLetterContainer {
        conn: Rc::from("localhost"),
        sig: Rc::from("abc123"),
    };
    let result =
        <MultiLetterContainer<Rc<str>, Rc<str>> as MultiLetterParams<Local>>::process(&container)
            .await;
    assert_eq!(result, "localhost:abc123");
}