mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 09:54:41 -05:00
chore: add missing docs for 0.7 (#3203)
This commit is contained in:
@@ -6,6 +6,10 @@ use reactive_graph::{
|
||||
use server_fn::{error::ServerFnErrorSerde, ServerFn, ServerFnError};
|
||||
use std::{ops::Deref, panic::Location, sync::Arc};
|
||||
|
||||
/// An error that can be caused by a server action.
|
||||
///
|
||||
/// This is used for propagating errors from the server to the client when JS/WASM are not
|
||||
/// supported.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ServerActionError {
|
||||
path: Arc<str>,
|
||||
@@ -13,6 +17,7 @@ pub struct ServerActionError {
|
||||
}
|
||||
|
||||
impl ServerActionError {
|
||||
/// Creates a new error associated with the given path.
|
||||
pub fn new(path: &str, err: &str) -> Self {
|
||||
Self {
|
||||
path: path.into(),
|
||||
@@ -20,15 +25,18 @@ impl ServerActionError {
|
||||
}
|
||||
}
|
||||
|
||||
/// The path with which this error is associated.
|
||||
pub fn path(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// The error message.
|
||||
pub fn err(&self) -> &str {
|
||||
&self.err
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`ArcAction`] that can be used to call a server function.
|
||||
pub struct ArcServerAction<S>
|
||||
where
|
||||
S: ServerFn + 'static,
|
||||
@@ -45,6 +53,7 @@ where
|
||||
S::Output: Send + Sync + 'static,
|
||||
S::Error: Send + Sync + 'static,
|
||||
{
|
||||
/// Creates a new [`ArcAction`] that will call the server function `S` when dispatched.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
let err = use_context::<ServerActionError>().and_then(|error| {
|
||||
@@ -116,6 +125,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`Action`] that can be used to call a server function.
|
||||
pub struct ServerAction<S>
|
||||
where
|
||||
S: ServerFn + 'static,
|
||||
@@ -132,6 +142,7 @@ where
|
||||
S::Output: Send + Sync + 'static,
|
||||
S::Error: Send + Sync + 'static,
|
||||
{
|
||||
/// Creates a new [`Action`] that will call the server function `S` when dispatched.
|
||||
pub fn new() -> Self {
|
||||
let err = use_context::<ServerActionError>().and_then(|error| {
|
||||
(error.path() == S::PATH)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//#![deny(missing_docs)]
|
||||
//! Utilities for communicating between the server and the client with [`leptos`].
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
mod action;
|
||||
@@ -13,135 +15,25 @@ pub use once_resource::*;
|
||||
mod resource;
|
||||
pub use resource::*;
|
||||
mod shared;
|
||||
////! # Leptos Server Functions
|
||||
////!
|
||||
////! This package is based on a simple idea: sometimes it’s useful to write functions
|
||||
////! that will only run on the server, and call them from the client.
|
||||
////!
|
||||
////! If you’re creating anything beyond a toy app, you’ll need to do this all the time:
|
||||
////! reading from or writing to a database that only runs on the server, running expensive
|
||||
////! computations using libraries you don’t want to ship down to the client, accessing
|
||||
////! APIs that need to be called from the server rather than the client for CORS reasons
|
||||
////! or because you need a secret API key that’s stored on the server and definitely
|
||||
////! shouldn’t be shipped down to a user’s browser.
|
||||
////!
|
||||
////! Traditionally, this is done by separating your server and client code, and by setting
|
||||
////! up something like a REST API or GraphQL API to allow your client to fetch and mutate
|
||||
////! data on the server. This is fine, but it requires you to write and maintain your code
|
||||
////! in multiple separate places (client-side code for fetching, server-side functions to run),
|
||||
////! as well as creating a third thing to manage, which is the API contract between the two.
|
||||
////!
|
||||
////! This package provides two simple primitives that allow you instead to write co-located,
|
||||
////! isomorphic server functions. (*Co-located* means you can write them in your app code so
|
||||
////! that they are “located alongside” the client code that calls them, rather than separating
|
||||
////! the client and server sides. *Isomorphic* means you can call them from the client as if
|
||||
////! you were simply calling a function; the function call has the “same shape” on the client
|
||||
////! as it does on the server.)
|
||||
////!
|
||||
////! ### `#[server]`
|
||||
////!
|
||||
////! The [`#[server]`](https://docs.rs/leptos/latest/leptos/attr.server.html) macro allows you to annotate a function to
|
||||
////! indicate that it should only run on the server (i.e., when you have an `ssr` feature in your
|
||||
////! crate that is enabled).
|
||||
////!
|
||||
////! ```rust,ignore
|
||||
////! use leptos::prelude::*;
|
||||
////! #[server(ReadFromDB)]
|
||||
////! async fn read_posts(how_many: usize, query: String) -> Result<Vec<Posts>, ServerFnError> {
|
||||
////! // do some server-only work here to access the database
|
||||
////! let posts = todo!();;
|
||||
////! Ok(posts)
|
||||
////! }
|
||||
////!
|
||||
////! // call the function
|
||||
////! spawn_local(async {
|
||||
////! let posts = read_posts(3, "my search".to_string()).await;
|
||||
////! log::debug!("posts = {posts:#?}");
|
||||
////! });
|
||||
////! ```
|
||||
////!
|
||||
////! If you call this function from the client, it will serialize the function arguments and `POST`
|
||||
////! them to the server as if they were the inputs in `<form method="POST">`.
|
||||
////!
|
||||
////! Here’s what you need to remember:
|
||||
////! - **Server functions must be `async`.** Even if the work being done inside the function body
|
||||
////! can run synchronously on the server, from the client’s perspective it involves an asynchronous
|
||||
////! function call.
|
||||
////! - **Server functions must return `Result<T, ServerFnError>`.** Even if the work being done
|
||||
////! inside the function body can’t fail, the processes of serialization/deserialization and the
|
||||
////! network call are fallible.
|
||||
////! - **Return types must be [Serializable](leptos_reactive::Serializable).**
|
||||
////! This should be fairly obvious: we have to serialize arguments to send them to the server, and we
|
||||
////! need to deserialize the result to return it to the client.
|
||||
////! - **Arguments must be implement [serde::Serialize].** They are serialized as an `application/x-www-form-urlencoded`
|
||||
////! form data using [`serde_qs`](https://docs.rs/serde_qs/latest/serde_qs/) or as `application/cbor`
|
||||
////! using [`cbor`](https://docs.rs/cbor/latest/cbor/). **Note**: You should explicitly include `serde` with the
|
||||
////! `derive` feature enabled in your `Cargo.toml`. You can do this by running `cargo add serde --features=derive`.
|
||||
////! - Context comes from the server. [`use_context`](leptos_reactive::use_context) can be used to access specific
|
||||
////! server-related data, as documented in the server integrations. This allows accessing things like HTTP request
|
||||
////! headers as needed. However, server functions *not* have access to reactive state that exists in the client.
|
||||
////!
|
||||
////! ## Server Function Encodings
|
||||
////!
|
||||
////! By default, the server function call is a `POST` request that serializes the arguments as URL-encoded form data in the body
|
||||
////! of the request. But there are a few other methods supported. Optionally, we can provide another argument to the `#[server]`
|
||||
////! macro to specify an alternate encoding:
|
||||
////!
|
||||
////! ```rust,ignore
|
||||
////! #[server(AddTodo, "/api", "Url")]
|
||||
////! #[server(AddTodo, "/api", "GetJson")]
|
||||
////! #[server(AddTodo, "/api", "Cbor")]
|
||||
////! #[server(AddTodo, "/api", "GetCbor")]
|
||||
////! ```
|
||||
////!
|
||||
////! The four options use different combinations of HTTP verbs and encoding methods:
|
||||
////!
|
||||
////! | Name | Method | Request | Response |
|
||||
////! | ----------------- | ------ | ----------- | -------- |
|
||||
////! | **Url** (default) | POST | URL encoded | JSON |
|
||||
////! | **GetJson** | GET | URL encoded | JSON |
|
||||
////! | **Cbor** | POST | CBOR | CBOR |
|
||||
////! | **GetCbor** | GET | URL encoded | CBOR |
|
||||
////!
|
||||
////! In other words, you have two choices:
|
||||
////!
|
||||
////! - `GET` or `POST`? This has implications for things like browser or CDN caching; while `POST` requests should not be cached,
|
||||
////! `GET` requests can be.
|
||||
////! - Plain text (arguments sent with URL/form encoding, results sent as JSON) or a binary format (CBOR, encoded as a base64
|
||||
////! string)?
|
||||
////!
|
||||
////! ## Why not `PUT` or `DELETE`? Why URL/form encoding, and not JSON?**
|
||||
////!
|
||||
////! These are reasonable questions. Much of the web is built on REST API patterns that encourage the use of semantic HTTP
|
||||
////! methods like `DELETE` to delete an item from a database, and many devs are accustomed to sending data to APIs in the
|
||||
////! JSON format.
|
||||
////!
|
||||
////! The reason we use `POST` or `GET` with URL-encoded data by default is the `<form>` support. For better or for worse,
|
||||
////! HTML forms don’t support `PUT` or `DELETE`, and they don’t support sending JSON. This means that if you use anything
|
||||
////! but a `GET` or `POST` request with URL-encoded data, it can only work once WASM has loaded.
|
||||
////!
|
||||
////! The CBOR encoding is supported for historical reasons; an earlier version of server functions used a URL encoding that
|
||||
////! didn’t support nested objects like structs or vectors as server function arguments, which CBOR did. But note that the
|
||||
////! CBOR forms encounter the same issue as `PUT`, `DELETE`, or JSON: they do not degrade gracefully if the WASM version of
|
||||
////! your app is not available.
|
||||
|
||||
//pub use server_fn::{error::ServerFnErrorErr, ServerFnError};
|
||||
|
||||
//mod action;
|
||||
//mod multi_action;
|
||||
//pub use action::*;
|
||||
//pub use multi_action::*;
|
||||
//extern crate tracing;
|
||||
use base64::{engine::general_purpose::STANDARD_NO_PAD, DecodeError, Engine};
|
||||
pub use shared::*;
|
||||
|
||||
/// Encodes data into a string.
|
||||
pub trait IntoEncodedString {
|
||||
/// Encodes the data.
|
||||
fn into_encoded_string(self) -> String;
|
||||
}
|
||||
|
||||
/// Decodes data from a string.
|
||||
pub trait FromEncodedStr {
|
||||
/// The decoded data.
|
||||
type DecodedType<'a>: Borrow<Self>;
|
||||
|
||||
/// The type of an error encountered during decoding.
|
||||
type DecodingError;
|
||||
|
||||
/// Decodes the string.
|
||||
fn from_encoded_str(
|
||||
data: &str,
|
||||
) -> Result<Self::DecodedType<'_>, Self::DecodingError>;
|
||||
|
||||
@@ -17,6 +17,7 @@ use std::{
|
||||
panic::Location,
|
||||
};
|
||||
|
||||
/// A reference-counted resource that only loads its data locally on the client.
|
||||
pub struct ArcLocalResource<T> {
|
||||
data: ArcAsyncDerived<SendWrapper<T>>,
|
||||
#[cfg(debug_assertions)]
|
||||
@@ -34,6 +35,10 @@ impl<T> Clone for ArcLocalResource<T> {
|
||||
}
|
||||
|
||||
impl<T> ArcLocalResource<T> {
|
||||
/// Creates the resource.
|
||||
///
|
||||
/// This will only begin loading data if you are on the client (i.e., if you do not have the
|
||||
/// `ssr` feature activated).
|
||||
#[track_caller]
|
||||
pub fn new<Fut>(fetcher: impl Fn() -> Fut + 'static) -> Self
|
||||
where
|
||||
@@ -192,6 +197,7 @@ impl<T> Subscriber for ArcLocalResource<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A resource that only loads its data locally on the client.
|
||||
pub struct LocalResource<T> {
|
||||
data: AsyncDerived<SendWrapper<T>>,
|
||||
#[cfg(debug_assertions)]
|
||||
@@ -207,6 +213,10 @@ impl<T> Clone for LocalResource<T> {
|
||||
impl<T> Copy for LocalResource<T> {}
|
||||
|
||||
impl<T> LocalResource<T> {
|
||||
/// Creates the resource.
|
||||
///
|
||||
/// This will only begin loading data if you are on the client (i.e., if you do not have the
|
||||
/// `ssr` feature activated).
|
||||
#[track_caller]
|
||||
pub fn new<Fut>(fetcher: impl Fn() -> Fut + 'static) -> Self
|
||||
where
|
||||
|
||||
@@ -5,6 +5,7 @@ use reactive_graph::{
|
||||
use server_fn::{ServerFn, ServerFnError};
|
||||
use std::{ops::Deref, panic::Location};
|
||||
|
||||
/// An [`ArcMultiAction`] that can be used to call a server function.
|
||||
pub struct ArcServerMultiAction<S>
|
||||
where
|
||||
S: ServerFn + 'static,
|
||||
@@ -21,6 +22,7 @@ where
|
||||
S::Output: Send + Sync + 'static,
|
||||
S::Error: Send + Sync + 'static,
|
||||
{
|
||||
/// Creates a new [`ArcMultiAction`] which, when dispatched, will call the server function `S`.
|
||||
#[track_caller]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@@ -87,6 +89,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`MultiAction`] that can be used to call a server function.
|
||||
pub struct ServerMultiAction<S>
|
||||
where
|
||||
S: ServerFn + 'static,
|
||||
@@ -114,6 +117,7 @@ where
|
||||
S::Output: Send + Sync + 'static,
|
||||
S::Error: Send + Sync + 'static,
|
||||
{
|
||||
/// Creates a new [`MultiAction`] which, when dispatched, will call the server function `S`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: MultiAction::new(|input: &S| {
|
||||
|
||||
@@ -1,344 +0,0 @@
|
||||
use leptos_reactive::{
|
||||
is_suppressing_resource_load, signal_prelude::*, spawn_local, store_value,
|
||||
untrack, StoredValue,
|
||||
};
|
||||
use server_fn::{ServerFn, ServerFnError};
|
||||
use std::{future::Future, pin::Pin, rc::Rc};
|
||||
|
||||
/// An action that synchronizes multiple imperative `async` calls to the reactive system,
|
||||
/// tracking the progress of each one.
|
||||
///
|
||||
/// Where an [Action](crate::Action) fires a single call, a `MultiAction` allows you to
|
||||
/// keep track of multiple in-flight actions.
|
||||
///
|
||||
/// If you’re trying to load data by running an `async` function reactively, you probably
|
||||
/// want to use a [Resource](leptos_reactive::Resource) instead. If you’re trying to occasionally
|
||||
/// run an `async` function in response to something like a user adding a task to a todo list,
|
||||
/// you’re in the right place.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// async fn send_new_todo_to_api(task: String) -> usize {
|
||||
/// // do something...
|
||||
/// // return a task id
|
||||
/// 42
|
||||
/// }
|
||||
/// let add_todo = create_multi_action(|task: &String| {
|
||||
/// // `task` is given as `&String` because its value is available in `input`
|
||||
/// send_new_todo_to_api(task.clone())
|
||||
/// });
|
||||
///
|
||||
/// # if false {
|
||||
/// add_todo.dispatch("Buy milk".to_string());
|
||||
/// add_todo.dispatch("???".to_string());
|
||||
/// add_todo.dispatch("Profit!!!".to_string());
|
||||
/// # }
|
||||
///
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
///
|
||||
/// The input to the `async` function should always be a single value,
|
||||
/// but it can be of any type. The argument is always passed by reference to the
|
||||
/// function, because it is stored in [Submission::input] as well.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// // if there's a single argument, just use that
|
||||
/// let action1 = create_multi_action(|input: &String| {
|
||||
/// let input = input.clone();
|
||||
/// async move { todo!() }
|
||||
/// });
|
||||
///
|
||||
/// // if there are no arguments, use the unit type `()`
|
||||
/// let action2 = create_multi_action(|input: &()| async { todo!() });
|
||||
///
|
||||
/// // if there are multiple arguments, use a tuple
|
||||
/// let action3 =
|
||||
/// create_multi_action(|input: &(usize, String)| async { todo!() });
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
pub struct MultiAction<I, O>(StoredValue<MultiActionState<I, O>>)
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static;
|
||||
|
||||
impl<I, O> MultiAction<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
}
|
||||
|
||||
impl<I, O> Clone for MultiAction<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O> Copy for MultiAction<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
}
|
||||
|
||||
impl<I, O> MultiAction<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
/// Calls the `async` function with a reference to the input type as its argument.
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", skip_all)
|
||||
)]
|
||||
pub fn dispatch(&self, input: I) {
|
||||
self.0.with_value(|a| a.dispatch(input))
|
||||
}
|
||||
|
||||
/// The set of all submissions to this multi-action.
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", skip_all)
|
||||
)]
|
||||
pub fn submissions(&self) -> ReadSignal<Vec<Submission<I, O>>> {
|
||||
self.0.with_value(|a| a.submissions())
|
||||
}
|
||||
|
||||
/// The URL associated with the action (typically as part of a server function.)
|
||||
/// This enables integration with the `MultiActionForm` component in `leptos_router`.
|
||||
pub fn url(&self) -> Option<String> {
|
||||
self.0.with_value(|a| a.url.as_ref().cloned())
|
||||
}
|
||||
|
||||
/// How many times an action has successfully resolved.
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", skip_all)
|
||||
)]
|
||||
pub fn version(&self) -> RwSignal<usize> {
|
||||
self.0.with_value(|a| a.version)
|
||||
}
|
||||
|
||||
/// Associates the URL of the given server function with this action.
|
||||
/// This enables integration with the `MultiActionForm` component in `leptos_router`.
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", skip_all)
|
||||
)]
|
||||
pub fn using_server_fn<T: ServerFn>(self) -> Self {
|
||||
self.0.update_value(|a| {
|
||||
a.url = Some(T::url().to_string());
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct MultiActionState<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
/// How many times an action has successfully resolved.
|
||||
pub version: RwSignal<usize>,
|
||||
submissions: RwSignal<Vec<Submission<I, O>>>,
|
||||
url: Option<String>,
|
||||
#[allow(clippy::complexity)]
|
||||
action_fn: Rc<dyn Fn(&I) -> Pin<Box<dyn Future<Output = O>>>>,
|
||||
}
|
||||
|
||||
/// An action that has been submitted by dispatching it to a [MultiAction](crate::MultiAction).
|
||||
pub struct Submission<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
/// The current argument that was dispatched to the `async` function.
|
||||
/// `Some` while we are waiting for it to resolve, `None` if it has resolved.
|
||||
pub input: RwSignal<Option<I>>,
|
||||
/// The most recent return value of the `async` function.
|
||||
pub value: RwSignal<Option<O>>,
|
||||
pub(crate) pending: RwSignal<bool>,
|
||||
/// Controls this submission has been canceled.
|
||||
pub canceled: RwSignal<bool>,
|
||||
}
|
||||
|
||||
impl<I, O> Clone for Submission<I, O> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O> Copy for Submission<I, O> {}
|
||||
|
||||
impl<I, O> Submission<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
/// Whether this submission is currently waiting to resolve.
|
||||
pub fn pending(&self) -> ReadSignal<bool> {
|
||||
self.pending.read_only()
|
||||
}
|
||||
|
||||
/// Cancels the submission, preventing it from resolving.
|
||||
pub fn cancel(&self) {
|
||||
self.canceled.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O> MultiActionState<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
{
|
||||
/// Calls the `async` function with a reference to the input type as its argument.
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", skip_all)
|
||||
)]
|
||||
pub fn dispatch(&self, input: I) {
|
||||
if !is_suppressing_resource_load() {
|
||||
let fut = (self.action_fn)(&input);
|
||||
|
||||
let submission = Submission {
|
||||
input: create_rw_signal(Some(input)),
|
||||
value: create_rw_signal(None),
|
||||
pending: create_rw_signal(true),
|
||||
canceled: create_rw_signal(false),
|
||||
};
|
||||
|
||||
self.submissions.update(|subs| subs.push(submission));
|
||||
|
||||
let canceled = submission.canceled;
|
||||
let input = submission.input;
|
||||
let pending = submission.pending;
|
||||
let value = submission.value;
|
||||
let version = self.version;
|
||||
|
||||
spawn_local(async move {
|
||||
let new_value = fut.await;
|
||||
let canceled = untrack(move || canceled.get());
|
||||
if !canceled {
|
||||
value.set(Some(new_value));
|
||||
}
|
||||
input.set(None);
|
||||
pending.set(false);
|
||||
version.update(|n| *n += 1);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The set of all submissions to this multi-action.
|
||||
pub fn submissions(&self) -> ReadSignal<Vec<Submission<I, O>>> {
|
||||
self.submissions.read_only()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an [MultiAction] to synchronize an imperative `async` call to the synchronous reactive system.
|
||||
///
|
||||
/// If you’re trying to load data by running an `async` function reactively, you probably
|
||||
/// want to use a [create_resource](leptos_reactive::create_resource) instead. If you’re trying
|
||||
/// to occasionally run an `async` function in response to something like a user clicking a button,
|
||||
/// you're in the right place.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// async fn send_new_todo_to_api(task: String) -> usize {
|
||||
/// // do something...
|
||||
/// // return a task id
|
||||
/// 42
|
||||
/// }
|
||||
/// let add_todo = create_multi_action(|task: &String| {
|
||||
/// // `task` is given as `&String` because its value is available in `input`
|
||||
/// send_new_todo_to_api(task.clone())
|
||||
/// });
|
||||
/// # if false {
|
||||
///
|
||||
/// add_todo.dispatch("Buy milk".to_string());
|
||||
/// add_todo.dispatch("???".to_string());
|
||||
/// add_todo.dispatch("Profit!!!".to_string());
|
||||
///
|
||||
/// assert_eq!(add_todo.submissions().get().len(), 3);
|
||||
/// # }
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
///
|
||||
/// The input to the `async` function should always be a single value,
|
||||
/// but it can be of any type. The argument is always passed by reference to the
|
||||
/// function, because it is stored in [Submission::input] as well.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// // if there's a single argument, just use that
|
||||
/// let action1 = create_multi_action(|input: &String| {
|
||||
/// let input = input.clone();
|
||||
/// async move { todo!() }
|
||||
/// });
|
||||
///
|
||||
/// // if there are no arguments, use the unit type `()`
|
||||
/// let action2 = create_multi_action(|input: &()| async { todo!() });
|
||||
///
|
||||
/// // if there are multiple arguments, use a tuple
|
||||
/// let action3 =
|
||||
/// create_multi_action(|input: &(usize, String)| async { todo!() });
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
|
||||
pub fn create_multi_action<I, O, F, Fu>(action_fn: F) -> MultiAction<I, O>
|
||||
where
|
||||
I: 'static,
|
||||
O: 'static,
|
||||
F: Fn(&I) -> Fu + 'static,
|
||||
Fu: Future<Output = O> + 'static,
|
||||
{
|
||||
let version = create_rw_signal(0);
|
||||
let submissions = create_rw_signal(Vec::new());
|
||||
let action_fn = Rc::new(move |input: &I| {
|
||||
let fut = action_fn(input);
|
||||
Box::pin(fut) as Pin<Box<dyn Future<Output = O>>>
|
||||
});
|
||||
|
||||
MultiAction(store_value(MultiActionState {
|
||||
version,
|
||||
submissions,
|
||||
url: None,
|
||||
action_fn,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Creates an [MultiAction] that can be used to call a server function.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # use leptos::*;
|
||||
///
|
||||
/// #[server(MyServerFn)]
|
||||
/// async fn my_server_fn() -> Result<(), ServerFnError> {
|
||||
/// todo!()
|
||||
/// }
|
||||
///
|
||||
/// # let runtime = create_runtime();
|
||||
/// let my_server_multi_action = create_server_multi_action::<MyServerFn>();
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
|
||||
pub fn create_server_multi_action<S>(
|
||||
) -> MultiAction<S, Result<S::Output, ServerFnError<S::Error>>>
|
||||
where
|
||||
S: Clone + ServerFn,
|
||||
{
|
||||
#[cfg(feature = "ssr")]
|
||||
let c = move |args: &S| S::run_body(args.clone());
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
let c = move |args: &S| S::run_on_client(args.clone());
|
||||
create_multi_action(c).using_server_fn::<S>()
|
||||
}
|
||||
@@ -43,6 +43,15 @@ use std::{
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
|
||||
/// A reference-counted resource that only loads once.
|
||||
///
|
||||
/// Resources allow asynchronously loading data and serializing it from the server to the client,
|
||||
/// so that it loads on the server, and is then deserialized on the client. This improves
|
||||
/// performance by beginning data loading on the server when the request is made, rather than
|
||||
/// beginning it on the client after WASM has been loaded.
|
||||
///
|
||||
/// You can access the value of the resource either synchronously using `.get()` or asynchronously
|
||||
/// using `.await`.
|
||||
#[derive(Debug)]
|
||||
pub struct ArcOnceResource<T, Ser = JsonSerdeCodec> {
|
||||
trigger: ArcTrigger,
|
||||
@@ -80,6 +89,12 @@ where
|
||||
<Ser as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<Ser as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding `Ser`. If `blocking` is `true`, this is a blocking
|
||||
/// resource.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_with_options(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -287,11 +302,17 @@ where
|
||||
<JsonSerdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<JsonSerdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`JsonSerdeCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new(fut: impl Future<Output = T> + Send + 'static) -> Self {
|
||||
ArcOnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`JsonSerdeCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_blocking(fut: impl Future<Output = T> + Send + 'static) -> Self {
|
||||
ArcOnceResource::new_with_options(fut, true)
|
||||
@@ -307,6 +328,7 @@ T: Send + Sync + 'static,
|
||||
<FromToStringCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<FromToStringCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`FromToStringCodec`] for encoding/decoding the value.
|
||||
pub fn new_str(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
) -> Self
|
||||
@@ -314,6 +336,11 @@ T: Send + Sync + 'static,
|
||||
ArcOnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`FromToStringCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_str_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
) -> Self
|
||||
@@ -332,6 +359,7 @@ T: Send + Sync + 'static,
|
||||
<JsonSerdeWasmCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<JsonSerdeWasmCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`JsonSerdeWasmCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -340,6 +368,11 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
ArcOnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`JsonSerdeWasmCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -360,6 +393,7 @@ where
|
||||
<MiniserdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<MiniserdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`MiniserdeCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_miniserde(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -367,6 +401,11 @@ where
|
||||
ArcOnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`MiniserdeCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_miniserde_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -385,6 +424,7 @@ T: Send + Sync + 'static,
|
||||
<SerdeLite<JsonSerdeCodec> as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<SerdeLite<JsonSerdeCodec> as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`SerdeLite`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -393,6 +433,11 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
ArcOnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`SerdeLite`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -414,11 +459,17 @@ where
|
||||
<RkyvCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<RkyvCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`RkyvCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_rkyv(fut: impl Future<Output = T> + Send + 'static) -> Self {
|
||||
ArcOnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`RkyvCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_rkyv_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -427,6 +478,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A resource that only loads once.
|
||||
///
|
||||
/// Resources allow asynchronously loading data and serializing it from the server to the client,
|
||||
/// so that it loads on the server, and is then deserialized on the client. This improves
|
||||
/// performance by beginning data loading on the server when the request is made, rather than
|
||||
/// beginning it on the client after WASM has been loaded.
|
||||
///
|
||||
/// You can access the value of the resource either synchronously using `.get()` or asynchronously
|
||||
/// using `.await`.
|
||||
#[derive(Debug)]
|
||||
pub struct OnceResource<T, Ser = JsonSerdeCodec> {
|
||||
inner: ArenaItem<ArcOnceResource<T, Ser>>,
|
||||
@@ -452,6 +512,12 @@ where
|
||||
<Ser as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<Ser as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding `Ser`. If `blocking` is `true`, this is a blocking
|
||||
/// resource.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_with_options(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -567,11 +633,17 @@ where
|
||||
<JsonSerdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<JsonSerdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`JsonSerdeCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new(fut: impl Future<Output = T> + Send + 'static) -> Self {
|
||||
OnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`JsonSerdeCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_blocking(fut: impl Future<Output = T> + Send + 'static) -> Self {
|
||||
OnceResource::new_with_options(fut, true)
|
||||
@@ -587,6 +659,7 @@ T: Send + Sync + 'static,
|
||||
<FromToStringCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<FromToStringCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`FromToStringCodec`] for encoding/decoding the value.
|
||||
pub fn new_str(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
) -> Self
|
||||
@@ -594,6 +667,11 @@ T: Send + Sync + 'static,
|
||||
OnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`FromToStringCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_str_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
) -> Self
|
||||
@@ -612,6 +690,7 @@ T: Send + Sync + 'static,
|
||||
<JsonSerdeWasmCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<JsonSerdeWasmCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`JsonSerdeWasmCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -620,6 +699,11 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
OnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`JsonSerdeWasmCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -640,6 +724,7 @@ where
|
||||
<MiniserdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<MiniserdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`MiniserdeCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_miniserde(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -647,6 +732,11 @@ where
|
||||
OnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`MiniserdeCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_miniserde_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
@@ -665,6 +755,7 @@ T: Send + Sync + 'static,
|
||||
<SerdeLite<JsonSerdeCodec> as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<SerdeLite<JsonSerdeCodec> as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`SerdeLite`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -673,6 +764,11 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
OnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`SerdeLite`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static
|
||||
@@ -694,11 +790,17 @@ where
|
||||
<RkyvCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<RkyvCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a resource using [`RkyvCodec`] for encoding/decoding the value.
|
||||
#[track_caller]
|
||||
pub fn new_rkyv(fut: impl Future<Output = T> + Send + 'static) -> Self {
|
||||
OnceResource::new_with_options(fut, false)
|
||||
}
|
||||
|
||||
/// Creates a blocking resource using [`RkyvCodec`] for encoding/decoding the value.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_rkyv_blocking(
|
||||
fut: impl Future<Output = T> + Send + 'static,
|
||||
|
||||
@@ -37,9 +37,12 @@ use std::{
|
||||
pub(crate) static IS_SUPPRESSING_RESOURCE_LOAD: AtomicBool =
|
||||
AtomicBool::new(false);
|
||||
|
||||
/// Used to prevent resources from actually loading, in environments (like server route generation)
|
||||
/// where they are not needed.
|
||||
pub struct SuppressResourceLoad;
|
||||
|
||||
impl SuppressResourceLoad {
|
||||
/// Prevents resources from loading until this is dropped.
|
||||
pub fn new() -> Self {
|
||||
IS_SUPPRESSING_RESOURCE_LOAD.store(true, Ordering::Relaxed);
|
||||
Self
|
||||
@@ -58,6 +61,15 @@ impl Drop for SuppressResourceLoad {
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference-counted asynchronous resource.
|
||||
///
|
||||
/// Resources allow asynchronously loading data and serializing it from the server to the client,
|
||||
/// so that it loads on the server, and is then deserialized on the client. This improves
|
||||
/// performance by beginning data loading on the server when the request is made, rather than
|
||||
/// beginning it on the client after WASM has been loaded.
|
||||
///
|
||||
/// You can access the value of the resource either synchronously using `.get()` or asynchronously
|
||||
/// using `.await`.
|
||||
pub struct ArcResource<T, Ser = JsonSerdeCodec> {
|
||||
ser: PhantomData<Ser>,
|
||||
refetch: ArcRwSignal<usize>,
|
||||
@@ -194,6 +206,21 @@ where
|
||||
<Ser as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<Ser as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding `Ser`.
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// If `blocking` is `true`, this is a blocking resource.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_with_options<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -278,6 +305,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronously, reactively reads the current value of the resource and applies the function
|
||||
/// `f` to its value if it is `Some(_)`.
|
||||
#[track_caller]
|
||||
pub fn map<U>(&self, f: impl FnOnce(&T) -> U) -> Option<U>
|
||||
where
|
||||
@@ -351,6 +380,13 @@ where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + Clone + 'static,
|
||||
{
|
||||
/// Applies the given function when a resource that returns `Result<T, E>`
|
||||
/// has resolved and loaded an `Ok(_)`, rather than requiring nested `.map()`
|
||||
/// calls over the `Option<Result<_, _>>` returned by the resource.
|
||||
///
|
||||
/// This is useful when used with features like server functions, in conjunction
|
||||
/// with `<ErrorBoundary/>` and `<Suspense/>`, when these other components are
|
||||
/// left to handle the `None` and `Err(_)` states.
|
||||
#[track_caller]
|
||||
pub fn and_then<U>(&self, f: impl FnOnce(&T) -> U) -> Option<Result<U, E>> {
|
||||
self.map(|data| data.as_ref().map(f).map_err(|e| e.clone()))
|
||||
@@ -367,6 +403,15 @@ where
|
||||
<JsonSerdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<JsonSerdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`JsonSerdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -380,6 +425,19 @@ where
|
||||
ArcResource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`JsonSerdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -402,6 +460,15 @@ where
|
||||
<FromToStringCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<FromToStringCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`FromToStringCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
pub fn new_str<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -414,6 +481,19 @@ where
|
||||
ArcResource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`FromToStringCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_str_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -436,6 +516,15 @@ where
|
||||
<JsonSerdeWasmCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<JsonSerdeWasmCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`JsonSerdeWasmCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -449,6 +538,19 @@ where
|
||||
ArcResource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`JsonSerdeWasmCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -473,6 +575,15 @@ where
|
||||
<MiniserdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<MiniserdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`MiniserdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new_miniserde<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -486,6 +597,19 @@ where
|
||||
ArcResource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`MiniserdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_miniserde_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -509,6 +633,15 @@ where
|
||||
<SerdeLite<JsonSerdeCodec> as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<SerdeLite<JsonSerdeCodec> as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`SerdeLite`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -522,6 +655,19 @@ where
|
||||
ArcResource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`SerdeLite`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -547,6 +693,15 @@ where
|
||||
<RkyvCodec as Encoder<T>>::Encoded: IntoEncodedString,
|
||||
<RkyvCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`RkyvCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new_rkyv<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -560,6 +715,19 @@ where
|
||||
ArcResource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`RkyvCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_rkyv_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -590,11 +758,22 @@ impl<T, Ser> ArcResource<T, Ser>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
/// Returns a new [`Future`] that is ready when the resource has loaded, and accesses its inner
|
||||
/// value by reference.
|
||||
pub fn by_ref(&self) -> AsyncDerivedRefFuture<T> {
|
||||
self.data.by_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// An asynchronous resource.
|
||||
///
|
||||
/// Resources allow asynchronously loading data and serializing it from the server to the client,
|
||||
/// so that it loads on the server, and is then deserialized on the client. This improves
|
||||
/// performance by beginning data loading on the server when the request is made, rather than
|
||||
/// beginning it on the client after WASM has been loaded.
|
||||
///
|
||||
/// You can access the value of the resource either synchronously using `.get()` or asynchronously
|
||||
/// using `.await`.
|
||||
pub struct Resource<T, Ser = JsonSerdeCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -707,6 +886,15 @@ where
|
||||
<FromToStringCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`FromToStringCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new_str<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -720,6 +908,19 @@ where
|
||||
Resource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`FromToStringCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_str_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -745,6 +946,15 @@ where
|
||||
<JsonSerdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`JsonSerdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
#[track_caller]
|
||||
pub fn new<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -758,6 +968,19 @@ where
|
||||
Resource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`JsonSerdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -782,6 +1005,15 @@ where
|
||||
<JsonSerdeWasmCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`JsonSerdeWasmCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
pub fn new_serde_wb<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -794,6 +1026,19 @@ where
|
||||
Resource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`JsonSerdeWasmCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_serde_wb_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -819,6 +1064,15 @@ where
|
||||
<MiniserdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`MiniserdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
pub fn new_miniserde<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -830,6 +1084,31 @@ where
|
||||
{
|
||||
Resource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`MiniserdeCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_miniserde_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
) -> Self
|
||||
where
|
||||
S: PartialEq + Clone + Send + Sync + 'static,
|
||||
T: Send + Sync + 'static,
|
||||
Fut: Future<Output = T> + Send + 'static,
|
||||
{
|
||||
Resource::new_with_options(source, fetcher, true)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-lite")]
|
||||
@@ -843,6 +1122,15 @@ where
|
||||
<SerdeLite<JsonSerdeCodec> as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`SerdeLite`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
pub fn new_serde_lite<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -855,6 +1143,19 @@ where
|
||||
Resource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`SerdeLite`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_serde_lite_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -880,6 +1181,15 @@ where
|
||||
<RkyvCodec as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding [`RkyvCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
pub fn new_rkyv<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -892,6 +1202,19 @@ where
|
||||
Resource::new_with_options(source, fetcher, false)
|
||||
}
|
||||
|
||||
/// Creates a new blocking resource with the encoding [`RkyvCodec`].
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
pub fn new_rkyv_blocking<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
@@ -915,6 +1238,21 @@ where
|
||||
<Ser as Decoder<T>>::Encoded: FromEncodedStr,
|
||||
T: Send + Sync,
|
||||
{
|
||||
/// Creates a new resource with the encoding `Ser`.
|
||||
///
|
||||
/// This takes a `source` function and a `fetcher`. The resource memoizes and reactively tracks
|
||||
/// the value returned by `source`. Whenever that value changes, it will run the `fetcher` to
|
||||
/// generate a new [`Future`] to load data.
|
||||
///
|
||||
/// On creation, if you are on the server, this will run the `fetcher` once to generate
|
||||
/// a `Future` whose value will be serialized from the server to the client. If you are on
|
||||
/// the client, the initial value will be deserialized without re-running that async task.
|
||||
///
|
||||
/// If `blocking` is `true`, this is a blocking resource.
|
||||
///
|
||||
/// Blocking resources prevent any of the HTTP response from being sent until they have loaded.
|
||||
/// This is useful if you need their data to set HTML document metadata or information that
|
||||
/// needs to appear in HTTP headers.
|
||||
#[track_caller]
|
||||
pub fn new_with_options<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
@@ -937,6 +1275,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronously, reactively reads the current value of the resource and applies the function
|
||||
/// `f` to its value if it is `Some(_)`.
|
||||
pub fn map<U>(&self, f: impl FnOnce(&T) -> U) -> Option<U> {
|
||||
self.data
|
||||
.try_with(|n| n.as_ref().map(|n| Some(f(n))))?
|
||||
@@ -961,6 +1301,13 @@ where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync + Clone,
|
||||
{
|
||||
/// Applies the given function when a resource that returns `Result<T, E>`
|
||||
/// has resolved and loaded an `Ok(_)`, rather than requiring nested `.map()`
|
||||
/// calls over the `Option<Result<_, _>>` returned by the resource.
|
||||
///
|
||||
/// This is useful when used with features like server functions, in conjunction
|
||||
/// with `<ErrorBoundary/>` and `<Suspense/>`, when these other components are
|
||||
/// left to handle the `None` and `Err(_)` states.
|
||||
#[track_caller]
|
||||
pub fn and_then<U>(&self, f: impl FnOnce(&T) -> U) -> Option<Result<U, E>> {
|
||||
self.map(|data| data.as_ref().map(f).map_err(|e| e.clone()))
|
||||
@@ -984,6 +1331,8 @@ impl<T, Ser> Resource<T, Ser>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
/// Returns a new [`Future`] that is ready when the resource has loaded, and accesses its inner
|
||||
/// value by reference.
|
||||
pub fn by_ref(&self) -> AsyncDerivedRefFuture<T> {
|
||||
self.data.by_ref()
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ pub struct SharedValue<T, Ser = JsonSerdeCodec> {
|
||||
}
|
||||
|
||||
impl<T, Ser> SharedValue<T, Ser> {
|
||||
/// Returns the inner value.
|
||||
pub fn into_inner(self) -> T {
|
||||
self.value
|
||||
}
|
||||
@@ -46,6 +47,12 @@ where
|
||||
<<JsonSerdeCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses the [`JsonSerdeCodec`] encoding.
|
||||
pub fn new(initial: impl FnOnce() -> T) -> Self {
|
||||
SharedValue::new_with_encoding(initial)
|
||||
}
|
||||
@@ -61,6 +68,12 @@ where
|
||||
<<FromToStringCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses the [`FromToStringCodec`] encoding.
|
||||
pub fn new_str(initial: impl FnOnce() -> T) -> Self {
|
||||
SharedValue::new_with_encoding(initial)
|
||||
}
|
||||
@@ -77,7 +90,13 @@ where
|
||||
<<SerdeLite<JsonSerdeCodec> as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
pub fn new(initial: impl FnOnce() -> T) -> Self {
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses the [`SerdeLite`] encoding.
|
||||
pub fn new_serde_lite(initial: impl FnOnce() -> T) -> Self {
|
||||
SharedValue::new_with_encoding(initial)
|
||||
}
|
||||
}
|
||||
@@ -93,7 +112,13 @@ where
|
||||
<<JsonSerdeWasmCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
pub fn new(initial: impl FnOnce() -> T) -> Self {
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses the [`JsonSerdeWasmCodec`] encoding.
|
||||
pub fn new_serde_wb(initial: impl FnOnce() -> T) -> Self {
|
||||
SharedValue::new_with_encoding(initial)
|
||||
}
|
||||
}
|
||||
@@ -109,7 +134,13 @@ where
|
||||
<<MiniserdeCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
pub fn new(initial: impl FnOnce() -> T) -> Self {
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses the [`MiniserdeCodec`] encoding.
|
||||
pub fn new_miniserde(initial: impl FnOnce() -> T) -> Self {
|
||||
SharedValue::new_with_encoding(initial)
|
||||
}
|
||||
}
|
||||
@@ -125,7 +156,13 @@ where
|
||||
<<RkyvCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
pub fn new(initial: impl FnOnce() -> T) -> Self {
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses the [`RkyvCodec`] encoding.
|
||||
pub fn new_rkyv(initial: impl FnOnce() -> T) -> Self {
|
||||
SharedValue::new_with_encoding(initial)
|
||||
}
|
||||
}
|
||||
@@ -140,6 +177,12 @@ where
|
||||
<<Ser as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
|
||||
Debug,
|
||||
{
|
||||
/// Wraps the initial value.
|
||||
///
|
||||
/// If this is on the server, the function will be invoked and the value serialized. When it runs
|
||||
/// on the client, it will be deserialized without running the function again.
|
||||
///
|
||||
/// This uses `Ser` as an encoding.
|
||||
pub fn new_with_encoding(initial: impl FnOnce() -> T) -> Self {
|
||||
let value: T;
|
||||
#[cfg(feature = "hydration")]
|
||||
|
||||
Reference in New Issue
Block a user