Compare commits

..

2 Commits

Author SHA1 Message Date
Greg Johnston
a76b9d71f0 fix: type inference regression due to From<T> for Signal<T> impl (closes #3200) 2024-11-17 16:23:12 -05:00
Greg Johnston
e768617dbb Revert "feat: Option<T> read-like traits & deprecate MaybeSignal (#3098)"
This reverts commit 396327b667.
2024-11-17 16:14:05 -05:00
38 changed files with 207 additions and 624 deletions

View File

@@ -6,7 +6,9 @@ use leptos_axum::ResponseOptions;
// A basic function to display errors served by the error boundaries.
// Feel free to do more complicated things here than just displaying them.
#[component]
pub fn ErrorTemplate(#[prop(into)] errors: Signal<Errors>) -> impl IntoView {
pub fn ErrorTemplate(
#[prop(into)] errors: MaybeSignal<Errors>,
) -> impl IntoView {
// Get Errors from Signal
// Downcast lets us take a type that implements `std::error::Error`
let errors = Memo::new(move |_| {

View File

@@ -10,7 +10,7 @@ struct Then {
// the type with Option<...> and marking the option as #[prop(optional)].
#[slot]
struct ElseIf {
cond: Signal<bool>,
cond: MaybeSignal<bool>,
children: ChildrenFn,
}
@@ -22,7 +22,7 @@ struct Fallback {
// Slots are added to components like any other prop.
#[component]
fn SlotIf(
cond: Signal<bool>,
cond: MaybeSignal<bool>,
then: Then,
#[prop(default=vec![])] else_if: Vec<ElseIf>,
#[prop(optional)] fallback: Option<Fallback>,
@@ -43,9 +43,9 @@ fn SlotIf(
#[component]
pub fn App() -> impl IntoView {
let (count, set_count) = signal(0);
let is_even = Signal::derive(move || count.get() % 2 == 0);
let is_div5 = Signal::derive(move || count.get() % 5 == 0);
let is_div7 = Signal::derive(move || count.get() % 7 == 0);
let is_even = MaybeSignal::derive(move || count.get() % 2 == 0);
let is_div5 = MaybeSignal::derive(move || count.get() % 5 == 0);
let is_div7 = MaybeSignal::derive(move || count.get() % 7 == 0);
view! {
<button on:click=move |_| set_count.update(|value| *value += 1)>"+1"</button>

View File

@@ -38,7 +38,7 @@ pub fn TimerDemo() -> impl IntoView {
pub fn use_interval<T, F>(interval_millis: T, f: F)
where
F: Fn() + Clone + 'static,
T: Into<Signal<u64>> + 'static,
T: Into<MaybeSignal<u64>> + 'static,
{
let interval_millis = interval_millis.into();
Effect::new(move |prev_handle: Option<IntervalHandle>| {

View File

@@ -83,14 +83,15 @@ pub trait SharedContext: Debug {
/// Reads the current value of some data from the shared context, if it has been
/// sent from the server. This returns the serialized data as a `String` that should
/// be deserialized.
/// be deserialized using [`Serializable::de`].
///
/// On the server and in client-side rendered implementations, this should
/// always return [`None`].
fn read_data(&self, id: &SerializedDataId) -> Option<String>;
/// Returns a [`Future`] that resolves with a `String` that should
/// be deserialized once the given piece of server data has resolved.
/// be deserialized using [`Serializable::de`] once the given piece of server
/// data has resolved.
///
/// On the server and in client-side rendered implementations, this should
/// return a [`Future`] that is immediately ready with [`None`].
@@ -147,8 +148,8 @@ pub trait SharedContext: Debug {
/// Adds a `Future` to the set of “blocking resources” that should prevent the servers
/// response stream from beginning until all are resolved. The `Future` returned by
/// blocking resources will not resolve until every `Future` added by this method
/// has resolved.
/// [`blocking_resources`](Self::blocking_resources) will not resolve until every `Future`
/// added by this method has resolved.
///
/// In browser implementations, this should be a no-op.
fn defer_stream(&self, wait_for: PinnedFuture<()>);

View File

@@ -82,7 +82,7 @@ impl ResponseParts {
}
}
/// A wrapper for an Actix [`HttpRequest`] that allows it to be used in an
/// A wrapper for an Actix [`HttpRequest`](actix_web::HttpRequest) that allows it to be used in an
/// `Send`/`Sync` setting like Leptos's Context API.
#[derive(Debug, Clone)]
pub struct Request(SendWrapper<HttpRequest>);
@@ -419,6 +419,12 @@ pub fn handle_server_fns_with_context(
/// will include fallback content for any `<Suspense/>` nodes, and be immediately interactive,
/// but requires some client-side JavaScript.
///
/// The provides a [MetaContext] and a [RouterIntegrationContext] to apps context before
/// rendering it, and includes any meta tags injected using [leptos_meta].
///
/// The HTML stream is rendered using [render_to_stream](leptos::ssr::render_to_stream), and
/// includes everything described in the documentation for that function.
///
/// This can then be set up at an appropriate route in your application:
/// ```
/// use actix_web::{App, HttpServer};
@@ -459,6 +465,7 @@ pub fn handle_server_fns_with_context(
/// - [ResponseOptions]
/// - [Request]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -478,6 +485,13 @@ where
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve before
/// sending down its HTML. The app will become interactive once it has fully loaded.
///
/// The provides a [MetaContext] and a [RouterIntegrationContext] to apps context before
/// rendering it, and includes any meta tags injected using [leptos_meta].
///
/// The HTML stream is rendered using
/// [render_to_stream_in_order](leptos::ssr::render_to_stream_in_order),
/// and includes everything described in the documentation for that function.
///
/// This can then be set up at an appropriate route in your application:
/// ```
/// use actix_web::{App, HttpServer};
@@ -520,6 +534,7 @@ where
/// This function always provides context values including the following types:
/// - [ResponseOptions]
/// - [Request]
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -536,7 +551,13 @@ where
/// Returns an Actix [struct@Route](actix_web::Route) that listens for a `GET` request and tries
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
/// `async` resources have loaded.
/// `async` [Resource](leptos::Resource)s have loaded.
///
/// The provides a [MetaContext] and a [RouterIntegrationContext] to the apps context before
/// rendering it, and includes any meta tags injected using [leptos_meta].
///
/// The HTML stream is rendered using [render_to_string_async](leptos::ssr::render_to_string_async), and
/// includes everything described in the documentation for that function.
///
/// This can then be set up at an appropriate route in your application:
/// ```
@@ -669,6 +690,7 @@ where
/// - [ResponseOptions]
/// - [Request]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -691,7 +713,7 @@ where
/// Returns an Actix [struct@Route](actix_web::Route) that listens for a `GET` request and tries
/// to route it using [leptos_router], asynchronously serving the page once all `async`
/// resources have loaded.
/// [Resource](leptos::Resource)s have loaded.
///
/// This function allows you to provide additional information to Leptos for your route.
/// It could be used to pass in Path Info, Connection Info, or anything your heart desires.

View File

@@ -197,9 +197,9 @@ impl ExtendResponse for AxumResponse {
/// 2. A server function that is called from WASM running in the client (e.g., a dispatched action
/// or a spawned `Future`).
/// 3. A `<form>` submitted to the server function endpoint using default browser APIs (often due
/// to using [`ActionForm`] without JS/WASM present.)
/// to using [`ActionForm`](leptos::form::ActionForm) without JS/WASM present.)
///
/// Using it with a non-blocking [`Resource`] will not work if you are using streaming rendering,
/// Using it with a non-blocking [`Resource`](leptos::server::Resource) will not work if you are using streaming rendering,
/// as the response's headers will already have been sent by the time the server function calls `redirect()`.
///
/// ### Implementation
@@ -442,6 +442,12 @@ pub type PinnedHtmlStream =
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], serving an HTML stream of your application.
///
/// The provides a [MetaContext] and a [RouterIntegrationContext] to apps context before
/// rendering it, and includes any meta tags injected using [leptos_meta].
///
/// The HTML stream is rendered using [render_to_stream](leptos::ssr::render_to_stream), and
/// includes everything described in the documentation for that function.
///
/// This can then be set up at an appropriate route in your application:
/// ```
/// use axum::{handler::Handler, Router};
@@ -479,7 +485,8 @@ pub type PinnedHtmlStream =
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -530,6 +537,12 @@ where
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve before
/// sending down its HTML. The app will become interactive once it has fully loaded.
///
/// The provides a [MetaContext] and a [RouterIntegrationContext] to apps context before
/// rendering it, and includes any meta tags injected using [leptos_meta].
///
/// The HTML stream is rendered using [render_to_stream_in_order], and includes everything described in
/// the documentation for that function.
///
/// This can then be set up at an appropriate route in your application:
/// ```
/// use axum::{handler::Handler, Router};
@@ -567,7 +580,8 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -620,7 +634,8 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -751,7 +766,8 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -818,7 +834,8 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -935,7 +952,13 @@ fn provide_contexts(
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
/// `async` resources have loaded.
/// `async` [Resource](leptos::Resource)s have loaded.
///
/// The provides a [MetaContext] and a [RouterIntegrationContext] to apps context before
/// rendering it, and includes any meta tags injected using [leptos_meta].
///
/// The HTML stream is rendered using [render_to_string_async], and includes everything described in
/// the documentation for that function.
///
/// This can then be set up at an appropriate route in your application:
/// ```
@@ -975,7 +998,8 @@ fn provide_contexts(
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -996,7 +1020,7 @@ where
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
/// `async` resources have loaded.
/// `async` [Resource](leptos::Resource)s have loaded.
///
/// This version allows us to pass Axum State/Extension/Extractor or other infro from Axum or network
/// layers above Leptos itself. To use it, you'll need to write your own handler function that provides
@@ -1029,7 +1053,8 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)
@@ -1063,7 +1088,7 @@ where
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
/// `async` resources have loaded.
/// `async` [Resource](leptos::Resource)s have loaded.
///
/// This version allows us to pass Axum State/Extension/Extractor or other infro from Axum or network
/// layers above Leptos itself. To use it, you'll need to write your own handler function that provides
@@ -1096,7 +1121,8 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`ServerMetaContext`]
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[cfg_attr(
feature = "tracing",
tracing::instrument(level = "trace", fields(error), skip_all)

View File

@@ -31,13 +31,13 @@
//! *Notes*:
//! - The `render_number` prop can receive any type that implements `Fn(i32) -> String`.
//! - Callbacks are most useful when you want optional generic props.
//! - All callbacks implement the [`Callable`](leptos::callback::Callable) trait, and can be invoked with `my_callback.run(input)`.
//! - All callbacks implement the [`Callable`] trait, and can be invoked with `my_callback.run(input)`.
//! - The callback types implement [`Copy`], so they can easily be moved into and out of other closures, just like signals.
//!
//! # Types
//! This modules implements 2 callback types:
//! - [`Callback`](leptos::callback::Callback)
//! - [`UnsyncCallback`](leptos::callback::UnsyncCallback)
//! - [`Callback`]
//! - [`UnsyncCallback`]
//!
//! Use `SyncCallback` if the function is not `Sync` and `Send`.

View File

@@ -246,7 +246,7 @@ where
}
}
/// A typed equivalent to [`ChildrenFnMut`], which takes a generic but preserves type information to
/// A typed equivalent to [`ChildrenMut`], which takes a generic but preserves type information to
/// allow the compiler to optimize the view more effectively.
pub struct TypedChildrenMut<T>(Box<dyn FnMut() -> View<T> + Send>);

View File

@@ -72,7 +72,9 @@ use web_sys::{
#[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
#[component]
pub fn ActionForm<ServFn>(
/// The action from which to build the form.
/// The action from which to build the form. This should include a URL, which can be generated
/// by default using [`create_server_action`](leptos_server::create_server_action) or added
/// manually using [`using_server_fn`](leptos_server::Action::using_server_fn).
action: ServerAction<ServFn>,
/// A [`NodeRef`] in which the `<form>` element should be stored.
#[prop(optional)]
@@ -147,7 +149,9 @@ where
/// progressively enhanced to use client-side routing.
#[component]
pub fn MultiActionForm<ServFn>(
/// The action from which to build the form.
/// The action from which to build the form. This should include a URL, which can be generated
/// by default using [create_server_action](leptos_server::create_server_action) or added
/// manually using [leptos_server::Action::using_server_fn].
action: ServerMultiAction<ServFn>,
/// A [`NodeRef`] in which the `<form>` element should be stored.
#[prop(optional)]

View File

@@ -39,7 +39,7 @@
//! server actions, forms, and server-sent events (SSE).
//! - **[`todomvc`]** shows the basics of building an isomorphic web app. Both the server and the client import the same app code.
//! The server renders the app directly to an HTML string, and the client hydrates that HTML to make it interactive.
//! You might also want to see how we use [`Effect::new`](leptos::prelude::Effect) to
//! You might also want to see how we use [`Effect::new`](leptos::prelude::Effect::new) to
//! [serialize JSON to `localStorage`](https://github.com/leptos-rs/leptos/blob/20af4928b2fffe017408d3f4e7330db22cf68277/examples/todomvc/src/lib.rs#L191-L209)
//! and [reactively call DOM methods](https://github.com/leptos-rs/leptos/blob/16f084a71268ac325fbc4a5e50c260df185eadb6/examples/todomvc/src/lib.rs#L292-L296)
//! on [references to elements](https://github.com/leptos-rs/leptos/blob/20af4928b2fffe017408d3f4e7330db22cf68277/examples/todomvc/src/lib.rs#L228).
@@ -78,7 +78,7 @@
//! + `async` interop: [`Resource`](leptos::prelude::Resource) for loading data using `async` functions
//! and [`Action`](leptos::prelude::Action) to mutate data or imperatively call `async` functions.
//! + reactions: [`Effect`](leptos::prelude::Effect) and [`RenderEffect`](leptos::prelude::RenderEffect).
//! - **Templating/Views**: the [`view`] macro and [`IntoView`] trait.
//! - **Templating/Views**: the [`view`] macro and [`IntoView`](leptos::IntoView) trait.
//! - **Routing**: the [`leptos_router`](https://docs.rs/leptos_router/latest/leptos_router/) crate
//! - **Server Functions**: the [`server`](macro@leptos::prelude::server) macro and [`ServerAction`](leptos::prelude::ServerAction).
//!

View File

@@ -0,0 +1,22 @@
#[test]
fn generic_component_signal_inference() {
use leptos::prelude::*;
#[component]
pub fn SimpleCounter(#[prop(into)] step: Signal<i32>) -> impl IntoView {
_ = step;
view! {
<div>
</div>
}
}
let a = RwSignal::new(1);
let (b, _) = signal(1);
view! {
<SimpleCounter step=a/>
<SimpleCounter step=b/>
<SimpleCounter step=Signal::stored(1)/>
};
}

View File

@@ -1,4 +1,4 @@
//! Macros for use with the Leptos framework.
//! Macros for use with the [`leptos`] framework.
#![cfg_attr(feature = "nightly", feature(proc_macro_span))]
#![forbid(unsafe_code)]
@@ -272,8 +272,8 @@ pub fn view(tokens: TokenStream) -> TokenStream {
view_macro_impl(tokens, false)
}
/// The `template` macro behaves like [`view`](view!), except that it wraps the entire tree in a
/// [`ViewTemplate`](https://docs.rs/leptos/0.7.0-gamma3/leptos/prelude/struct.ViewTemplate.html). This optimizes creation speed by rendering
/// The `template` macro behaves like [`view`], except that it wraps the entire tree in a
/// [`ViewTemplate`](leptos::prelude::ViewTemplate). This optimizes creation speed by rendering
/// most of the view into a `<template>` tag with HTML rendered at compile time, then hydrating it.
/// In exchange, there is a small binary size overhead.
#[proc_macro_error2::proc_macro_error]
@@ -366,7 +366,7 @@ fn normalized_call_site(site: proc_macro::Span) -> Option<String> {
}
}
/// This behaves like the [`view`](view!) macro, but loads the view from an external file instead of
/// This behaves like the [`view`] macro, but loads the view from an external file instead of
/// parsing it inline.
///
/// This is designed to allow editing views in a separate file, if this improves a user's workflow.

View File

@@ -1,4 +1,4 @@
//! Utilities for communicating between the server and the client with Leptos.
//! Utilities for communicating between the server and the client with [`leptos`].
#![deny(missing_docs)]
#![forbid(unsafe_code)]

View File

@@ -253,8 +253,7 @@ where
}
}
/// A [`Future`] that is ready when an
/// [`ArcAsyncDerived`](reactive_graph::computed::ArcAsyncDerived) is finished loading or reloading,
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
/// and contains its value. `.await`ing this clones the value `T`.
pub struct OnceResourceFuture<T> {
source: AnySource,

View File

@@ -7,7 +7,8 @@
//! using the [`Leptos`](https://github.com/leptos-rs/leptos) web framework.
//!
//! Document metadata is updated automatically when running in the browser. For server-side
//! rendering, after the component tree is rendered to HTML, [`ServerMetaContextOutput::inject_meta_context`] will inject meta tags into a stream of HTML inside the `<head>`.
//! rendering, after the component tree is rendered to HTML, [`MetaContext::dehydrate`] can generate
//! HTML that should be injected into the `<head>` of the HTML document being rendered.
//!
//! ```
//! use leptos::prelude::*;

View File

@@ -19,7 +19,7 @@ pub(crate) use inner::MemoInner;
pub use memo::*;
pub use selector::*;
/// Derives a reactive slice of an [`RwSignal`].
/// Derives a reactive slice of an [`RwSignal`](crate::signal::RwSignal).
///
/// Slices have the same guarantees as [`Memo`s](crate::computed::Memo):
/// they only emit their value when it has actually been changed.

View File

@@ -84,7 +84,6 @@ pub mod owner;
#[cfg(feature = "serde")]
mod serde;
pub mod signal;
mod trait_options;
pub mod traits;
pub mod transition;
pub mod wrappers;
@@ -124,7 +123,7 @@ pub fn log_warning(text: Arguments) {
}
}
/// Calls [`Executor::spawn`](any_spawner::Executor), but ensures that the task also runs in the current arena, if
/// Calls [`Executor::spawn`], but ensures that the task also runs in the current arena, if
/// multithreaded arena sandboxing is enabled.
pub fn spawn(task: impl Future<Output = ()> + Send + 'static) {
#[cfg(feature = "sandboxed-arenas")]
@@ -133,9 +132,8 @@ pub fn spawn(task: impl Future<Output = ()> + Send + 'static) {
any_spawner::Executor::spawn(task);
}
/// Calls [`Executor::spawn_local`](any_spawner::Executor), but ensures that the task runs under the current reactive [`Owner`](crate::owner::Owner) and observer.
///
/// Does not cancel the task if the owner is cleaned up.
/// Calls [`Executor::spawn_local`], but ensures that the task runs under the current reactive [`Owner`]
/// and [`Observed`]. Does not cancel the task if the owner is cleaned up.
pub fn spawn_local_scoped(task: impl Future<Output = ()> + 'static) {
let task = ScopedFuture::new(task);
@@ -145,9 +143,8 @@ pub fn spawn_local_scoped(task: impl Future<Output = ()> + 'static) {
any_spawner::Executor::spawn_local(task);
}
/// Calls [`Executor::spawn_local`](any_spawner::Executor), but ensures that the task runs under the current reactive [`Owner`](crate::owner::Owner) and observer.
///
/// Cancels the task if the owner is cleaned up.
/// Calls [`Executor::spawn_local`], but ensures that the task runs under the current reactive [`Owner`]
/// and [`Observed`]. Cancels the task if the owner is cleaned up.
pub fn spawn_local_scoped_with_cancellation(
task: impl Future<Output = ()> + 'static,
) {

View File

@@ -1,5 +1,3 @@
#[allow(deprecated)]
use crate::wrappers::read::{MaybeProp, MaybeSignal};
use crate::{
computed::{ArcMemo, Memo},
owner::Storage,
@@ -9,7 +7,7 @@ use crate::{
},
traits::{Get, Set},
wrappers::{
read::{ArcSignal, Signal, SignalTypes},
read::{ArcSignal, MaybeProp, MaybeSignal, Signal},
write::SignalSetter,
},
};
@@ -114,8 +112,7 @@ macro_rules! impl_get_fn_traits_get_arena {
($($ty:ident),*) => {
$(
#[cfg(feature = "nightly")]
#[allow(deprecated)]
impl<T, S> FnOnce<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>> {
impl<T, S> FnOnce<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> {
type Output = <Self as Get>::Value;
#[inline(always)]
@@ -125,8 +122,7 @@ macro_rules! impl_get_fn_traits_get_arena {
}
#[cfg(feature = "nightly")]
#[allow(deprecated)]
impl<T, S> FnMut<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>> {
impl<T, S> FnMut<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> {
#[inline(always)]
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
self.get()
@@ -134,8 +130,7 @@ macro_rules! impl_get_fn_traits_get_arena {
}
#[cfg(feature = "nightly")]
#[allow(deprecated)]
impl<T, S> Fn<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>> {
impl<T, S> Fn<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> {
#[inline(always)]
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.get()

View File

@@ -30,7 +30,7 @@ impl<T> StorageAccess<T> for SendWrapper<T> {
}
}
/// A way of storing an [`ArenaItem`](super::arena_item::ArenaItem), either as itself or with a wrapper to make it threadsafe.
/// A way of storing a [`ArenaItem`], either as itself or with a wrapper to make it threadsafe.
///
/// This exists because all items stored in the arena must be `Send + Sync`, but in single-threaded
/// environments you might want or need to use thread-unsafe types.

View File

@@ -1,11 +1,9 @@
#[allow(deprecated)]
use crate::wrappers::read::{MaybeProp, MaybeSignal};
use crate::{
computed::{ArcMemo, Memo},
owner::Storage,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::With,
wrappers::read::{Signal, SignalTypes},
wrappers::read::{MaybeProp, MaybeSignal, Signal, SignalTypes},
};
use serde::{Deserialize, Serialize};
@@ -75,7 +73,6 @@ impl<T: Serialize + 'static, St: Storage<T>> Serialize for ArcMemo<T, St> {
}
}
#[allow(deprecated)]
impl<T, St> Serialize for MaybeSignal<T, St>
where
T: Clone + Send + Sync + Serialize,
@@ -99,8 +96,15 @@ where
S: serde::Serializer,
{
match &self.0 {
None => None::<T>.serialize(serializer),
Some(signal) => signal.with(|value| value.serialize(serializer)),
None | Some(MaybeSignal::Static(None)) => {
None::<T>.serialize(serializer)
}
Some(MaybeSignal::Static(Some(value))) => {
value.serialize(serializer)
}
Some(MaybeSignal::Dynamic(signal)) => {
signal.with(|value| value.serialize(serializer))
}
}
}
}
@@ -142,7 +146,6 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcRwSignal<T> {
}
}
#[allow(deprecated)]
impl<'de, T: Deserialize<'de>, St> Deserialize<'de> for MaybeSignal<T, St>
where
St: Storage<T>,

View File

@@ -1,238 +0,0 @@
use crate::{
traits::{
DefinedAt, Get, GetUntracked, Read, ReadUntracked, Track, With,
WithUntracked,
},
unwrap_signal,
};
use std::panic::Location;
impl<T> DefinedAt for Option<T>
where
T: DefinedAt,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
self.as_ref().map(DefinedAt::defined_at).unwrap_or(None)
}
}
impl<T> Track for Option<T>
where
T: Track,
{
fn track(&self) {
if let Some(signal) = self {
signal.track();
}
}
}
/// An alternative [`ReadUntracked`](crate) trait that works with `Option<Readable>` types.
pub trait ReadUntrackedOptional: Sized + DefinedAt {
/// The guard type that will be returned, which can be dereferenced to the value.
type Value;
/// Returns the guard, or `None` if the signal has already been disposed.
#[track_caller]
fn try_read_untracked(&self) -> Option<Self::Value>;
/// Returns the guard.
///
/// # Panics
/// Panics if you try to access a signal that has been disposed.
#[track_caller]
fn read_untracked(&self) -> Self::Value {
self.try_read_untracked()
.unwrap_or_else(unwrap_signal!(self))
}
}
impl<T> ReadUntrackedOptional for Option<T>
where
Self: DefinedAt,
T: ReadUntracked,
{
type Value = Option<<T as ReadUntracked>::Value>;
fn try_read_untracked(&self) -> Option<Self::Value> {
Some(if let Some(signal) = self {
Some(signal.try_read_untracked()?)
} else {
None
})
}
}
/// An alternative [`Read`](crate) trait that works with `Option<Readable>` types.
pub trait ReadOptional: DefinedAt {
/// The guard type that will be returned, which can be dereferenced to the value.
type Value;
/// Subscribes to the signal, and returns the guard, or `None` if the signal has already been disposed.
#[track_caller]
fn try_read(&self) -> Option<Self::Value>;
/// Subscribes to the signal, and returns the guard.
///
/// # Panics
/// Panics if you try to access a signal that has been disposed.
#[track_caller]
fn read(&self) -> Self::Value {
self.try_read().unwrap_or_else(unwrap_signal!(self))
}
}
impl<T> ReadOptional for Option<T>
where
Self: DefinedAt,
T: Read,
{
type Value = Option<<T as Read>::Value>;
fn try_read(&self) -> Option<Self::Value> {
Some(if let Some(readable) = self {
Some(readable.try_read()?)
} else {
None
})
}
}
/// An alternative [`WithUntracked`](crate) trait that works with `Option<Withable>` types.
pub trait WithUntrackedOptional: DefinedAt {
/// The type of the value contained in the signal.
type Value: ?Sized;
/// Applies the closure to the value, and returns the result,
/// or `None` if the signal has already been disposed.
#[track_caller]
fn try_with_untracked<U>(
&self,
fun: impl FnOnce(Option<&Self::Value>) -> U,
) -> Option<U>;
/// Applies the closure to the value, and returns the result.
///
/// # Panics
/// Panics if you try to access a signal that has been disposed.
#[track_caller]
fn with_untracked<U>(
&self,
fun: impl FnOnce(Option<&Self::Value>) -> U,
) -> U {
self.try_with_untracked(fun)
.unwrap_or_else(unwrap_signal!(self))
}
}
impl<T> WithUntrackedOptional for Option<T>
where
Self: DefinedAt,
T: WithUntracked,
<T as WithUntracked>::Value: Sized,
{
type Value = <T as WithUntracked>::Value;
fn try_with_untracked<U>(
&self,
fun: impl FnOnce(Option<&Self::Value>) -> U,
) -> Option<U> {
if let Some(signal) = self {
Some(signal.try_with_untracked(|val| fun(Some(val)))?)
} else {
Some(fun(None))
}
}
}
/// An alternative [`With`](crate) trait that works with `Option<Withable>` types.
pub trait WithOptional: DefinedAt {
/// The type of the value contained in the signal.
type Value: ?Sized;
/// Subscribes to the signal, applies the closure to the value, and returns the result,
/// or `None` if the signal has already been disposed.
#[track_caller]
fn try_with<U>(
&self,
fun: impl FnOnce(Option<&Self::Value>) -> U,
) -> Option<U>;
/// Subscribes to the signal, applies the closure to the value, and returns the result.
///
/// # Panics
/// Panics if you try to access a signal that has been disposed.
#[track_caller]
fn with<U>(&self, fun: impl FnOnce(Option<&Self::Value>) -> U) -> U {
self.try_with(fun).unwrap_or_else(unwrap_signal!(self))
}
}
impl<T> WithOptional for Option<T>
where
Self: DefinedAt,
T: With,
<T as With>::Value: Sized,
{
type Value = <T as With>::Value;
fn try_with<U>(
&self,
fun: impl FnOnce(Option<&Self::Value>) -> U,
) -> Option<U> {
if let Some(signal) = self {
Some(signal.try_with(|val| fun(Some(val)))?)
} else {
Some(fun(None))
}
}
}
impl<T> GetUntracked for Option<T>
where
Self: DefinedAt,
T: GetUntracked,
{
type Value = Option<<T as GetUntracked>::Value>;
fn try_get_untracked(&self) -> Option<Self::Value> {
Some(if let Some(signal) = self {
Some(signal.try_get_untracked()?)
} else {
None
})
}
}
impl<T> Get for Option<T>
where
Self: DefinedAt,
T: Get,
{
type Value = Option<<T as Get>::Value>;
fn try_get(&self) -> Option<Self::Value> {
Some(if let Some(signal) = self {
Some(signal.try_get()?)
} else {
None
})
}
}
/// Helper trait to implement flatten() on `Option<&Option<T>>`.
pub trait FlattenOptionRefOption {
/// The type of the value contained in the double option.
type Value;
/// Converts from `Option<&Option<T>>` to `Option<&T>`.
fn flatten(&self) -> Option<&Self::Value>;
}
impl<'a, T> FlattenOptionRefOption for Option<&'a Option<T>> {
type Value = T;
fn flatten(&self) -> Option<&'a T> {
self.map(Option::as_ref).flatten()
}
}

View File

@@ -16,7 +16,7 @@
//! | Trait | Mode | Description |
//! |-------------------|-------|---------------------------------------------------------------------------------------|
//! | [`Track`] | — | Tracks changes to this value, adding it as a source of the current reactive observer. |
//! | [`Notify`] | — | Notifies subscribers that this value has changed. |
//! | [`Trigger`] | — | Notifies subscribers that this value has changed. |
//! | [`ReadUntracked`] | Guard | Gives immutable access to the value of this signal. |
//! | [`Write`] | Guard | Gives mutable access to the value of this signal.
//!
@@ -34,7 +34,7 @@
//! | Trait | Mode | Composition | Description
//! |---------------------|---------------|-----------------------------------|------------
//! | [`UpdateUntracked`] | `fn(&mut T)` | [`Write`] | Applies closure to the current value to update it, but doesn't notify subscribers.
//! | [`Update`] | `fn(&mut T)` | [`UpdateUntracked`] + [`Notify`] | Applies closure to the current value to update it, and notifies subscribers.
//! | [`Update`] | `fn(&mut T)` | [`UpdateUntracked`] + [`Trigger`] | Applies closure to the current value to update it, and notifies subscribers.
//! | [`Set`] | `T` | [`Update`] | Sets the value to a new value, and notifies subscribers.
//!
//! ## Using the Traits
@@ -48,7 +48,6 @@
//! there isn't an `RwLock` so you can't wrap in a [`ReadGuard`](crate::signal::guards::ReadGuard),
//! but you can still implement [`WithUntracked`] and [`Track`], the same traits will still be implemented.
pub use crate::trait_options::*;
use crate::{
effect::Effect,
graph::{Observer, Source, Subscriber, ToAnySource},

View File

@@ -606,33 +606,6 @@ pub mod read {
}
}
impl<T: Send + Sync + 'static> From<T> for ArcSignal<T, SyncStorage> {
#[track_caller]
fn from(value: T) -> Self {
ArcSignal::stored(value)
}
}
impl<T> From<T> for Signal<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: T) -> Self {
Self::stored(value)
}
}
impl<T> From<T> for Signal<T, LocalStorage>
where
T: 'static,
{
#[track_caller]
fn from(value: T) -> Self {
Self::stored_local(value)
}
}
impl<T> From<ArcSignal<T, SyncStorage>> for Signal<T>
where
T: Send + Sync + 'static,
@@ -708,34 +681,6 @@ pub mod read {
}
}
impl<T> From<ArcReadSignal<T>> for Signal<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcReadSignal<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::ReadSignal(value)),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<ArcReadSignal<T>> for Signal<T, LocalStorage>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcReadSignal<T>) -> Self {
Self {
inner: ArenaItem::new_local(SignalTypes::ReadSignal(value)),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<RwSignal<T>> for Signal<T>
where
T: Send + Sync + 'static,
@@ -768,38 +713,6 @@ pub mod read {
}
}
impl<T> From<ArcRwSignal<T>> for Signal<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcRwSignal<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::ReadSignal(
value.read_only(),
)),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<ArcRwSignal<T>> for Signal<T, LocalStorage>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcRwSignal<T>) -> Self {
Self {
inner: ArenaItem::new_local(SignalTypes::ReadSignal(
value.read_only(),
)),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<Memo<T>> for Signal<T>
where
T: Send + Sync + 'static,
@@ -828,74 +741,6 @@ pub mod read {
}
}
impl<T> From<ArcMemo<T>> for Signal<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcMemo<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::Memo(value)),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<ArcMemo<T, LocalStorage>> for Signal<T, LocalStorage>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcMemo<T, LocalStorage>) -> Self {
Self {
inner: ArenaItem::new_local(SignalTypes::Memo(value)),
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
}
impl<T> From<T> for Signal<Option<T>>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: T) -> Self {
Signal::stored(Some(value))
}
}
impl<T> From<T> for Signal<Option<T>, LocalStorage>
where
T: 'static,
{
#[track_caller]
fn from(value: T) -> Self {
Signal::stored_local(Some(value))
}
}
impl<T> From<Signal<T>> for Signal<Option<T>>
where
T: Clone + Send + Sync + 'static,
{
#[track_caller]
fn from(value: Signal<T>) -> Self {
Signal::derive(move || Some(value.get()))
}
}
impl<T> From<Signal<T, LocalStorage>> for Signal<Option<T>, LocalStorage>
where
T: Clone + 'static,
{
#[track_caller]
fn from(value: Signal<T, LocalStorage>) -> Self {
Signal::derive_local(move || Some(value.get()))
}
}
impl From<&str> for Signal<String> {
#[track_caller]
fn from(value: &str) -> Self {
@@ -968,7 +813,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<MaybeSignal<T>> for Signal<T>
where
T: Send + Sync + 'static,
@@ -982,7 +826,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<MaybeSignal<T, LocalStorage>> for Signal<T, LocalStorage>
where
T: Send + Sync + 'static,
@@ -996,7 +839,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<MaybeSignal<T>> for Signal<Option<T>>
where
T: Clone + Send + Sync + 'static,
@@ -1012,7 +854,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<MaybeSignal<T, LocalStorage>> for Signal<Option<T>, LocalStorage>
where
T: Clone + Send + Sync + 'static,
@@ -1028,27 +869,6 @@ pub mod read {
}
}
impl<T> From<MaybeProp<T>> for Option<Signal<Option<T>>>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: MaybeProp<T>) -> Self {
value.0
}
}
impl<T> From<MaybeProp<T, LocalStorage>>
for Option<Signal<Option<T>, LocalStorage>>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: MaybeProp<T, LocalStorage>) -> Self {
value.0
}
}
/// A wrapper for a value that is *either* `T` or [`Signal<T>`].
///
/// This allows you to create APIs that take either a reactive or a non-reactive value
@@ -1077,12 +897,6 @@ pub mod read {
/// assert_eq!(above_3(&memoized_double_count.into()), true);
/// ```
#[derive(Debug, PartialEq, Eq)]
#[deprecated(
since = "0.7.0-rc1",
note = "`MaybeSignal<T>` is deprecated in favour of `Signal<T>` which \
is `Copy`, now has a more efficient From<T> implementation \
and other benefits in 0.7."
)]
pub enum MaybeSignal<T, S = SyncStorage>
where
T: 'static,
@@ -1094,7 +908,6 @@ pub mod read {
Dynamic(Signal<T, S>),
}
#[allow(deprecated)]
impl<T: Clone, S> Clone for MaybeSignal<T, S>
where
S: Storage<T>,
@@ -1107,10 +920,8 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T: Copy, S> Copy for MaybeSignal<T, S> where S: Storage<T> {}
#[allow(deprecated)]
impl<T: Default, S> Default for MaybeSignal<T, S>
where
S: Storage<T>,
@@ -1120,7 +931,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T, S> DefinedAt for MaybeSignal<T, S>
where
S: Storage<T>,
@@ -1132,7 +942,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T, S> Track for MaybeSignal<T, S>
where
S: Storage<T> + Storage<SignalTypes<T, S>>,
@@ -1145,7 +954,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T, S> ReadUntracked for MaybeSignal<T, S>
where
T: Clone,
@@ -1170,7 +978,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> MaybeSignal<T>
where
T: Send + Sync,
@@ -1184,7 +991,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> MaybeSignal<T, LocalStorage> {
/// Wraps a derived signal, i.e., any computation that accesses one or more
/// reactive signals.
@@ -1193,7 +999,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<T> for MaybeSignal<T, SyncStorage>
where
SyncStorage: Storage<T>,
@@ -1203,7 +1008,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> FromLocal<T> for MaybeSignal<T, LocalStorage>
where
LocalStorage: Storage<T>,
@@ -1213,7 +1017,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<ReadSignal<T>> for MaybeSignal<T>
where
T: Send + Sync,
@@ -1223,14 +1026,12 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<ReadSignal<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
fn from(value: ReadSignal<T, LocalStorage>) -> Self {
Self::Dynamic(value.into())
}
}
#[allow(deprecated)]
impl<T> From<RwSignal<T>> for MaybeSignal<T>
where
T: Send + Sync,
@@ -1240,14 +1041,12 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<RwSignal<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
fn from(value: RwSignal<T, LocalStorage>) -> Self {
Self::Dynamic(value.into())
}
}
#[allow(deprecated)]
impl<T> From<Memo<T>> for MaybeSignal<T>
where
T: Send + Sync,
@@ -1257,14 +1056,12 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<Memo<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
fn from(value: Memo<T, LocalStorage>) -> Self {
Self::Dynamic(value.into())
}
}
#[allow(deprecated)]
impl<T> From<ArcReadSignal<T>> for MaybeSignal<T>
where
T: Send + Sync,
@@ -1274,14 +1071,12 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> FromLocal<ArcReadSignal<T>> for MaybeSignal<T, LocalStorage> {
fn from_local(value: ArcReadSignal<T>) -> Self {
ReadSignal::from_local(value).into()
}
}
#[allow(deprecated)]
impl<T> From<ArcRwSignal<T>> for MaybeSignal<T>
where
T: Send + Sync + 'static,
@@ -1291,7 +1086,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> FromLocal<ArcRwSignal<T>> for MaybeSignal<T, LocalStorage>
where
T: 'static,
@@ -1301,7 +1095,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> From<ArcMemo<T>> for MaybeSignal<T>
where
T: Send + Sync,
@@ -1311,14 +1104,12 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<T> FromLocal<ArcMemo<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
fn from_local(value: ArcMemo<T, LocalStorage>) -> Self {
Memo::from_local(value).into()
}
}
#[allow(deprecated)]
impl<T, S> From<Signal<T, S>> for MaybeSignal<T, S>
where
S: Storage<T>,
@@ -1328,7 +1119,6 @@ pub mod read {
}
}
#[allow(deprecated)]
impl<S> From<&str> for MaybeSignal<String, S>
where
S: Storage<String> + Storage<Arc<RwLock<String>>>,
@@ -1372,28 +1162,25 @@ pub mod read {
/// ```
#[derive(Debug, PartialEq, Eq)]
pub struct MaybeProp<T: 'static, S = SyncStorage>(
pub(crate) Option<Signal<Option<T>, S>>,
pub(crate) Option<MaybeSignal<Option<T>, S>>,
)
where
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>;
S: Storage<Option<T>>;
impl<T, S> Clone for MaybeProp<T, S>
impl<T: Clone, S> Clone for MaybeProp<T, S>
where
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
S: Storage<Option<T>>,
{
fn clone(&self) -> Self {
*self
Self(self.0.clone())
}
}
impl<T, S> Copy for MaybeProp<T, S> where
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>
{
}
impl<T: Copy, S> Copy for MaybeProp<T, S> where S: Storage<Option<T>> {}
impl<T, S> Default for MaybeProp<T, S>
where
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
S: Storage<Option<T>>,
{
fn default() -> Self {
Self(None)
@@ -1402,7 +1189,7 @@ pub mod read {
impl<T, S> DefinedAt for MaybeProp<T, S>
where
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
S: Storage<Option<T>>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
// TODO this can be improved by adding a defined_at field
@@ -1425,7 +1212,7 @@ pub mod read {
impl<T, S> ReadUntracked for MaybeProp<T, S>
where
T: Clone,
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
S: Storage<SignalTypes<Option<T>, S>> + Storage<Option<T>>,
{
type Value = ReadGuard<Option<T>, SignalReadGuard<Option<T>, S>>;
@@ -1453,49 +1240,43 @@ pub mod read {
pub fn derive(
derived_signal: impl Fn() -> Option<T> + Send + Sync + 'static,
) -> Self {
Self(Some(Signal::derive(derived_signal)))
Self(Some(MaybeSignal::derive(derived_signal)))
}
}
impl<T> From<T> for MaybeProp<T>
where
T: Send + Sync,
SyncStorage: Storage<Option<T>>,
{
fn from(value: T) -> Self {
Self(Some(Signal::stored(Some(value))))
Self(Some(MaybeSignal::from(Some(value))))
}
}
impl<T> From<Option<T>> for MaybeProp<T>
where
T: Send + Sync,
SyncStorage: Storage<Option<T>>,
{
fn from(value: Option<T>) -> Self {
Self(Some(Signal::stored(value)))
Self(Some(MaybeSignal::from(value)))
}
}
#[allow(deprecated)]
impl<T> From<MaybeSignal<Option<T>>> for MaybeProp<T>
where
T: Send + Sync,
SyncStorage: Storage<Option<T>>,
{
fn from(value: MaybeSignal<Option<T>>) -> Self {
Self(Some(value.into()))
Self(Some(value))
}
}
#[allow(deprecated)]
impl<T> From<Option<MaybeSignal<Option<T>>>> for MaybeProp<T>
where
T: Send + Sync,
SyncStorage: Storage<Option<T>>,
{
fn from(value: Option<MaybeSignal<Option<T>>>) -> Self {
Self(value.map(Into::into))
Self(value)
}
}
@@ -1528,11 +1309,10 @@ pub mod read {
impl<T> From<Signal<Option<T>>> for MaybeProp<T>
where
T: Send + Sync,
SyncStorage: Storage<Option<T>>,
{
fn from(value: Signal<Option<T>>) -> Self {
Self(Some(value))
Self(Some(value.into()))
}
}
@@ -1541,7 +1321,7 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: ReadSignal<T>) -> Self {
Self(Some(Signal::derive(move || Some(value.get()))))
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
}
}
@@ -1550,7 +1330,7 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: RwSignal<T>) -> Self {
Self(Some(Signal::derive(move || Some(value.get()))))
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
}
}
@@ -1559,7 +1339,7 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: Memo<T>) -> Self {
Self(Some(Signal::derive(move || Some(value.get()))))
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
}
}
@@ -1568,13 +1348,13 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: Signal<T>) -> Self {
Self(Some(Signal::derive(move || Some(value.get()))))
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
}
}
impl From<&str> for MaybeProp<String> {
fn from(value: &str) -> Self {
Self(Some(Signal::from(Some(value.to_string()))))
Self(Some(MaybeSignal::from(Some(value.to_string()))))
}
}
@@ -1584,41 +1364,35 @@ pub mod read {
pub fn derive_local(
derived_signal: impl Fn() -> Option<T> + 'static,
) -> Self {
Self(Some(Signal::derive_local(derived_signal)))
Self(Some(MaybeSignal::derive_local(derived_signal)))
}
}
impl<T> FromLocal<T> for MaybeProp<T, LocalStorage> {
fn from_local(value: T) -> Self {
Self(Some(Signal::stored_local(Some(value))))
Self(Some(MaybeSignal::from_local(Some(value))))
}
}
impl<T> FromLocal<Option<T>> for MaybeProp<T, LocalStorage> {
fn from_local(value: Option<T>) -> Self {
Self(Some(Signal::stored_local(value)))
Self(Some(MaybeSignal::from_local(value)))
}
}
#[allow(deprecated)]
impl<T> From<MaybeSignal<Option<T>, LocalStorage>>
for MaybeProp<T, LocalStorage>
where
T: Send + Sync,
{
fn from(value: MaybeSignal<Option<T>, LocalStorage>) -> Self {
Self(Some(value.into()))
Self(Some(value))
}
}
#[allow(deprecated)]
impl<T> From<Option<MaybeSignal<Option<T>, LocalStorage>>>
for MaybeProp<T, LocalStorage>
where
T: Send + Sync,
{
fn from(value: Option<MaybeSignal<Option<T>, LocalStorage>>) -> Self {
Self(value.map(Into::into))
Self(value)
}
}
@@ -1651,7 +1425,7 @@ pub mod read {
impl<T> From<Signal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage> {
fn from(value: Signal<Option<T>, LocalStorage>) -> Self {
Self(Some(value))
Self(Some(value.into()))
}
}
@@ -1660,7 +1434,7 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: ReadSignal<T, LocalStorage>) -> Self {
Self(Some(Signal::derive_local(move || Some(value.get()))))
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
}
}
@@ -1669,7 +1443,7 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: RwSignal<T, LocalStorage>) -> Self {
Self(Some(Signal::derive_local(move || Some(value.get()))))
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
}
}
@@ -1678,7 +1452,7 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: Memo<T, LocalStorage>) -> Self {
Self(Some(Signal::derive_local(move || Some(value.get()))))
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
}
}
@@ -1687,13 +1461,13 @@ pub mod read {
T: Send + Sync + Clone,
{
fn from(value: Signal<T, LocalStorage>) -> Self {
Self(Some(Signal::derive_local(move || Some(value.get()))))
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
}
}
impl From<&str> for MaybeProp<String, LocalStorage> {
fn from(value: &str) -> Self {
Self(Some(Signal::stored_local(Some(value.to_string()))))
Self(Some(MaybeSignal::from_local(Some(value.to_string()))))
}
}

View File

@@ -64,8 +64,8 @@ pub fn Router<Chil>(
//#[prop(optional)]
//trailing_slash: TrailingSlash,
/// The `<Router/>` should usually wrap your whole page. It can contain
/// any elements, and should include a [`Routes`] component somewhere
/// to define and display [`Route`]s.
/// any elements, and should include a [`Routes`](crate::Routes) component somewhere
/// to define and display [`Route`](crate::Route)s.
children: TypedChildren<Chil>,
) -> impl IntoView
where
@@ -328,10 +328,9 @@ where
/// and the element it should display.
#[component(transparent)]
pub fn Route<Segments, View>(
/// The path fragment that this route should match. This can be created using the
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
/// The path fragment that this route should match. This can be created using the [`path`]
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
/// [`OptionalParamSegment`]).
path: Segments,
/// The view for this route.
view: View,
@@ -350,10 +349,9 @@ where
/// and the element it should display.
#[component(transparent)]
pub fn ParentRoute<Segments, View, Children>(
/// The path fragment that this route should match. This can be created using the
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
/// The path fragment that this route should match. This can be created using the [`path`]
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
/// [`OptionalParamSegment`]).
path: Segments,
/// The view for this route.
view: View,
@@ -376,10 +374,9 @@ where
/// redirects to `redirect_path` instead of displaying its `view`.
#[component(transparent)]
pub fn ProtectedRoute<Segments, ViewFn, View, C, PathFn, P>(
/// The path fragment that this route should match. This can be created using the
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
/// The path fragment that this route should match. This can be created using the [`path`]
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
/// [`OptionalParamSegment`]).
path: Segments,
/// The view for this route.
view: ViewFn,
@@ -430,10 +427,9 @@ where
#[component(transparent)]
pub fn ProtectedParentRoute<Segments, ViewFn, View, C, PathFn, P, Children>(
/// The path fragment that this route should match. This can be created using the
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
/// The path fragment that this route should match. This can be created using the [`path`]
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
/// [`OptionalParamSegment`]).
path: Segments,
/// The view for this route.
view: ViewFn,

View File

@@ -17,8 +17,7 @@
//! and are rendered by different components. This means you can navigate between siblings
//! in this tree without re-rendering or triggering any change in the parent routes.
//!
//! 3. **Progressive enhancement.** The [`A`](crate::components::A) and
//! [`Form`](crate::components::Form) components resolve any relative
//! 3. **Progressive enhancement.** The [`A`] and [`Form`] components resolve any relative
//! nested routes, render actual `<a>` and `<form>` elements, and (when possible)
//! upgrading them to handle those navigations with client-side routing. If youre using
//! them with server-side rendering (with or without hydration), they just work,

View File

@@ -9,7 +9,8 @@ pub use static_segment::*;
/// or URL segment.
///
/// This is a "horizontal" matching: i.e., it treats a tuple of route segments
/// as subsequent segments of the URL and tries to match them all.
/// as subsequent segments of the URL and tries to match them all. For a "vertical"
/// matching that sees a tuple as alternatives to one another, see [`RouteChild`](super::RouteChild).
pub trait PossibleRouteMatch {
const OPTIONAL: bool = false;

View File

@@ -1,6 +1,6 @@
use crate::location::State;
/// Options that can be used to configure a navigation. Used with [use_navigate](crate::hooks::use_navigate).
/// Options that can be used to configure a navigation. Used with [use_navigate](crate::use_navigate).
#[derive(Clone, Debug)]
pub struct NavigateOptions {
/// Whether the URL being navigated to should be resolved relative to the current route.

View File

@@ -24,7 +24,7 @@ impl ParamsMap {
/// Inserts a value into the map.
///
/// If a value with that key already exists, the new value will be added to it.
/// To replace the value instead, see [`replace`](Self::replace).
/// To replace the value instead, see [`replace`].
pub fn insert(&mut self, key: impl Into<Cow<'static, str>>, value: String) {
let value = Url::unescape(&value);

View File

@@ -10,8 +10,8 @@ use crate::{
use wasm_bindgen::JsValue;
use web_sys::Element;
/// Extends an HTML element, allowing you to add attributes and children to the
/// element's built state at runtime, with a similar API to how they
/// Extends the [`Element`](Renderer::Element) type of a [`Renderer`], allowing you to add
/// attributes and children to the element's built state at runtime, with a similar API to how they
/// can be added to the static view tree at compile time.
///
/// ```rust,ignore

View File

@@ -128,9 +128,7 @@ where
}
/// Any type that can be added to the `style` attribute or set as a style in
/// the [`CssStyleDeclaration`](web_sys::CssStyleDeclaration).
///
/// This could be a plain string, or a property name-value pair.
/// the [`CssStyleDeclaration`]. This could be a plain string, or a property name-value pair.
pub trait IntoStyle: Send {
/// The type after all async data have resolved.
type AsyncOutput: IntoStyle;

View File

@@ -519,7 +519,6 @@ mod stable {
macro_rules! class_signal_arena {
($sig:ident) => {
#[allow(deprecated)]
impl<C, S> IntoClass for $sig<C, S>
where
$sig<C, S>: Get<Value = C>,
@@ -589,7 +588,6 @@ mod stable {
}
}
#[allow(deprecated)]
impl<S> IntoClass for (&'static str, $sig<bool, S>)
where
$sig<bool, S>: Get<Value = bool>,
@@ -827,14 +825,12 @@ mod stable {
use super::RenderEffect;
use crate::html::class::IntoClass;
#[allow(deprecated)]
use reactive_graph::wrappers::read::MaybeSignal;
use reactive_graph::{
computed::{ArcMemo, Memo},
owner::Storage,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::Get,
wrappers::read::{ArcSignal, Signal},
wrappers::read::{ArcSignal, MaybeSignal, Signal},
};
class_signal_arena!(RwSignal);

View File

@@ -89,15 +89,13 @@ where
#[cfg(not(feature = "nightly"))]
mod stable {
use crate::html::element::InnerHtmlValue;
#[allow(deprecated)]
use reactive_graph::wrappers::read::MaybeSignal;
use reactive_graph::{
computed::{ArcMemo, Memo},
effect::RenderEffect,
owner::Storage,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::Get,
wrappers::read::{ArcSignal, Signal},
wrappers::read::{ArcSignal, MaybeSignal, Signal},
};
macro_rules! inner_html_signal {
@@ -161,7 +159,6 @@ mod stable {
macro_rules! inner_html_signal_arena {
($sig:ident) => {
#[allow(deprecated)]
impl<V, S> InnerHtmlValue for $sig<V, S>
where
$sig<V, S>: Get<Value = V>,

View File

@@ -507,15 +507,13 @@ mod stable {
RenderHtml,
},
};
#[allow(deprecated)]
use reactive_graph::wrappers::read::MaybeSignal;
use reactive_graph::{
computed::{ArcMemo, Memo},
effect::RenderEffect,
owner::Storage,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::Get,
wrappers::read::{ArcSignal, Signal},
wrappers::read::{ArcSignal, MaybeSignal, Signal},
};
macro_rules! signal_impl {
@@ -685,7 +683,6 @@ mod stable {
macro_rules! signal_impl_arena {
($sig:ident $dry_resolve:literal) => {
#[allow(deprecated)]
impl<V, S> Render for $sig<V, S>
where
$sig<V, S>: Get<Value = V>,
@@ -710,7 +707,6 @@ mod stable {
}
}
#[allow(deprecated)]
impl<V, S> AddAnyAttr for $sig<V, S>
where
$sig<V, S>: Get<Value = V>,
@@ -732,7 +728,6 @@ mod stable {
}
}
#[allow(deprecated)]
impl<V, S> RenderHtml for $sig<V, S>
where
$sig<V, S>: Get<Value = V>,
@@ -798,7 +793,6 @@ mod stable {
}
}
#[allow(deprecated)]
impl<V, S> AttributeValue for $sig<V, S>
where
$sig<V, S>: Get<Value = V>,

View File

@@ -82,15 +82,13 @@ where
#[cfg(not(feature = "nightly"))]
mod stable {
use crate::html::property::IntoProperty;
#[allow(deprecated)]
use reactive_graph::wrappers::read::MaybeSignal;
use reactive_graph::{
computed::{ArcMemo, Memo},
effect::RenderEffect,
owner::Storage,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::Get,
wrappers::read::{ArcSignal, Signal},
wrappers::read::{ArcSignal, MaybeSignal, Signal},
};
macro_rules! property_signal {
@@ -138,7 +136,6 @@ mod stable {
macro_rules! property_signal_arena {
($sig:ident) => {
#[allow(deprecated)]
impl<V, S> IntoProperty for $sig<V, S>
where
$sig<V, S>: Get<Value = V>,

View File

@@ -393,7 +393,6 @@ mod stable {
macro_rules! style_signal_arena {
($sig:ident) => {
#[allow(deprecated)]
impl<C, S> IntoStyle for $sig<C, S>
where
$sig<C, S>: Get<Value = C>,
@@ -459,7 +458,6 @@ mod stable {
}
}
#[allow(deprecated)]
impl<S, St> IntoStyle for (&'static str, $sig<S, St>)
where
$sig<S, St>: Get<Value = S>,
@@ -536,14 +534,12 @@ mod stable {
use super::RenderEffect;
use crate::html::style::IntoStyle;
#[allow(deprecated)]
use reactive_graph::wrappers::read::MaybeSignal;
use reactive_graph::{
computed::{ArcMemo, Memo},
owner::Storage,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::Get,
wrappers::read::{ArcSignal, Signal},
wrappers::read::{ArcSignal, MaybeSignal, Signal},
};
use std::borrow::Cow;

View File

@@ -1,6 +1,6 @@
#![allow(missing_docs)]
//! See [`Renderer`](crate::renderer::Renderer) and [`Rndr`](crate::renderer::Rndr) for additional information.
//! See [`Renderer`](super::Renderer) and [`Rndr`](super::Rndr) for additional information.
use super::{CastFrom, RemoveEventHandler};
use crate::{
@@ -15,7 +15,7 @@ use std::{any::TypeId, borrow::Cow, cell::RefCell};
use wasm_bindgen::{intern, prelude::Closure, JsCast, JsValue};
use web_sys::{Comment, HtmlTemplateElement};
/// A [`Renderer`](crate::renderer::Renderer) that uses `web-sys` to manipulate DOM elements in the browser.
/// A [`Renderer`] that uses `web-sys` to manipulate DOM elements in the browser.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Dom;

View File

@@ -14,8 +14,7 @@ pub mod dom;
/// applications, so this "generic rendering" approach was removed before 0.7.0 release.
///
/// It is possible that we will try a different approach to achieve the same functionality in the
/// future, so to the extent possible the rest of the crate tries to stick to using
/// [`Renderer`].
/// future, so to the extent possible the rest of the crate tries to stick to using [`Renderer`]
/// methods rather than directly manipulating the DOM inline.
pub type Rndr = dom::Dom;

View File

@@ -29,6 +29,9 @@ pub mod template;
pub mod tuples;
/// The `Render` trait allows rendering something as part of the user interface.
///
/// It is generic over the renderer itself, as long as that implements the [`Renderer`]
/// trait.
pub trait Render: Sized {
/// The “view state” for this type, which can be retained between updates.
///