use crate::Transportable;
use dioxus_core::{suspend, use_hook, RenderError};
use dioxus_hooks::*;
use dioxus_signals::ReadableExt;
use std::future::Future;
#[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
#[track_caller]
pub fn use_server_future<T, F, M>(
mut future: impl FnMut() -> F + 'static,
) -> Result<Resource<T>, RenderError>
where
F: Future<Output = T> + 'static,
T: Transportable<M>,
M: 'static,
{
let serialize_context = use_hook(crate::transport::serialize_context);
#[allow(unused)]
let storage_entry: crate::transport::SerializeContextEntry<T> =
use_hook(|| serialize_context.create_entry());
#[cfg(feature = "server")]
let caller = std::panic::Location::caller();
#[cfg(feature = "web")]
let initial_web_result =
use_hook(|| std::rc::Rc::new(std::cell::RefCell::new(Some(storage_entry.get()))));
let resource = use_resource(move || {
#[cfg(feature = "server")]
let storage_entry = storage_entry.clone();
let user_fut = future();
#[cfg(feature = "web")]
let initial_web_result = initial_web_result.clone();
#[allow(clippy::let_and_return)]
async move {
#[cfg(feature = "web")]
match initial_web_result.take() {
Some(Ok(o)) => return o,
Some(Err(crate::transport::TakeDataError::DataPending)) => {
std::future::pending::<()>().await
}
Some(Err(_)) => {}
None => {}
}
let out = user_fut.await;
#[cfg(feature = "server")]
storage_entry.insert(&out, caller);
out
}
});
use_hook(|| {
let _ = resource.task().poll_now();
});
if resource.state().cloned() == UseResourceState::Pending {
let task = resource.task();
if !task.paused() {
return Err(suspend(task).unwrap_err());
}
}
Ok(resource)
}