use dbuff::*;
use std::time::Duration;
#[derive(Debug, Clone, Default)]
struct AppData {
user_id: i32,
post_count: usize,
log: Vec<String>,
}
#[derive(Debug, Clone, wherror::Error)]
#[error(debug)]
struct CmdError;
struct FetchUser(i32);
#[async_trait::async_trait]
impl Command<()> for FetchUser {
type Output = i32;
type Error = CmdError;
async fn execute(self, _: ()) -> Result<Self::Output, Self::Error> {
Ok(self.0)
}
}
struct FetchPosts(i32);
#[async_trait::async_trait]
impl Command<()> for FetchPosts {
type Output = usize;
type Error = CmdError;
async fn execute(self, _: ()) -> Result<Self::Output, Self::Error> {
#[allow(clippy::cast_sign_loss)]
Ok(self.0 as usize * 10)
}
}
struct Log(String);
#[async_trait::async_trait]
impl Command<()> for Log {
type Output = String;
type Error = CmdError;
async fn execute(self, _: ()) -> Result<Self::Output, Self::Error> {
Ok(self.0)
}
}
#[tokio::main]
async fn main() {
let rt = tokio::runtime::Handle::current();
let (domain, write_handle) =
SharedDomainData::with_coalesce(AppData::default(), Duration::from_millis(1));
tokio::spawn(write_handle.run());
let handle = domain
.bind((), rt.clone())
.exec(FetchUser(42), |d, id: &i32| d.user_id = *id)
.then(
|user_id: &i32| FetchPosts(*user_id),
|d, count: &usize| d.post_count = *count,
)
.exec(Log("posts loaded".into()), |d, msg: &String| {
d.log.push(msg.clone());
})
.go();
let flow = handle.await.unwrap();
assert_eq!(flow, ControlFlow::Continue);
tokio::time::sleep(Duration::from_millis(10)).await;
let guard = domain.read();
assert_eq!(guard.user_id, 42);
assert_eq!(guard.post_count, 420);
assert_eq!(guard.log, vec!["posts loaded"]);
println!(
"user_id = {}, post_count = {}, log = {:?}",
guard.user_id, guard.post_count, guard.log
);
}