use dioxus_lib::prelude::*;
use serde::{de::DeserializeOwned, Serialize};
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>(
mut future: impl FnMut() -> F + 'static,
) -> Result<Resource<T>, RenderError>
where
T: Serialize + DeserializeOwned + 'static,
F: Future<Output = T> + 'static,
{
#[cfg(feature = "server")]
let serialize_context = crate::html_storage::use_serialize_context();
#[cfg(feature = "server")]
let server_storage_entry = 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(
dioxus_web::take_server_data::<T>(),
)))
});
let resource = use_resource(move || {
#[cfg(feature = "server")]
let serialize_context = serialize_context.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(Some(o))) => return o,
Some(Ok(None)) => std::future::pending::<()>().await,
Some(Err(_)) => {}
None => {}
}
let out = user_fut.await;
#[cfg(feature = "server")]
serialize_context.insert(server_storage_entry, &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)
}