Compare commits

..

1 Commits

Author SHA1 Message Date
Greg Johnston
9e5bfd0009 chore: fix broken links, etc. in docs 2024-11-20 20:48:04 -05:00
106 changed files with 861 additions and 2015 deletions

12
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "cargo"
directories:
- "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10

View File

@@ -13,7 +13,6 @@ concurrency:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
DEBIAN_FRONTEND: noninteractive
jobs:
autofix:
runs-on: ubuntu-latest
@@ -22,10 +21,6 @@ jobs:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with: {toolchain: nightly, components: "rustfmt, clippy", target: "wasm32-unknown-unknown", rustflags: ""}
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev
- name: Install jq
run: sudo apt-get install jq
- run: |

View File

@@ -8,21 +8,15 @@ on:
branches:
- main
- leptos_0.6
env:
DEBIAN_FRONTEND: noninteractive
jobs:
get-leptos-changed:
uses: ./.github/workflows/get-leptos-changed.yml
test:
needs: [get-leptos-changed]
if: needs.get-leptos-changed.outputs.leptos_changed == 'true' && github.event.pull_request.labels[0].name != 'breaking'
if: github.event.pull_request.labels[0].name == 'semver' # needs.get-leptos-changed.outputs.leptos_changed == 'true' && github.event.pull_request.labels[0].name != 'breaking'
name: Run semver check (nightly-2024-08-01)
runs-on: ubuntu-latest
steps:
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev
- name: Checkout
uses: actions/checkout@v4
- name: Semver Checks

View File

@@ -14,7 +14,6 @@ on:
env:
CARGO_TERM_COLOR: always
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
DEBIAN_FRONTEND: noninteractive
jobs:
test:
name: Run ${{ inputs.cargo_make_task }} (${{ inputs.toolchain }})
@@ -34,10 +33,6 @@ jobs:
echo "Disk space after cleanup:"
df -h
# Setup environment
- name: Install Glib
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@master

650
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -40,36 +40,36 @@ members = [
exclude = ["benchmarks", "examples", "projects"]
[workspace.package]
version = "0.7.2"
version = "0.7.0-rc1"
edition = "2021"
rust-version = "1.76"
[workspace.dependencies]
throw_error = { path = "./any_error/", version = "0.2.0" }
any_spawner = { path = "./any_spawner/", version = "0.2.0" }
throw_error = { path = "./any_error/", version = "0.2.0-rc1" }
any_spawner = { path = "./any_spawner/", version = "0.1.0" }
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1.0" }
either_of = { path = "./either_of/", version = "0.1.0" }
hydration_context = { path = "./hydration_context", version = "0.2.0" }
leptos = { path = "./leptos", version = "0.7.2" }
leptos_config = { path = "./leptos_config", version = "0.7.2" }
leptos_dom = { path = "./leptos_dom", version = "0.7.2" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.7.2" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.7.2" }
leptos_macro = { path = "./leptos_macro", version = "0.7.2" }
leptos_router = { path = "./router", version = "0.7.2" }
leptos_router_macro = { path = "./router_macro", version = "0.7.2" }
leptos_server = { path = "./leptos_server", version = "0.7.2" }
leptos_meta = { path = "./meta", version = "0.7.2" }
next_tuple = { path = "./next_tuple", version = "0.1.0" }
hydration_context = { path = "./hydration_context", version = "0.2.0-rc1" }
leptos = { path = "./leptos", version = "0.7.0-rc1" }
leptos_config = { path = "./leptos_config", version = "0.7.0-rc1" }
leptos_dom = { path = "./leptos_dom", version = "0.7.0-rc1" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.7.0-rc1" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.7.0-rc1" }
leptos_macro = { path = "./leptos_macro", version = "0.7.0-rc1" }
leptos_router = { path = "./router", version = "0.7.0-rc1" }
leptos_router_macro = { path = "./router_macro", version = "0.7.0-rc1" }
leptos_server = { path = "./leptos_server", version = "0.7.0-rc1" }
leptos_meta = { path = "./meta", version = "0.7.0-rc1" }
next_tuple = { path = "./next_tuple", version = "0.1.0-rc1" }
oco_ref = { path = "./oco", version = "0.2.0" }
or_poisoned = { path = "./or_poisoned", version = "0.1.0" }
reactive_graph = { path = "./reactive_graph", version = "0.1.0" }
reactive_stores = { path = "./reactive_stores", version = "0.1.0" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.1.0" }
server_fn = { path = "./server_fn", version = "0.7.2" }
server_fn_macro = { path = "./server_fn_macro", version = "0.7.2" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.7.2" }
tachys = { path = "./tachys", version = "0.1.0" }
reactive_graph = { path = "./reactive_graph", version = "0.1.0-rc1" }
reactive_stores = { path = "./reactive_stores", version = "0.1.0-rc1" }
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.1.0-rc1" }
server_fn = { path = "./server_fn", version = "0.7.0-rc1" }
server_fn_macro = { path = "./server_fn_macro", version = "0.7.0-rc1" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.7.0-rc1" }
tachys = { path = "./tachys", version = "0.1.0-rc1" }
[profile.release]
codegen-units = 1
@@ -78,9 +78,3 @@ opt-level = 'z'
[workspace.metadata.cargo-all-features]
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"]]
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(leptos_debuginfo)',
'cfg(erase_components)',
] }

View File

@@ -12,6 +12,8 @@
You can find a list of useful libraries and example projects at [`awesome-leptos`](https://github.com/leptos-rs/awesome-leptos).
# The `main` branch is currently undergoing major changes in preparation for the [0.7](https://github.com/leptos-rs/leptos/milestone/4) release. For a stable version, please use the [v0.6.13 tag](https://github.com/leptos-rs/leptos/tree/v0.6.13)
# Leptos
```rust

View File

@@ -1,6 +1,6 @@
[package]
name = "throw_error"
version = "0.2.0"
version = "0.2.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -1,6 +1,6 @@
[package]
name = "any_spawner"
version = "0.2.1"
version = "0.1.1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -16,8 +16,8 @@ thiserror = "2.0"
tokio = { version = "1.41", optional = true, default-features = false, features = [
"rt",
] }
tracing = { version = "0.1.41", optional = true }
wasm-bindgen-futures = { version = "0.4.47", optional = true }
tracing = { version = "0.1.40", optional = true }
wasm-bindgen-futures = { version = "0.4.45", optional = true }
[features]
async-executor = ["dep:async-executor"]

View File

@@ -1,6 +1,6 @@
[package]
name = "either_of"
version = "0.1.2"
version = "0.1.0"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -134,7 +134,7 @@ tuples!(EitherOf14 + EitherOf14Future + EitherOf14FutureProj => A, B, C, D, E, F
tuples!(EitherOf15 + EitherOf15Future + EitherOf15FutureProj => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
tuples!(EitherOf16 + EitherOf16Future + EitherOf16FutureProj => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
/// Matches over the first expression and returns an either ([`Either`], [`EitherOf3`], ... [`EitherOf8`])
/// Matches over the first expression and returns an either ([`Either`], [`EitherOf3`], ... [`EitherOf6`])
/// composed of the values returned by the match arms.
///
/// The pattern syntax is exactly the same as found in a match arm.
@@ -197,29 +197,6 @@ macro_rules! either {
$e_pattern => $crate::EitherOf6::E($e_expression),
$f_pattern => $crate::EitherOf6::F($f_expression),
}
};
($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr,) => {
match $match {
$a_pattern => $crate::EitherOf7::A($a_expression),
$b_pattern => $crate::EitherOf7::B($b_expression),
$c_pattern => $crate::EitherOf7::C($c_expression),
$d_pattern => $crate::EitherOf7::D($d_expression),
$e_pattern => $crate::EitherOf7::E($e_expression),
$f_pattern => $crate::EitherOf7::F($f_expression),
$g_pattern => $crate::EitherOf7::G($g_expression),
}
};
($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr,) => {
match $match {
$a_pattern => $crate::EitherOf8::A($a_expression),
$b_pattern => $crate::EitherOf8::B($b_expression),
$c_pattern => $crate::EitherOf8::C($c_expression),
$d_pattern => $crate::EitherOf8::D($d_expression),
$e_pattern => $crate::EitherOf8::E($e_expression),
$f_pattern => $crate::EitherOf8::F($f_expression),
$g_pattern => $crate::EitherOf8::G($g_expression),
$h_pattern => $crate::EitherOf8::H($h_expression),
}
}; // if you need more eithers feel free to open a PR ;-)
}
@@ -256,23 +233,4 @@ fn either_macro() {
16 => 24u8,
_ => 12,
);
let _: EitherOf7<&str, f64, char, f32, u8, i8, i32> = either!(12,
12 => "12",
13 => 0.0,
14 => ' ',
15 => 0.0f32,
16 => 24u8,
17 => 2i8,
_ => 12,
);
let _: EitherOf8<&str, f64, char, f32, u8, i8, u32, i32> = either!(12,
12 => "12",
13 => 0.0,
14 => ' ',
15 => 0.0f32,
16 => 24u8,
17 => 2i8,
18 => 42u32,
_ => 12,
);
}

View File

@@ -4,6 +4,25 @@ use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use server_fn::ServerFnError;
pub fn shell(leptos_options: &LeptosOptions) -> impl IntoView {
view! {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<AutoReload options=leptos_options.clone() />
<HydrationScripts options=leptos_options.clone()/>
<link rel="stylesheet" id="leptos" href="/pkg/todo_app_sqlite_csr.css"/>
<link rel="shortcut icon" type="image/ico" href="/favicon.ico"/>
</head>
<body>
<TodoApp/>
</body>
</html>
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "ssr", derive(sqlx::FromRow))]
pub struct Todo {

View File

@@ -1,6 +1,6 @@
[package]
name = "hydration_context"
version = "0.2.1"
version = "0.2.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -14,8 +14,8 @@ throw_error = { workspace = true }
or_poisoned = { workspace = true }
futures = "0.3.31"
serde = { version = "1.0", features = ["derive"] }
wasm-bindgen = { version = "0.2.97", optional = true }
js-sys = { version = "0.3.74", optional = true }
wasm-bindgen = { version = "0.2.95", optional = true }
js-sys = { version = "0.3.72", optional = true }
once_cell = "1.20"
pin-project-lite = "0.2.15"
@@ -25,6 +25,3 @@ browser = ["dep:wasm-bindgen", "dep:js-sys"]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -1,8 +1,3 @@
// #[wasm_bindgen(thread_local)] is deprecated in wasm-bindgen 0.2.96
// but the replacement is also only shipped in that version
// as a result, we'll just allow deprecated for now
#![allow(deprecated)]
use super::{SerializedDataId, SharedContext};
use crate::{PinnedFuture, PinnedStream};
use core::fmt::Debug;

View File

@@ -375,8 +375,8 @@ pub fn handle_server_fns_with_context(
.take(),
);
// if it accepts text/html (i.e., is a plain form post) and doesn't already have a
// Location set, then redirect to the Referer
// it it accepts text/html (i.e., is a plain form post) and doesn't already have a
// Location set, then redirect to to Referer
if accepts_html {
if let Some(referrer) = referrer {
let has_location =
@@ -390,20 +390,7 @@ pub fn handle_server_fns_with_context(
}
}
// the Location header may have been set to Referer, so any redirection by the
// user must overwrite it
{
let mut res_options = res_options.0.write();
let headers = res.0.headers_mut();
for location in
res_options.headers.remove(header::LOCATION)
{
headers.insert(header::LOCATION, location);
}
}
// apply status code and headers if user changed them
// apply status code and headers if used changed them
res.extend_response(&res_options);
res.0
})

View File

@@ -11,7 +11,7 @@ edition.workspace = true
[dependencies]
any_spawner = { workspace = true, features = ["tokio"] }
hydration_context = { workspace = true }
axum = { version = "0.7.9", default-features = false, features = [
axum = { version = "0.7.8", default-features = false, features = [
"matched-path",
] }
dashmap = "6"
@@ -26,11 +26,11 @@ once_cell = "1"
parking_lot = "0.12.3"
tokio = { version = "1.41", default-features = false }
tower = { version = "0.5.1", features = ["util"] }
tower-http = "0.6.2"
tracing = { version = "0.1.41", optional = true }
tower-http = "0.6.1"
tracing = { version = "0.1.40", optional = true }
[dev-dependencies]
axum = "0.7.9"
axum = "0.7.8"
tokio = { version = "1.41", features = ["net", "rt-multi-thread"] }
[features]

View File

@@ -399,8 +399,8 @@ async fn handle_server_fns_inner(
// actually run the server fn
let mut res = AxumResponse(service.run(req).await);
// if it accepts text/html (i.e., is a plain form post) and doesn't already have a
// Location set, then redirect to the Referer
// it it accepts text/html (i.e., is a plain form post) and doesn't already have a
// Location set, then redirect to to Referer
if accepts_html {
if let Some(referrer) = referrer {
let has_location =
@@ -412,7 +412,7 @@ async fn handle_server_fns_inner(
}
}
// apply status code and headers if user changed them
// apply status code and headers if used changed them
res.extend_response(&res_options);
Ok(res.0)
})

View File

@@ -40,28 +40,15 @@ pub trait ExtendResponse: Sized {
let (owner, stream) =
build_response(app_fn, additional_context, stream_builder);
let sc = owner.shared_context().unwrap();
let stream = stream.await.ready_chunks(32).map(|n| n.join(""));
let sc = owner.shared_context().unwrap();
while let Some(pending) = sc.await_deferred() {
pending.await;
}
let mut stream = Box::pin(
meta_context.inject_meta_context(stream).await.then({
let sc = Arc::clone(&sc);
move |chunk| {
let sc = Arc::clone(&sc);
async move {
while let Some(pending) = sc.await_deferred() {
pending.await;
}
chunk
}
}
}),
);
let mut stream =
Box::pin(meta_context.inject_meta_context(stream).await);
// wait for the first chunk of the stream, then set the status and headers
let first_chunk = stream.next().await.unwrap_or_default();

View File

@@ -30,7 +30,7 @@ reactive_graph = { workspace = true, features = ["serde"] }
rustc-hash = "2.0"
tachys = { workspace = true, features = ["reactive_graph", "reactive_stores", "oco"] }
thiserror = "2.0"
tracing = { version = "0.1.41", optional = true }
tracing = { version = "0.1.40", optional = true }
typed-builder = "0.20.0"
typed-builder-macro = "0.20.0"
serde = "1.0"
@@ -45,7 +45,7 @@ web-sys = { version = "0.3.72", features = [
"ShadowRootInit",
"ShadowRootMode",
] }
wasm-bindgen = "0.2.97"
wasm-bindgen = "0.2.95"
serde_qs = "0.13.0"
slotmap = "1.0"
futures = "0.3.31"
@@ -121,6 +121,3 @@ skip_feature_sets = [
[package.metadata.docs.rs]
rustdoc-args = ["--generate-link-to-definition"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -1,150 +0,0 @@
use crate::attr::{
any_attribute::{AnyAttribute, IntoAnyAttribute},
Attribute, NextAttribute,
};
use leptos::prelude::*;
/// Function stored to build/rebuild the wrapped children when attributes are added.
type ChildBuilder<T> = dyn Fn(AnyAttribute) -> T + Send + Sync + 'static;
/// Intercepts attributes passed to your component, allowing passing them to any element.
///
/// By default, Leptos passes any attributes passed to your component (e.g. `<MyComponent
/// attr:class="some-class"/>`) to the top-level element in the view returned by your component.
/// [`AttributeInterceptor`] allows you to intercept this behavior and pass it onto any element in
/// your component instead.
///
/// Must be the top level element in your component's view.
///
/// ## Example
///
/// Any attributes passed to MyComponent will be passed to the #inner element.
///
/// ```
/// # use leptos::prelude::*;
/// use leptos::attribute_interceptor::AttributeInterceptor;
///
/// #[component]
/// pub fn MyComponent() -> impl IntoView {
/// view! {
/// <AttributeInterceptor let:attrs>
/// <div id="wrapper">
/// <div id="inner" {..attrs} />
/// </div>
/// </AttributeInterceptor>
/// }
/// }
/// ```
#[component]
pub fn AttributeInterceptor<Chil, T>(
/// The elements that will be rendered, with the attributes this component received as a
/// parameter.
children: Chil,
) -> impl IntoView
where
Chil: Fn(AnyAttribute) -> T + Send + Sync + 'static,
T: IntoView,
{
AttributeInterceptorInner::new(children)
}
/// Wrapper to intercept attributes passed to a component so you can apply them to a different
/// element.
struct AttributeInterceptorInner<T: IntoView, A> {
children_builder: Box<ChildBuilder<T>>,
children: T,
attributes: A,
}
impl<T: IntoView> AttributeInterceptorInner<T, ()> {
/// Use this as the returned view from your component to collect the attributes that are passed
/// to your component so you can manually handle them.
pub fn new<F>(children: F) -> Self
where
F: Fn(AnyAttribute) -> T + Send + Sync + 'static,
{
let children_builder = Box::new(children);
let children = children_builder(().into_any_attr());
Self {
children_builder,
children,
attributes: (),
}
}
}
impl<T: IntoView, A: Attribute> Render for AttributeInterceptorInner<T, A> {
type State = <T as Render>::State;
fn build(self) -> Self::State {
self.children.build()
}
fn rebuild(self, state: &mut Self::State) {
self.children.rebuild(state);
}
}
impl<T: IntoView, A> AddAnyAttr for AttributeInterceptorInner<T, A>
where
A: Attribute,
{
type Output<SomeNewAttr: leptos::attr::Attribute> =
AttributeInterceptorInner<T, <<A as NextAttribute>::Output<SomeNewAttr> as Attribute>::CloneableOwned>;
fn add_any_attr<NewAttr: leptos::attr::Attribute>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml,
{
let attributes =
self.attributes.add_any_attr(attr).into_cloneable_owned();
let children =
(self.children_builder)(attributes.clone().into_any_attr());
AttributeInterceptorInner {
children_builder: self.children_builder,
children,
attributes,
}
}
}
impl<T: IntoView, A: Attribute> RenderHtml for AttributeInterceptorInner<T, A> {
type AsyncOutput = T::AsyncOutput;
const MIN_LENGTH: usize = T::MIN_LENGTH;
fn dry_resolve(&mut self) {
self.children.dry_resolve()
}
fn resolve(
self,
) -> impl std::future::Future<Output = Self::AsyncOutput> + Send {
self.children.resolve()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut leptos::tachys::view::Position,
escape: bool,
mark_branches: bool,
) {
self.children
.to_html_with_buf(buf, position, escape, mark_branches)
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &leptos::tachys::hydration::Cursor,
position: &leptos::tachys::view::PositionState,
) -> Self::State {
self.children.hydrate::<FROM_SERVER>(cursor, position)
}
}

View File

@@ -85,7 +85,7 @@ type BoxedChildrenFn = Box<dyn Fn() -> AnyView + Send>;
/// )
/// }
pub trait ToChildren<F> {
/// Convert the provided type (generally a closure) to Self (generally a "children" type,
/// Convert the provided type to (generally a closure) to Self (generally a "children" type,
/// e.g., [Children]). See the implementations to see exactly which input types are supported
/// and which "children" type they are converted to.
fn to_children(f: F) -> Self;
@@ -285,13 +285,6 @@ impl<T> Debug for TypedChildrenFn<T> {
}
}
impl<T> Clone for TypedChildrenFn<T> {
// Manual implementation to avoid the `T: Clone` bound.
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> TypedChildrenFn<T> {
/// Extracts the inner `children` function.
pub fn into_inner(self) -> Arc<dyn Fn() -> View<T> + Send + Sync> {

View File

@@ -44,67 +44,6 @@ use tachys::{reactive_graph::OwnedView, view::keyed::keyed};
/// }
/// }
/// ```
///
/// For convenience, you can also choose to write template code directly in the `<For>`
/// component, using the `let` syntax:
///
/// ```
/// # use leptos::prelude::*;
///
/// # #[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// # struct Counter {
/// # id: usize,
/// # count: RwSignal<i32>
/// # }
/// #
/// # #[component]
/// # fn Counters() -> impl IntoView {
/// # let (counters, set_counters) = create_signal::<Vec<Counter>>(vec![]);
/// #
/// view! {
/// <div>
/// <For
/// each=move || counters.get()
/// key=|counter| counter.id
/// let(counter)
/// >
/// <button>"Value: " {move || counter.count.get()}</button>
/// </For>
/// </div>
/// }
/// # }
/// ```
///
/// The `let` syntax also supports destructuring the pattern of your data.
/// `let((one, two))` in the case of tuples, and `let(Struct { field_one, field_two })`
/// in the case of structs.
///
/// ```
/// # use leptos::prelude::*;
///
/// # #[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// # struct Counter {
/// # id: usize,
/// # count: RwSignal<i32>
/// # }
/// #
/// # #[component]
/// # fn Counters() -> impl IntoView {
/// # let (counters, set_counters) = create_signal::<Vec<Counter>>(vec![]);
/// #
/// view! {
/// <div>
/// <For
/// each=move || counters.get()
/// key=|counter| counter.id
/// let(Counter { id, count })
/// >
/// <button>"Value: " {move || count.get()}</button>
/// </For>
/// </div>
/// }
/// # }
/// ```
#[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
#[component]
pub fn For<IF, I, T, EF, N, KF, K>(

View File

@@ -192,9 +192,6 @@ pub mod callback;
/// Types that can be passed as the `children` prop of a component.
pub mod children;
/// Wrapper for intercepting component attributes.
pub mod attribute_interceptor;
#[doc(hidden)]
/// Traits used to implement component constructors.
pub mod component;
@@ -293,7 +290,7 @@ pub mod logging {
/// Utilities for working with asynchronous tasks.
pub mod task {
pub use any_spawner::{self, CustomExecutor, Executor};
pub use any_spawner::Executor;
use std::future::Future;
/// Spawns a thread-safe [`Future`].

View File

@@ -1535,7 +1535,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
@@ -1851,7 +1851,7 @@ dependencies = [
[[package]]
name = "quote-use"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58e9a38ef862d7fec635661503289062bc5b3035e61859a8de3d3f81823accd2"
dependencies = [
@@ -1953,7 +1953,7 @@ dependencies = [
[[package]]
name = "ron"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a"
dependencies = [
@@ -2104,7 +2104,7 @@ dependencies = [
[[package]]
name = "serde_urlencoded"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [

View File

@@ -26,6 +26,3 @@ temp-env = { version = "0.3.6", features = ["async_closure"] }
[package.metadata.docs.rs]
rustdoc-args = ["--generate-link-to-definition"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -12,10 +12,10 @@ edition.workspace = true
tachys = { workspace = true }
reactive_graph = { workspace = true }
or_poisoned = { workspace = true }
js-sys = "0.3.74"
js-sys = "0.3.72"
send_wrapper = "0.6.0"
tracing = { version = "0.1.41", optional = true }
wasm-bindgen = "0.2.97"
tracing = { version = "0.1.40", optional = true }
wasm-bindgen = "0.2.95"
serde_json = { version = "1.0", optional = true }
serde = { version = "1.0", optional = true }
@@ -37,6 +37,3 @@ rustdoc-args = ["--generate-link-to-definition"]
[package.metadata.cargo-all-features]
denylist = ["tracing"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_macro"
version = "0.7.2"
version = "0.7.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
repository = "https://github.com/leptos-rs/leptos"
@@ -13,7 +13,7 @@ edition.workspace = true
proc-macro = true
[dependencies]
attribute-derive = { version = "0.10.3", features = ["syn-full"] }
attribute-derive = { version = "0.10.2", features = ["syn-full"] }
cfg-if = "1.0"
html-escape = "0.2.13"
itertools = "0.13.0"
@@ -27,7 +27,7 @@ leptos_hot_reload = { workspace = true }
server_fn_macro = { workspace = true }
convert_case = "0.6.0"
uuid = { version = "1.11", features = ["v4"] }
tracing = { version = "0.1.41", optional = true }
tracing = { version = "0.1.40", optional = true }
[dev-dependencies]
log = "0.4.22"
@@ -83,7 +83,4 @@ skip_feature_sets = [
rustdoc-args = ["--generate-link-to-definition"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(leptos_debuginfo)',
'cfg(erase_components)',
] }
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(erase_components)'] }

View File

@@ -639,7 +639,7 @@ pub fn island(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
abort!(
transparent,
"only `transparent` is supported";
help = "try `#[island(transparent)]` or `#[island]`"
help = "try `#[component(transparent)]` or `#[component]`"
);
}

View File

@@ -108,12 +108,9 @@ pub(crate) fn component_to_tokens(
let KeyedAttributeValue::Binding(binding) = &attr.possible_value
else {
if let Some(ident) = attr.key.to_string().strip_prefix("let:") {
let span = match &attr.key {
NodeName::Punctuated(path) => path[1].span(),
_ => unreachable!(),
};
let ident1 = format_ident!("{ident}", span = span);
return Some(quote_spanned! { span => #ident1 });
let ident1 =
format_ident!("{ident}", span = attr.key.span());
return Some(quote! { #ident1 });
} else {
return None;
}

View File

@@ -652,18 +652,6 @@ pub(crate) fn element_to_tokens(
},
_ => None,
};
if let NodeAttribute::Attribute(a) = a {
if let Some(Tuple(_)) = a.value() {
return Ordering::Greater;
}
}
if let NodeAttribute::Attribute(b) = b {
if let Some(Tuple(_)) = b.value() {
return Ordering::Less;
}
}
match (key_a.as_deref(), key_b.as_deref()) {
(Some("class"), Some("class")) | (Some("style"), Some("style")) => {
Ordering::Equal
@@ -767,7 +755,7 @@ pub(crate) fn element_to_tokens(
let name = node.name().to_string();
// link custom ident to name span for IDE docs
let custom = Ident::new("custom", name.span());
quote_spanned! { node.name().span() => ::leptos::tachys::html::element::#custom(#name) }
quote! { ::leptos::tachys::html::element::#custom(#name) }
} else if is_svg_element(&tag) {
parent_type = TagType::Svg;
let name = if tag == "use" || tag == "use_" {
@@ -775,33 +763,33 @@ pub(crate) fn element_to_tokens(
} else {
name.to_token_stream()
};
quote_spanned! { node.name().span() => ::leptos::tachys::svg::#name() }
quote! { ::leptos::tachys::svg::#name() }
} else if is_math_ml_element(&tag) {
parent_type = TagType::Math;
quote_spanned! { node.name().span() => ::leptos::tachys::mathml::#name() }
quote! { ::leptos::tachys::mathml::#name() }
} else if is_ambiguous_element(&tag) {
match parent_type {
TagType::Unknown => {
// We decided this warning was too aggressive, but I'll leave it here in case we want it later
/* proc_macro_error2::emit_warning!(name.span(), "The view macro is assuming this is an HTML element, \
but it is ambiguous; if it is an SVG or MathML element, prefix with svg:: or math::"); */
quote_spanned! { node.name().span() =>
quote! {
::leptos::tachys::html::element::#name()
}
}
TagType::Html => {
quote_spanned! { node.name().span() => ::leptos::tachys::html::element::#name() }
quote! { ::leptos::tachys::html::element::#name() }
}
TagType::Svg => {
quote_spanned! { node.name().span() => ::leptos::tachys::svg::#name() }
quote! { ::leptos::tachys::svg::#name() }
}
TagType::Math => {
quote_spanned! { node.name().span() => ::leptos::tachys::math::#name() }
quote! { ::leptos::tachys::math::#name() }
}
}
} else {
parent_type = TagType::Html;
quote_spanned! { name.span() => ::leptos::tachys::html::element::#name() }
quote! { ::leptos::tachys::html::element::#name() }
};
/* TODO restore this
@@ -1722,7 +1710,7 @@ fn tuple_name(name: &str, node: &KeyedAttribute) -> TupleName {
TupleName::None
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug)]
enum TupleName {
None,
Str(String),

View File

@@ -15,7 +15,7 @@ codee = { version = "0.2.0", features = ["json_serde"] }
hydration_context = { workspace = true }
reactive_graph = { workspace = true, features = ["hydration"] }
server_fn = { workspace = true }
tracing = { version = "0.1.41", optional = true }
tracing = { version = "0.1.40", optional = true }
futures = "0.3.31"
any_spawner = { workspace = true }
@@ -25,8 +25,8 @@ send_wrapper = "0.6"
# serialization formats
serde = { version = "1.0" }
js-sys = { version = "0.3.74", optional = true }
wasm-bindgen = { version = "0.2.97", optional = true }
js-sys = { version = "0.3.72", optional = true }
wasm-bindgen = { version = "0.2.95", optional = true }
serde_json = { version = "1.0" }
[features]
@@ -44,6 +44,3 @@ denylist = ["tracing"]
[package.metadata.docs.rs]
rustdoc-args = ["--generate-link-to-definition"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -43,7 +43,7 @@ where
S::Output: 'static,
{
inner: ArcAction<S, Result<S::Output, ServerFnError<S::Error>>>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -65,7 +65,7 @@ where
inner: ArcAction::new_with_value(err, |input: &S| {
S::run_on_client(input.clone())
}),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -91,7 +91,7 @@ where
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
@@ -114,11 +114,11 @@ where
S::Output: 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -132,7 +132,7 @@ where
S::Output: 'static,
{
inner: Action<S, Result<S::Output, ServerFnError<S::Error>>>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -153,7 +153,7 @@ where
inner: Action::new_with_value(err, |input: &S| {
S::run_on_client(input.clone())
}),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -217,11 +217,11 @@ where
S::Output: 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -20,7 +20,7 @@ use std::{
/// A reference-counted resource that only loads its data locally on the client.
pub struct ArcLocalResource<T> {
data: ArcAsyncDerived<SendWrapper<T>>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -28,7 +28,7 @@ impl<T> Clone for ArcLocalResource<T> {
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
@@ -70,7 +70,7 @@ impl<T> ArcLocalResource<T> {
let fut = fetcher();
SendWrapper::new(async move { SendWrapper::new(fut.await) })
}),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -104,11 +104,11 @@ where
impl<T> DefinedAt for ArcLocalResource<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -200,7 +200,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(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -253,7 +253,7 @@ impl<T> LocalResource<T> {
SendWrapper::new(async move { SendWrapper::new(fut.await) })
})
},
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -287,11 +287,11 @@ where
impl<T> DefinedAt for LocalResource<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -398,7 +398,7 @@ impl<T: 'static> From<ArcLocalResource<T>> for LocalResource<T> {
fn from(arc: ArcLocalResource<T>) -> Self {
Self {
data: arc.data.into(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: arc.defined_at,
}
}
@@ -408,7 +408,7 @@ impl<T: 'static> From<LocalResource<T>> for ArcLocalResource<T> {
fn from(local: LocalResource<T>) -> Self {
Self {
data: local.data.into(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: local.defined_at,
}
}

View File

@@ -12,7 +12,7 @@ where
S::Output: 'static,
{
inner: ArcMultiAction<S, Result<S::Output, ServerFnError<S::Error>>>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -29,7 +29,7 @@ where
inner: ArcMultiAction::new(|input: &S| {
S::run_on_client(input.clone())
}),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -55,7 +55,7 @@ where
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
@@ -78,11 +78,11 @@ where
S::Output: 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -96,7 +96,7 @@ where
S::Output: 'static,
{
inner: MultiAction<S, Result<S::Output, ServerFnError<S::Error>>>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -123,7 +123,7 @@ where
inner: MultiAction::new(|input: &S| {
S::run_on_client(input.clone())
}),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -176,11 +176,11 @@ where
S::Output: 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -60,7 +60,7 @@ pub struct ArcOnceResource<T, Ser = JsonSerdeCodec> {
suspenses: Arc<RwLock<Vec<SuspenseContext>>>,
loading: Arc<AtomicBool>,
ser: PhantomData<fn() -> Ser>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -73,7 +73,7 @@ impl<T, Ser> Clone for ArcOnceResource<T, Ser> {
suspenses: self.suspenses.clone(),
loading: self.loading.clone(),
ser: self.ser,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
@@ -140,7 +140,7 @@ where
wakers,
suspenses,
ser: PhantomData,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
};
@@ -183,11 +183,11 @@ impl<T, Ser> ArcOnceResource<T, Ser> {
impl<T, Ser> DefinedAt for ArcOnceResource<T, Ser> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
@@ -272,7 +272,7 @@ where
#[track_caller]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let _guard = SpecialNonReactiveZone::enter();
let waker = cx.waker();
self.source.track();
@@ -491,7 +491,7 @@ where
#[derive(Debug)]
pub struct OnceResource<T, Ser = JsonSerdeCodec> {
inner: ArenaItem<ArcOnceResource<T, Ser>>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -524,13 +524,13 @@ where
fut: impl Future<Output = T> + Send + 'static,
blocking: bool,
) -> Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let defined_at = Location::caller();
Self {
inner: ArenaItem::new(ArcOnceResource::new_with_options(
fut, blocking,
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at,
}
}
@@ -551,11 +551,11 @@ where
impl<T, Ser> DefinedAt for OnceResource<T, Ser> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}

View File

@@ -74,7 +74,7 @@ pub struct ArcResource<T, Ser = JsonSerdeCodec> {
ser: PhantomData<Ser>,
refetch: ArcRwSignal<usize>,
data: ArcAsyncDerived<T>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -82,7 +82,7 @@ impl<T, Ser> Debug for ArcResource<T, Ser> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut d = f.debug_struct("ArcResource");
d.field("ser", &self.ser).field("data", &self.data);
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
d.field("defined_at", self.defined_at);
d.finish_non_exhaustive()
}
@@ -98,7 +98,7 @@ where
ser: PhantomData,
data: arc_resource.data.into(),
refetch: arc_resource.refetch.into(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -114,7 +114,7 @@ where
ser: PhantomData,
data: resource.data.into(),
refetch: resource.refetch.into(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -122,11 +122,11 @@ where
impl<T, Ser> DefinedAt for ArcResource<T, Ser> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -139,7 +139,7 @@ impl<T, Ser> Clone for ArcResource<T, Ser> {
ser: self.ser,
refetch: self.refetch.clone(),
data: self.data.clone(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
@@ -300,7 +300,7 @@ where
ser: PhantomData,
data,
refetch,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -781,7 +781,7 @@ where
ser: PhantomData<Ser>,
data: AsyncDerived<T>,
refetch: RwSignal<usize>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -792,7 +792,7 @@ where
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut d = f.debug_struct("ArcResource");
d.field("ser", &self.ser).field("data", &self.data);
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
d.field("defined_at", self.defined_at);
d.finish_non_exhaustive()
}
@@ -803,11 +803,11 @@ where
T: Send + Sync + 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -1270,7 +1270,7 @@ where
ser: PhantomData,
data: data.into(),
refetch: refetch.into(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_meta"
version = "0.7.2"
version = "0.7.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
repository = "https://github.com/leptos-rs/leptos"
@@ -14,8 +14,8 @@ once_cell = "1.20"
or_poisoned = { workspace = true }
indexmap = "2.6"
send_wrapper = "0.6.0"
tracing = { version = "0.1.41", optional = true }
wasm-bindgen = "0.2.97"
tracing = { version = "0.1.40", optional = true }
wasm-bindgen = "0.2.95"
futures = "0.3.31"
[dependencies.web-sys]
@@ -32,6 +32,3 @@ rustdoc-args = ["--generate-link-to-definition"]
[package.metadata.cargo-all-features]
denylist = ["tracing"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -37,10 +37,14 @@
//! }
//! ```
//! # Feature Flags
//! - `csr` Client-side rendering: Generate DOM nodes in the browser
//! - `ssr` Server-side rendering: Generate an HTML string (typically on the server)
//! - `tracing` Adds integration with the `tracing` crate.
//! - `hydrate` Hydration: use this to add interactivity to an SSRed Leptos app
//! - `stable` By default, Leptos requires `nightly` Rust, which is what allows the ergonomics
//! of calling signals as functions. Enable this feature to support `stable` Rust.
//!
//! **Important Note:** If youre using server-side rendering, you should enable `ssr`.
//! **Important Note:** You must enable one of `csr`, `hydrate`, or `ssr` to tell Leptos
//! which mode your app is operating in.
use futures::{Stream, StreamExt};
use leptos::{

View File

@@ -1,6 +1,6 @@
[package]
name = "next_tuple"
version = "0.1.0"
version = "0.1.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -1,6 +1,6 @@
[package]
name = "reactive_graph"
version = "0.1.1"
version = "0.1.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -19,7 +19,7 @@ rustc-hash = "2.0"
serde = { version = "1.0", features = ["derive"], optional = true }
slotmap = "1.0"
thiserror = "2.0"
tracing = { version = "0.1.41", optional = true }
tracing = { version = "0.1.40", optional = true }
guardian = "1.2"
async-lock = "3.4.0"
send_wrapper = { version = "0.6.0", features = ["futures"] }
@@ -47,6 +47,3 @@ rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-all-features]
denylist = ["tracing"]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -101,7 +101,7 @@ pub struct ArcAction<I, O> {
action_fn: Arc<
dyn Fn(&I) -> Pin<Box<dyn Future<Output = O> + Send>> + Send + Sync,
>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -114,7 +114,7 @@ impl<I, O> Clone for ArcAction<I, O> {
version: self.version.clone(),
dispatched: self.dispatched.clone(),
action_fn: self.action_fn.clone(),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
}
}
@@ -198,7 +198,7 @@ where
version: Default::default(),
dispatched: Default::default(),
action_fn: Arc::new(move |input| Box::pin(action_fn(input))),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -370,7 +370,7 @@ where
action_fn: Arc::new(move |input| {
Box::pin(SendWrapper::new(action_fn(input)))
}),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -502,11 +502,11 @@ where
O: 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -592,7 +592,7 @@ where
/// ```
pub struct Action<I, O, S = SyncStorage> {
inner: ArenaItem<ArcAction<I, O>, S>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -656,7 +656,7 @@ where
{
Self {
inner: ArenaItem::new(ArcAction::new(action_fn)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -681,7 +681,7 @@ where
{
Self {
inner: ArenaItem::new(ArcAction::new_with_value(value, action_fn)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -715,11 +715,11 @@ where
pub fn new_local<F, Fu>(action_fn: F) -> Self
where
F: Fn(&I) -> Fu + 'static,
Fu: Future<Output = O> + 'static,
Fu: Future<Output = O> + Send + 'static,
{
Self {
inner: ArenaItem::new_local(ArcAction::new_unsync(action_fn)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -737,7 +737,7 @@ where
inner: ArenaItem::new_local(ArcAction::new_unsync_with_value(
value, action_fn,
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -979,7 +979,7 @@ where
inner: ArenaItem::new_with_storage(ArcAction::new_unsync(
action_fn,
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -998,7 +998,7 @@ where
inner: ArenaItem::new_with_storage(
ArcAction::new_unsync_with_value(value, action_fn),
),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -1006,11 +1006,11 @@ where
impl<I, O, S> DefinedAt for Action<I, O, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -46,7 +46,7 @@ use std::{fmt::Debug, future::Future, panic::Location, pin::Pin, sync::Arc};
/// ```
pub struct MultiAction<I, O, S = SyncStorage> {
inner: ArenaItem<ArcMultiAction<I, O>, S>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -62,11 +62,11 @@ where
O: 'static,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -130,7 +130,7 @@ where
{
Self {
inner: ArenaItem::new_with_storage(ArcMultiAction::new(action_fn)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}

View File

@@ -93,7 +93,7 @@ pub struct ArcMemo<T, S = SyncStorage>
where
S: Storage<T>,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: Arc<RwLock<MemoInner<T, S>>>,
}
@@ -164,7 +164,7 @@ where
RwLock::new(MemoInner::new(Arc::new(fun), subscriber))
});
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner,
}
@@ -177,7 +177,7 @@ where
{
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
inner: Arc::clone(&self.inner),
}
@@ -190,11 +190,11 @@ where
{
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -272,7 +272,7 @@ where
AnySource(
Arc::as_ptr(&self.inner) as usize,
Arc::downgrade(&self.inner) as Weak<dyn Source + Send + Sync>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
self.defined_at,
)
}

View File

@@ -107,7 +107,7 @@ use std::{
/// - [`IntoFuture`](std::future::Future) allows you to create a [`Future`] that resolves
/// when this resource is done loading.
pub struct ArcAsyncDerived<T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
// the current state of this signal
pub(crate) value: Arc<AsyncRwLock<Option<T>>>,
@@ -117,7 +117,6 @@ pub struct ArcAsyncDerived<T> {
pub(crate) loading: Arc<AtomicBool>,
}
#[allow(dead_code)]
pub(crate) trait BlockingLock<T> {
fn blocking_read_arc(self: &Arc<Self>)
-> async_lock::RwLockReadGuardArc<T>;
@@ -184,7 +183,7 @@ impl<T> BlockingLock<T> for AsyncRwLock<T> {
impl<T> Clone for ArcAsyncDerived<T> {
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
value: Arc::clone(&self.value),
wakers: Arc::clone(&self.wakers),
@@ -197,7 +196,7 @@ impl<T> Clone for ArcAsyncDerived<T> {
impl<T> Debug for ArcAsyncDerived<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_struct("ArcAsyncDerived");
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
f.field("defined_at", &self.defined_at);
f.finish_non_exhaustive()
}
@@ -206,11 +205,11 @@ impl<T> Debug for ArcAsyncDerived<T> {
impl<T> DefinedAt for ArcAsyncDerived<T> {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -241,7 +240,7 @@ macro_rules! spawn_derived {
let wakers = Arc::new(RwLock::new(Vec::new()));
let this = ArcAsyncDerived {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::clone(&value),
wakers,
@@ -584,17 +583,19 @@ impl<T: 'static> ReadUntracked for ArcAsyncDerived<T> {
fn try_read_untracked(&self) -> Option<Self::Value> {
if let Some(suspense_context) = use_context::<SuspenseContext>() {
let handle = suspense_context.task_id();
let ready = SpecialNonReactiveFuture::new(self.ready());
crate::spawn(async move {
ready.await;
drop(handle);
});
self.inner
.write()
.or_poisoned()
.suspenses
.push(suspense_context);
if self.value.blocking_read().is_none() {
let handle = suspense_context.task_id();
let ready = SpecialNonReactiveFuture::new(self.ready());
crate::spawn(async move {
ready.await;
drop(handle);
});
self.inner
.write()
.or_poisoned()
.suspenses
.push(suspense_context);
}
}
AsyncPlain::try_new(&self.value).map(ReadGuard::new)
}
@@ -632,7 +633,7 @@ impl<T: 'static> ToAnySource for ArcAsyncDerived<T> {
AnySource(
Arc::as_ptr(&self.inner) as usize,
Arc::downgrade(&self.inner) as Weak<dyn Source + Send + Sync>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
self.defined_at,
)
}

View File

@@ -83,7 +83,7 @@ use std::{future::Future, ops::DerefMut, panic::Location};
/// - [`IntoFuture`](std::future::Future) allows you to create a [`Future`] that resolves
/// when this resource is done loading.
pub struct AsyncDerived<T, S = SyncStorage> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
pub(crate) inner: ArenaItem<ArcAsyncDerived<T>, S>,
}
@@ -99,10 +99,10 @@ where
T: Send + Sync + 'static,
{
fn from(value: ArcAsyncDerived<T>) -> Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let defined_at = value.defined_at;
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at,
inner: ArenaItem::new_with_storage(value),
}
@@ -127,10 +127,10 @@ where
T: 'static,
{
fn from_local(value: ArcAsyncDerived<T>) -> Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let defined_at = value.defined_at;
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at,
inner: ArenaItem::new_with_storage(value),
}
@@ -152,7 +152,7 @@ where
Fut: Future<Output = T> + Send + 'static,
{
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcAsyncDerived::new(fun)),
}
@@ -170,7 +170,7 @@ where
Fut: Future<Output = T> + Send + 'static,
{
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(
ArcAsyncDerived::new_with_initial(initial_value, fun),
@@ -187,7 +187,7 @@ impl<T> AsyncDerived<SendWrapper<T>> {
Fut: Future<Output = T> + 'static,
{
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcAsyncDerived::new_mock(fun)),
}
@@ -209,7 +209,7 @@ where
Fut: Future<Output = T> + 'static,
{
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcAsyncDerived::new_unsync(
fun,
@@ -230,7 +230,7 @@ where
Fut: Future<Output = T> + 'static,
{
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(
ArcAsyncDerived::new_unsync_with_initial(initial_value, fun),
@@ -278,11 +278,11 @@ where
impl<T, S> DefinedAt for AsyncDerived<T, S> {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -67,9 +67,7 @@ where
fn mark_check(&self) {
{
let mut lock = self.write().or_poisoned();
if lock.state != ReactiveNodeState::Dirty {
lock.state = ReactiveNodeState::Check;
}
lock.state = ReactiveNodeState::Check;
}
for sub in (&self.read().or_poisoned().subscribers).into_iter() {
sub.mark_check();

View File

@@ -100,7 +100,7 @@ pub struct Memo<T, S = SyncStorage>
where
S: Storage<T>,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: ArenaItem<ArcMemo<T, S>, S>,
}
@@ -121,7 +121,7 @@ where
#[track_caller]
fn from(value: ArcMemo<T, SyncStorage>) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
@@ -135,7 +135,7 @@ where
#[track_caller]
fn from_local(value: ArcMemo<T, LocalStorage>) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
@@ -175,7 +175,7 @@ where
T: PartialEq,
{
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcMemo::new(fun)),
}
@@ -197,7 +197,7 @@ where
changed: fn(Option<&T>, Option<&T>) -> bool,
) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcMemo::new_with_compare(
fun, changed,
@@ -207,7 +207,7 @@ where
/// Creates a new memo by passing a function that computes the value.
///
/// Unlike [`Memo::new`](), this receives ownership of the previous value. As a result, it
/// Unlike [`ArcMemo::new`](), this receives ownership of the previous value. As a result, it
/// must return both the new value and a `bool` that is `true` if the value has changed.
///
/// This is lazy: the function will not be called until the memo's value is read for the first
@@ -221,7 +221,7 @@ where
fun: impl Fn(Option<T>) -> (T, bool) + Send + Sync + 'static,
) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcMemo::new_owning(fun)),
}
@@ -276,11 +276,11 @@ where
S: Storage<T>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -59,7 +59,7 @@ impl<'a> IntoIterator for &'a SourceSet {
self.0.iter()
}
}
#[derive(Debug, Default, Clone)]
#[derive(Default, Clone)]
pub struct SubscriberSet(Vec<AnySubscriber>);
impl SubscriberSet {

View File

@@ -26,17 +26,16 @@ pub trait Source: ReactiveNode {
pub struct AnySource(
pub(crate) usize,
pub(crate) Weak<dyn Source + Send + Sync>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
pub(crate) &'static Location<'static>,
#[cfg(debug_assertions)] pub(crate) &'static Location<'static>,
);
impl DefinedAt for AnySource {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.2)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -1,6 +1,6 @@
use crate::{
signal::guards::{Plain, ReadGuard, UntrackedWriteGuard},
traits::{DefinedAt, IntoInner, IsDisposed, ReadValue, WriteValue},
traits::{DefinedAt, IsDisposed, ReadValue, WriteValue},
};
use std::{
fmt::{Debug, Formatter},
@@ -19,7 +19,7 @@ use std::{
/// accessing it does not cause effects to subscribe, and
/// updating it does not notify anything else.
pub struct ArcStoredValue<T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
value: Arc<RwLock<T>>,
}
@@ -27,7 +27,7 @@ pub struct ArcStoredValue<T> {
impl<T> Clone for ArcStoredValue<T> {
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
value: Arc::clone(&self.value),
}
@@ -47,7 +47,7 @@ impl<T: Default> Default for ArcStoredValue<T> {
#[track_caller]
fn default() -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::new(RwLock::new(T::default())),
}
@@ -70,11 +70,11 @@ impl<T> Hash for ArcStoredValue<T> {
impl<T> DefinedAt for ArcStoredValue<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -90,7 +90,7 @@ impl<T> ArcStoredValue<T> {
#[track_caller]
pub fn new(value: T) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::new(RwLock::new(value)),
}
@@ -124,12 +124,3 @@ impl<T> IsDisposed for ArcStoredValue<T> {
false
}
}
impl<T> IntoInner for ArcStoredValue<T> {
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
Some(Arc::into_inner(self.value)?.into_inner().unwrap())
}
}

View File

@@ -121,11 +121,8 @@ pub mod sandboxed {
}
impl<T> Sandboxed<T> {
/// Wraps the given [`Future`], ensuring that any [`ArenaItem`][item] created while it is
/// being polled will be associated with the same arena that was active when this was
/// called.
///
/// [item]:[crate::owner::ArenaItem]
/// Wraps the given [`Future`], ensuring that any [`ArenaItem`] created while it is being
/// polled will be associated with the same arena that was active when this was called.
pub fn new(inner: T) -> Self {
let arena = MAP.with_borrow(|n| n.as_ref().and_then(Weak::upgrade));
Self { arena, inner }

View File

@@ -2,7 +2,7 @@ use super::{
arena::{Arena, NodeId},
LocalStorage, Storage, SyncStorage, OWNER,
};
use crate::traits::{Dispose, IntoInner, IsDisposed};
use crate::traits::{Dispose, IsDisposed};
use send_wrapper::SendWrapper;
use std::{any::Any, hash::Hash, marker::PhantomData};
@@ -134,12 +134,3 @@ impl<T, S> Dispose for ArenaItem<T, S> {
Arena::with_mut(|arena| arena.remove(self.node));
}
}
impl<T, S: Storage<T>> IntoInner for ArenaItem<T, S> {
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
S::take(self.node)
}
}

View File

@@ -15,14 +15,35 @@ impl Owner {
}
fn use_context<T: Clone + 'static>(&self) -> Option<T> {
self.with_context(Clone::clone)
let ty = TypeId::of::<T>();
let inner = self.inner.read().or_poisoned();
let mut parent = inner.parent.as_ref().and_then(|p| p.upgrade());
let contexts = &self.inner.read().or_poisoned().contexts;
if let Some(context) = contexts.get(&ty) {
context.downcast_ref::<T>().cloned()
} else {
while let Some(ref this_parent) = parent.clone() {
let this_parent = this_parent.read().or_poisoned();
let contexts = &this_parent.contexts;
let value = contexts.get(&ty);
let downcast = value
.and_then(|context| context.downcast_ref::<T>().cloned());
if let Some(value) = downcast {
return Some(value);
} else {
parent =
this_parent.parent.as_ref().and_then(|p| p.upgrade());
}
}
None
}
}
fn take_context<T: 'static>(&self) -> Option<T> {
let ty = TypeId::of::<T>();
let mut inner = self.inner.write().or_poisoned();
let inner = self.inner.read().or_poisoned();
let mut parent = inner.parent.as_ref().and_then(|p| p.upgrade());
let contexts = &mut inner.contexts;
let contexts = &mut self.inner.write().or_poisoned().contexts;
if let Some(context) = contexts.remove(&ty) {
context.downcast::<T>().ok().map(|n| *n)
} else {
@@ -43,64 +64,6 @@ impl Owner {
}
}
fn with_context<T: 'static, R>(
&self,
cb: impl FnOnce(&T) -> R,
) -> Option<R> {
let ty = TypeId::of::<T>();
let inner = self.inner.read().or_poisoned();
let mut parent = inner.parent.as_ref().and_then(|p| p.upgrade());
let contexts = &inner.contexts;
let reference = if let Some(context) = contexts.get(&ty) {
context.downcast_ref::<T>()
} else {
while let Some(ref this_parent) = parent.clone() {
let this_parent = this_parent.read().or_poisoned();
let contexts = &this_parent.contexts;
let value = contexts.get(&ty);
let downcast =
value.and_then(|context| context.downcast_ref::<T>());
if let Some(value) = downcast {
return Some(cb(value));
} else {
parent =
this_parent.parent.as_ref().and_then(|p| p.upgrade());
}
}
None
};
reference.map(cb)
}
fn update_context<T: 'static, R>(
&self,
cb: impl FnOnce(&mut T) -> R,
) -> Option<R> {
let ty = TypeId::of::<T>();
let mut inner = self.inner.write().or_poisoned();
let mut parent = inner.parent.as_ref().and_then(|p| p.upgrade());
let contexts = &mut inner.contexts;
let reference = if let Some(context) = contexts.get_mut(&ty) {
context.downcast_mut::<T>()
} else {
while let Some(ref this_parent) = parent.clone() {
let mut this_parent = this_parent.write().or_poisoned();
let contexts = &mut this_parent.contexts;
let value = contexts.get_mut(&ty);
let downcast =
value.and_then(|context| context.downcast_mut::<T>());
if let Some(value) = downcast {
return Some(cb(value));
} else {
parent =
this_parent.parent.as_ref().and_then(|p| p.upgrade());
}
}
None
};
reference.map(cb)
}
/// Searches for items stored in context in either direction, either among parents or among
/// descendants.
pub fn use_context_bidirectional<T: Clone + 'static>(&self) -> Option<T> {
@@ -356,86 +319,3 @@ pub fn expect_context<T: Clone + 'static>() -> T {
pub fn take_context<T: 'static>() -> Option<T> {
Owner::current().and_then(|owner| owner.take_context())
}
/// Access a reference to a context value of type `T` in the reactive system.
///
/// This traverses the reactive ownership graph, beginning from the current reactive
/// [`Owner`] and iterating through its parents, if any. When the value is found,
/// the function that you pass is applied to an immutable reference to it.
///
/// The context value should have been provided elsewhere using
/// [`provide_context`](provide_context).
///
/// This is useful for passing values down to components or functions lower in a
/// hierarchy without needs to “prop drill” by passing them through each layer as
/// arguments to a function or properties of a component.
///
/// Context works similarly to variable scope: a context that is provided higher in
/// the reactive graph can be used lower down, but a context that is provided lower
/// in the tree cannot be used higher up.
///
/// ```rust
/// # use reactive_graph::prelude::*;
/// # use reactive_graph::owner::*;
/// # let owner = Owner::new(); owner.set();
/// # use reactive_graph::effect::Effect;
/// # futures::executor::block_on(async move {
/// # any_spawner::Executor::init_futures_executor();
/// Effect::new(move |_| {
/// provide_context(String::from("foo"));
///
/// Effect::new(move |_| {
/// let value = with_context::<String, _>(|val| val.to_string())
/// .expect("could not find String in context");
/// assert_eq!(value, "foo");
/// });
/// });
/// # });
/// ```
pub fn with_context<T: 'static, R>(cb: impl FnOnce(&T) -> R) -> Option<R> {
Owner::current().and_then(|owner| owner.with_context(cb))
}
/// Update a context value of type `T` in the reactive system.
///
/// This traverses the reactive ownership graph, beginning from the current reactive
/// [`Owner`] and iterating through its parents, if any. When the value is found,
/// the function that you pass is applied to a mutable reference to it.
///
/// The context value should have been provided elsewhere using
/// [`provide_context`](provide_context).
///
/// This is useful for passing values down to components or functions lower in a
/// hierarchy without needs to “prop drill” by passing them through each layer as
/// arguments to a function or properties of a component.
///
/// Context works similarly to variable scope: a context that is provided higher in
/// the reactive graph can be used lower down, but a context that is provided lower
/// in the tree cannot be used higher up.
///
/// ```rust
/// # use reactive_graph::prelude::*;
/// # use reactive_graph::owner::*;
/// # let owner = Owner::new(); owner.set();
/// # use reactive_graph::effect::Effect;
/// # futures::executor::block_on(async move {
/// # any_spawner::Executor::init_futures_executor();
/// Effect::new(move |_| {
/// provide_context(String::from("foo"));
///
/// Effect::new(move |_| {
/// let value = update_context::<String, _>(|val| {
/// std::mem::replace(val, "bar".to_string())
/// })
/// .expect("could not find String in context");
/// assert_eq!(value, "foo");
/// assert_eq!(expect_context::<String>(), "bar");
/// });
/// });
/// # });
/// ```
pub fn update_context<T: 'static, R>(
cb: impl FnOnce(&mut T) -> R,
) -> Option<R> {
Owner::current().and_then(|owner| owner.update_context(cb))
}

View File

@@ -54,10 +54,6 @@ pub trait Storage<T>: Send + Sync + 'static {
/// Sets a new value for the stored value. If it has been disposed, returns `Some(T)`.
fn try_set(node: NodeId, value: T) -> Option<T>;
/// Takes an item from the arena if it exists and can be accessed from this thread.
/// If it cannot be casted, it will still be removed from the arena.
fn take(node: NodeId) -> Option<T>;
}
/// A form of [`Storage`] that stores the type as itself, with no wrapper.
@@ -104,16 +100,6 @@ where
}
})
}
fn take(node: NodeId) -> Option<T> {
Arena::with_mut(|arena| {
let m = arena.remove(node)?;
match m.downcast::<T>() {
Ok(inner) => Some(*inner),
Err(_) => None,
}
})
}
}
/// A form of [`Storage`] that stores the type with a wrapper that makes it `Send + Sync`, but only
@@ -162,14 +148,4 @@ where
}
})
}
fn take(node: NodeId) -> Option<T> {
Arena::with_mut(|arena| {
let m = arena.remove(node)?;
match m.downcast::<SendWrapper<T>>() {
Ok(inner) => Some(inner.take()),
Err(_) => None,
}
})
}
}

View File

@@ -4,9 +4,7 @@ use super::{
};
use crate::{
signal::guards::{Plain, ReadGuard, UntrackedWriteGuard},
traits::{
DefinedAt, Dispose, IntoInner, IsDisposed, ReadValue, WriteValue,
},
traits::{DefinedAt, Dispose, IsDisposed, ReadValue, WriteValue},
unwrap_signal,
};
use std::{
@@ -24,7 +22,7 @@ use std::{
/// updating it does not notify anything else.
pub struct StoredValue<T, S = SyncStorage> {
value: ArenaItem<ArcStoredValue<T>, S>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
}
@@ -64,11 +62,11 @@ impl<T, S> Hash for StoredValue<T, S> {
impl<T, S> DefinedAt for StoredValue<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -85,7 +83,7 @@ where
pub fn new_with_storage(value: T) -> Self {
Self {
value: ArenaItem::new_with_storage(ArcStoredValue::new(value)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
}
}
@@ -164,19 +162,6 @@ impl<T, S> Dispose for StoredValue<T, S> {
}
}
impl<T, S> IntoInner for StoredValue<T, S>
where
T: 'static,
S: Storage<ArcStoredValue<T>>,
{
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
self.value.into_inner()?.into_inner()
}
}
impl<T> From<ArcStoredValue<T>> for StoredValue<T>
where
T: Send + Sync + 'static,
@@ -184,7 +169,7 @@ where
#[track_caller]
fn from(value: ArcStoredValue<T>) -> Self {
StoredValue {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: ArenaItem::new(value),
}

View File

@@ -113,8 +113,7 @@ pub fn arc_signal<T>(value: T) -> (ArcReadSignal<T>, ArcWriteSignal<T>) {
pub fn signal<T: Send + Sync + 'static>(
value: T,
) -> (ReadSignal<T>, WriteSignal<T>) {
let (r, w) = arc_signal(value);
(r.into(), w.into())
RwSignal::new(value).split()
}
/// Creates an arena-allocated signal.

View File

@@ -4,7 +4,7 @@ use super::{
};
use crate::{
graph::SubscriberSet,
traits::{DefinedAt, IntoInner, IsDisposed, ReadUntracked},
traits::{DefinedAt, IsDisposed, ReadUntracked},
};
use core::fmt::{Debug, Formatter, Result};
use std::{
@@ -54,7 +54,7 @@ use std::{
/// assert_eq!(count.read(), 0);
/// ```
pub struct ArcReadSignal<T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) value: Arc<RwLock<T>>,
pub(crate) inner: Arc<RwLock<SubscriberSet>>,
@@ -64,7 +64,7 @@ impl<T> Clone for ArcReadSignal<T> {
#[track_caller]
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
value: Arc::clone(&self.value),
inner: Arc::clone(&self.inner),
@@ -85,7 +85,7 @@ impl<T: Default> Default for ArcReadSignal<T> {
#[track_caller]
fn default() -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::new(RwLock::new(T::default())),
inner: Arc::new(RwLock::new(SubscriberSet::new())),
@@ -110,11 +110,11 @@ impl<T> Hash for ArcReadSignal<T> {
impl<T> DefinedAt for ArcReadSignal<T> {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -128,15 +128,6 @@ impl<T> IsDisposed for ArcReadSignal<T> {
}
}
impl<T> IntoInner for ArcReadSignal<T> {
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
Some(Arc::into_inner(self.value)?.into_inner().unwrap())
}
}
impl<T> AsSubscriberSet for ArcReadSignal<T> {
type Output = Arc<RwLock<SubscriberSet>>;

View File

@@ -6,7 +6,7 @@ use super::{
use crate::{
graph::{ReactiveNode, SubscriberSet},
prelude::{IsDisposed, Notify},
traits::{DefinedAt, IntoInner, ReadUntracked, UntrackableGuard, Write},
traits::{DefinedAt, ReadUntracked, UntrackableGuard, Write},
};
use core::fmt::{Debug, Formatter, Result};
use std::{
@@ -94,7 +94,7 @@ use std::{
/// assert_eq!(double_count(), 2);
/// ```
pub struct ArcRwSignal<T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) value: Arc<RwLock<T>>,
pub(crate) inner: Arc<RwLock<SubscriberSet>>,
@@ -104,7 +104,7 @@ impl<T> Clone for ArcRwSignal<T> {
#[track_caller]
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
value: Arc::clone(&self.value),
inner: Arc::clone(&self.inner),
@@ -154,7 +154,7 @@ impl<T> ArcRwSignal<T> {
#[track_caller]
pub fn new(value: T) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::new(RwLock::new(value)),
inner: Arc::new(RwLock::new(SubscriberSet::new())),
@@ -165,7 +165,7 @@ impl<T> ArcRwSignal<T> {
#[track_caller]
pub fn read_only(&self) -> ArcReadSignal<T> {
ArcReadSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::clone(&self.value),
inner: Arc::clone(&self.inner),
@@ -176,7 +176,7 @@ impl<T> ArcRwSignal<T> {
#[track_caller]
pub fn write_only(&self) -> ArcWriteSignal<T> {
ArcWriteSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::clone(&self.value),
inner: Arc::clone(&self.inner),
@@ -198,7 +198,7 @@ impl<T> ArcRwSignal<T> {
) -> Option<Self> {
if Arc::ptr_eq(&read.inner, &write.inner) {
Some(Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: read.value,
inner: read.inner,
@@ -212,11 +212,11 @@ impl<T> ArcRwSignal<T> {
impl<T> DefinedAt for ArcRwSignal<T> {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -230,15 +230,6 @@ impl<T> IsDisposed for ArcRwSignal<T> {
}
}
impl<T> IntoInner for ArcRwSignal<T> {
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
Some(Arc::into_inner(self.value)?.into_inner().unwrap())
}
}
impl<T> AsSubscriberSet for ArcRwSignal<T> {
type Output = Arc<RwLock<SubscriberSet>>;

View File

@@ -13,7 +13,7 @@ use std::{
///
/// This can be useful for when using external data not stored in signals, for example.
pub struct ArcTrigger {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) inner: Arc<RwLock<SubscriberSet>>,
}
@@ -23,7 +23,7 @@ impl ArcTrigger {
#[track_caller]
pub fn new() -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: Default::default(),
}
@@ -40,7 +40,7 @@ impl Clone for ArcTrigger {
#[track_caller]
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
inner: Arc::clone(&self.inner),
}
@@ -72,11 +72,11 @@ impl AsSubscriberSet for ArcTrigger {
impl DefinedAt for ArcTrigger {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -2,7 +2,7 @@ use super::guards::{UntrackedWriteGuard, WriteGuard};
use crate::{
graph::{ReactiveNode, SubscriberSet},
prelude::{IsDisposed, Notify},
traits::{DefinedAt, IntoInner, UntrackableGuard, Write},
traits::{DefinedAt, UntrackableGuard, Write},
};
use core::fmt::{Debug, Formatter, Result};
use std::{
@@ -54,7 +54,7 @@ use std::{
/// assert_eq!(count.get(), 3);
/// ```
pub struct ArcWriteSignal<T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) value: Arc<RwLock<T>>,
pub(crate) inner: Arc<RwLock<SubscriberSet>>,
@@ -64,7 +64,7 @@ impl<T> Clone for ArcWriteSignal<T> {
#[track_caller]
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
value: Arc::clone(&self.value),
inner: Arc::clone(&self.inner),
@@ -98,11 +98,11 @@ impl<T> Hash for ArcWriteSignal<T> {
impl<T> DefinedAt for ArcWriteSignal<T> {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -116,15 +116,6 @@ impl<T> IsDisposed for ArcWriteSignal<T> {
}
}
impl<T> IntoInner for ArcWriteSignal<T> {
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
Some(Arc::into_inner(self.value)?.into_inner().unwrap())
}
}
impl<T> Notify for ArcWriteSignal<T> {
fn notify(&self) {
self.inner.mark_dirty();

View File

@@ -6,7 +6,7 @@ use super::{
use crate::{
graph::SubscriberSet,
owner::{ArenaItem, FromLocal, LocalStorage, Storage, SyncStorage},
traits::{DefinedAt, Dispose, IntoInner, IsDisposed, ReadUntracked},
traits::{DefinedAt, Dispose, IsDisposed, ReadUntracked},
unwrap_signal,
};
use core::fmt::Debug;
@@ -58,7 +58,7 @@ use std::{
/// assert_eq!(count.read(), 0);
/// ```
pub struct ReadSignal<T, S = SyncStorage> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) inner: ArenaItem<ArcReadSignal<T>, S>,
}
@@ -105,11 +105,11 @@ impl<T, S> Hash for ReadSignal<T, S> {
impl<T, S> DefinedAt for ReadSignal<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -122,18 +122,6 @@ impl<T, S> IsDisposed for ReadSignal<T, S> {
}
}
impl<T, S> IntoInner for ReadSignal<T, S>
where
S: Storage<ArcReadSignal<T>>,
{
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
self.inner.into_inner()?.into_inner()
}
}
impl<T, S> AsSubscriberSet for ReadSignal<T, S>
where
S: Storage<ArcReadSignal<T>>,
@@ -168,7 +156,7 @@ where
#[track_caller]
fn from(value: ArcReadSignal<T>) -> Self {
ReadSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
@@ -182,7 +170,7 @@ where
#[track_caller]
fn from_local(value: ArcReadSignal<T>) -> Self {
ReadSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}

View File

@@ -8,7 +8,7 @@ use crate::{
owner::{ArenaItem, FromLocal, LocalStorage, Storage, SyncStorage},
signal::guards::{UntrackedWriteGuard, WriteGuard},
traits::{
DefinedAt, Dispose, IntoInner, IsDisposed, Notify, ReadUntracked,
DefinedAt, Dispose, IsDisposed, Notify, ReadUntracked,
UntrackableGuard, Write,
},
unwrap_signal,
@@ -100,7 +100,7 @@ use std::{
/// assert_eq!(double_count(), 2);
/// ```
pub struct RwSignal<T, S = SyncStorage> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: ArenaItem<ArcRwSignal<T>, S>,
}
@@ -139,7 +139,7 @@ where
#[track_caller]
pub fn new_with_storage(value: T) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcRwSignal::new(value)),
}
@@ -172,7 +172,7 @@ where
#[track_caller]
pub fn read_only(&self) -> ReadSignal<T, S> {
ReadSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(
self.inner
@@ -194,7 +194,7 @@ where
#[track_caller]
pub fn write_only(&self) -> WriteSignal<T, S> {
WriteSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(
self.inner
@@ -231,10 +231,10 @@ where
(Some(read), Some(write)) => {
if Arc::ptr_eq(&read.inner, &write.inner) {
Some(Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcRwSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::clone(&read.value),
inner: Arc::clone(&read.inner),
@@ -296,11 +296,11 @@ impl<T, S> Hash for RwSignal<T, S> {
impl<T, S> DefinedAt for RwSignal<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -313,18 +313,6 @@ impl<T: 'static, S> IsDisposed for RwSignal<T, S> {
}
}
impl<T, S> IntoInner for RwSignal<T, S>
where
S: Storage<ArcRwSignal<T>>,
{
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
self.inner.into_inner()?.into_inner()
}
}
impl<T, S> AsSubscriberSet for RwSignal<T, S>
where
S: Storage<ArcRwSignal<T>>,
@@ -390,7 +378,7 @@ where
#[track_caller]
fn from(value: ArcRwSignal<T>) -> Self {
RwSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
@@ -414,7 +402,7 @@ where
#[track_caller]
fn from_local(value: ArcRwSignal<T>) -> Self {
RwSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}

View File

@@ -105,7 +105,7 @@ where
AnySource(
Arc::as_ptr(subs) as usize,
Arc::downgrade(subs) as Weak<dyn Source + Send + Sync>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
self.defined_at().expect("no DefinedAt in debug mode"),
)
})

View File

@@ -18,7 +18,7 @@ use std::{
/// [`Owner`](crate::owner::Owner) cleans up. For a reference-counted trigger that lives
/// as long as a reference to it is alive, see [`ArcTrigger`].
pub struct Trigger {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) inner: ArenaItem<ArcTrigger>,
}
@@ -28,7 +28,7 @@ impl Trigger {
#[track_caller]
pub fn new() -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new(ArcTrigger::new()),
}
@@ -83,11 +83,11 @@ impl AsSubscriberSet for Trigger {
impl DefinedAt for Trigger {
#[inline(always)]
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -1,10 +1,7 @@
use super::{guards::WriteGuard, ArcWriteSignal};
use crate::{
owner::{ArenaItem, FromLocal, LocalStorage, Storage, SyncStorage},
traits::{
DefinedAt, Dispose, IntoInner, IsDisposed, Notify, UntrackableGuard,
Write,
},
owner::{ArenaItem, Storage, SyncStorage},
traits::{DefinedAt, Dispose, IsDisposed, Notify, UntrackableGuard, Write},
};
use core::fmt::Debug;
use guardian::ArcRwLockWriteGuardian;
@@ -53,7 +50,7 @@ use std::{hash::Hash, ops::DerefMut, panic::Location, sync::Arc};
/// assert_eq!(count.get(), 3);
/// ```
pub struct WriteSignal<T, S = SyncStorage> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) inner: ArenaItem<ArcWriteSignal<T>, S>,
}
@@ -100,63 +97,23 @@ impl<T, S> Hash for WriteSignal<T, S> {
impl<T, S> DefinedAt for WriteSignal<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
}
}
impl<T> From<ArcWriteSignal<T>> for WriteSignal<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcWriteSignal<T>) -> Self {
WriteSignal {
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
}
}
impl<T> FromLocal<ArcWriteSignal<T>> for WriteSignal<T, LocalStorage>
where
T: 'static,
{
#[track_caller]
fn from_local(value: ArcWriteSignal<T>) -> Self {
WriteSignal {
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
}
}
impl<T, S> IsDisposed for WriteSignal<T, S> {
fn is_disposed(&self) -> bool {
self.inner.is_disposed()
}
}
impl<T, S> IntoInner for WriteSignal<T, S>
where
S: Storage<ArcWriteSignal<T>>,
{
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
self.inner.into_inner()?.into_inner()
}
}
impl<T, S> Notify for WriteSignal<T, S>
where
T: 'static,

View File

@@ -67,10 +67,10 @@ use std::{
#[macro_export]
macro_rules! unwrap_signal {
($signal:ident) => {{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let location = std::panic::Location::caller();
|| {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
panic!(
"{}",
@@ -80,7 +80,7 @@ macro_rules! unwrap_signal {
)
);
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
panic!(
"Tried to access a reactive value that has already been \
@@ -630,18 +630,6 @@ pub trait IsDisposed {
fn is_disposed(&self) -> bool;
}
/// Turns a signal back into a raw value.
pub trait IntoInner {
/// The type of the value contained in the signal.
type Value;
/// Returns the inner value if this is the only reference to to the signal.
/// Otherwise, returns `None` and drops this reference.
/// # Panics
/// Panics if the inner lock is poisoned.
fn into_inner(self) -> Option<Self::Value>;
}
/// Describes where the signal was defined. This is used for diagnostic warnings and is purely a
/// debug-mode tool.
pub trait DefinedAt {

View File

@@ -93,35 +93,17 @@ pub mod read {
}
/// A wrapper for any kind of reference-counted reactive signal:
/// an [`ArcReadSignal`], [`ArcMemo`], [`ArcRwSignal`], or derived signal closure,
/// or a plain value of the same type
/// an [`ArcReadSignal`], [`ArcMemo`], [`ArcRwSignal`],
/// or derived signal closure.
///
/// This allows you to create APIs that take `T` or any reactive value that returns `T`
/// as an argument, rather than adding a generic `F: Fn() -> T`.
///
/// Values can be accessed with the same function call, `read()`, `with()`, and `get()`
/// APIs as other signals.
///
/// ## Important Notes about Derived Signals
///
/// `Signal::derive()` is simply a way to box and type-erase a “derived signal,” which
/// is a plain closure that accesses one or more signals. It does *not* cache the value
/// of that computation. Accessing the value of a `Signal<_>` that is created using `Signal::derive()`
/// will run the closure again every time you call `.read()`, `.with()`, or `.get()`.
///
/// If you want the closure to run the minimal number of times necessary to update its state,
/// and then to cache its value, you should use a [`Memo`] (and convert it into a `Signal<_>`)
/// rather than using `Signal::derive()`.
///
/// Note that for many computations, it is nevertheless less expensive to use a derived signal
/// than to create a separate memo and to cache the value: creating a new reactive node and
/// taking the lock on that cached value whenever you access the signal is *more* expensive than
/// simply re-running the calculation in many cases.
/// This allows you to create APIs that take any kind of `ArcSignal<T>` as an argument,
/// rather than adding a generic `F: Fn() -> T`. Values can be access with the same
/// function call, `with()`, and `get()` APIs as other signals.
pub struct ArcSignal<T: 'static, S = SyncStorage>
where
S: Storage<T>,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: SignalTypes<T, S>,
}
@@ -132,7 +114,7 @@ pub mod read {
{
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
inner: self.inner.clone(),
}
@@ -146,7 +128,7 @@ pub mod read {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut s = f.debug_struct("ArcSignal");
s.field("inner", &self.inner);
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
s.field("defined_at", &self.defined_at);
s.finish()
}
@@ -202,7 +184,7 @@ pub mod read {
Self {
inner: SignalTypes::DerivedSignal(Arc::new(derived_signal)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -212,7 +194,7 @@ pub mod read {
pub fn stored(value: T) -> Self {
Self {
inner: SignalTypes::Stored(ArcStoredValue::new(value)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -232,7 +214,7 @@ pub mod read {
fn from(value: ArcReadSignal<T>) -> Self {
Self {
inner: SignalTypes::ReadSignal(value),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -243,7 +225,7 @@ pub mod read {
fn from(value: ArcRwSignal<T>) -> Self {
Self {
inner: SignalTypes::ReadSignal(value.read_only()),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -257,7 +239,7 @@ pub mod read {
fn from(value: ArcMemo<T, S>) -> Self {
Self {
inner: SignalTypes::Memo(value),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -268,11 +250,11 @@ pub mod read {
S: Storage<T>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -348,35 +330,16 @@ pub mod read {
}
/// A wrapper for any kind of arena-allocated reactive signal:
/// a [`ReadSignal`], [`Memo`], [`RwSignal`], or derived signal closure,
/// or a plain value of the same type
/// an [`ReadSignal`], [`Memo`], [`RwSignal`], or derived signal closure.
///
/// This allows you to create APIs that take `T` or any reactive value that returns `T`
/// as an argument, rather than adding a generic `F: Fn() -> T`.
///
/// Values can be accessed with the same function call, `read()`, `with()`, and `get()`
/// APIs as other signals.
///
/// ## Important Notes about Derived Signals
///
/// `Signal::derive()` is simply a way to box and type-erase a “derived signal,” which
/// is a plain closure that accesses one or more signals. It does *not* cache the value
/// of that computation. Accessing the value of a `Signal<_>` that is created using `Signal::derive()`
/// will run the closure again every time you call `.read()`, `.with()`, or `.get()`.
///
/// If you want the closure to run the minimal number of times necessary to update its state,
/// and then to cache its value, you should use a [`Memo`] (and convert it into a `Signal<_>`)
/// rather than using `Signal::derive()`.
///
/// Note that for many computations, it is nevertheless less expensive to use a derived signal
/// than to create a separate memo and to cache the value: creating a new reactive node and
/// taking the lock on that cached value whenever you access the signal is *more* expensive than
/// simply re-running the calculation in many cases.
/// This allows you to create APIs that take any kind of `Signal<T>` as an argument,
/// rather than adding a generic `F: Fn() -> T`. Values can be access with the same
/// function call, `with()`, and `get()` APIs as other signals.
pub struct Signal<T, S = SyncStorage>
where
S: Storage<T>,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: ArenaItem<SignalTypes<T, S>, S>,
}
@@ -408,7 +371,7 @@ pub mod read {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut s = f.debug_struct("Signal");
s.field("inner", &self.inner);
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
s.field("defined_at", &self.defined_at);
s.finish()
}
@@ -430,11 +393,11 @@ pub mod read {
S: Storage<T>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -567,7 +530,7 @@ pub mod read {
inner: ArenaItem::new_with_storage(SignalTypes::DerivedSignal(
Arc::new(derived_signal),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -579,7 +542,7 @@ pub mod read {
inner: ArenaItem::new_with_storage(SignalTypes::Stored(
ArcStoredValue::new(value),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -606,7 +569,7 @@ pub mod read {
inner: ArenaItem::new_local(SignalTypes::DerivedSignal(
Arc::new(derived_signal),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -619,7 +582,7 @@ pub mod read {
inner: ArenaItem::new_local(SignalTypes::Stored(
ArcStoredValue::new(value),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -677,7 +640,7 @@ pub mod read {
#[track_caller]
fn from(value: ArcSignal<T, SyncStorage>) -> Self {
Signal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new(value.inner),
}
@@ -691,7 +654,7 @@ pub mod read {
#[track_caller]
fn from_local(value: ArcSignal<T, LocalStorage>) -> Self {
Signal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_local(value.inner),
}
@@ -705,7 +668,7 @@ pub mod read {
#[track_caller]
fn from(value: Signal<T, S>) -> Self {
ArcSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: value
.inner
@@ -723,7 +686,7 @@ pub mod read {
fn from(value: ReadSignal<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::ReadSignal(value.into())),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -739,7 +702,7 @@ pub mod read {
inner: ArenaItem::new_local(SignalTypes::ReadSignal(
value.into(),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -753,7 +716,7 @@ pub mod read {
fn from(value: ArcReadSignal<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::ReadSignal(value)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -767,7 +730,7 @@ pub mod read {
fn from(value: ArcReadSignal<T>) -> Self {
Self {
inner: ArenaItem::new_local(SignalTypes::ReadSignal(value)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -783,7 +746,7 @@ pub mod read {
inner: ArenaItem::new(SignalTypes::ReadSignal(
value.read_only().into(),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -799,7 +762,7 @@ pub mod read {
inner: ArenaItem::new_local(SignalTypes::ReadSignal(
value.read_only().into(),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -815,7 +778,7 @@ pub mod read {
inner: ArenaItem::new(SignalTypes::ReadSignal(
value.read_only(),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -831,7 +794,7 @@ pub mod read {
inner: ArenaItem::new_local(SignalTypes::ReadSignal(
value.read_only(),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -845,7 +808,7 @@ pub mod read {
fn from(value: Memo<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::Memo(value.into())),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -859,7 +822,7 @@ pub mod read {
fn from(value: Memo<T, LocalStorage>) -> Self {
Self {
inner: ArenaItem::new_local(SignalTypes::Memo(value.into())),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -873,7 +836,7 @@ pub mod read {
fn from(value: ArcMemo<T>) -> Self {
Self {
inner: ArenaItem::new(SignalTypes::Memo(value)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -887,7 +850,7 @@ pub mod read {
fn from(value: ArcMemo<T, LocalStorage>) -> Self {
Self {
inner: ArenaItem::new_local(SignalTypes::Memo(value)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -1868,7 +1831,7 @@ pub mod write {
T: 'static,
{
inner: SignalSetterTypes<T, S>,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static std::panic::Location<'static>,
}
@@ -1883,7 +1846,7 @@ pub mod write {
fn default() -> Self {
Self {
inner: SignalSetterTypes::Default,
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -1936,7 +1899,7 @@ pub mod write {
inner: SignalSetterTypes::Mapped(ArenaItem::new_with_storage(
Box::new(mapped_setter),
)),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -1947,7 +1910,7 @@ pub mod write {
fn from(value: WriteSignal<T, S>) -> Self {
Self {
inner: SignalSetterTypes::Write(value),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}
@@ -1962,7 +1925,7 @@ pub mod write {
fn from(value: RwSignal<T, S>) -> Self {
Self {
inner: SignalSetterTypes::Write(value.write_only()),
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: std::panic::Location::caller(),
}
}

View File

@@ -443,43 +443,3 @@ fn unsync_derived_signal_and_memo() {
assert_eq!(f.with(|n| *n), 6);
assert_eq!(f.get_untracked(), 6);
}
#[test]
fn memo_updates_even_if_not_read_until_later() {
#![allow(clippy::bool_assert_comparison)]
let owner = Owner::new();
owner.set();
// regression test for https://github.com/leptos-rs/leptos/issues/3339
let input = RwSignal::new(0);
let first_memo = Memo::new(move |_| input.get() == 1);
let second_memo = Memo::new(move |_| first_memo.get());
assert_eq!(input.get(), 0);
assert_eq!(first_memo.get(), false);
println!("update to 1");
input.set(1);
assert_eq!(input.get(), 1);
println!("read memo 1");
assert_eq!(first_memo.get(), true);
println!("read memo 2");
assert_eq!(second_memo.get(), true);
// this time, we don't read the memo
println!("\nupdate to 2");
input.set(2);
assert_eq!(input.get(), 2);
println!("read memo 1");
assert_eq!(first_memo.get(), false);
println!("\nupdate to 3");
input.set(3);
assert_eq!(input.get(), 3);
println!("read memo 1");
assert_eq!(first_memo.get(), false);
println!("read memo 2");
assert_eq!(second_memo.get(), false);
}

View File

@@ -2,8 +2,8 @@ use reactive_graph::{
owner::Owner,
signal::{arc_signal, signal, ArcRwSignal, RwSignal},
traits::{
Dispose, Get, GetUntracked, IntoInner, Read, Set, Update,
UpdateUntracked, With, WithUntracked, Write,
Get, GetUntracked, Read, Set, Update, UpdateUntracked, With,
WithUntracked, Write,
},
};
@@ -108,35 +108,3 @@ fn update_signal() {
set_a.set(4);
assert_eq!(a.get(), 4);
}
#[test]
fn into_inner_signal() {
let owner = Owner::new();
owner.set();
let rw_signal = RwSignal::new(1);
assert_eq!(rw_signal.get(), 1);
assert_eq!(rw_signal.into_inner(), Some(1));
}
#[test]
fn into_inner_arc_signal() {
let owner = Owner::new();
owner.set();
let (a, b) = arc_signal(2);
assert_eq!(a.get(), 2);
std::mem::drop(b);
assert_eq!(a.into_inner(), Some(2));
}
#[test]
fn into_inner_non_arc_signal() {
let owner = Owner::new();
owner.set();
let (a, b) = signal(2);
assert_eq!(a.get(), 2);
b.dispose();
assert_eq!(a.into_inner(), Some(2));
}

View File

@@ -1,6 +1,6 @@
[package]
name = "reactive_stores"
version = "0.1.2"
version = "0.1.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -23,6 +23,3 @@ tokio = { version = "1.41", features = ["rt-multi-thread", "macros"] }
tokio-test = { version = "0.4.4" }
any_spawner = { workspace = true, features = ["futures-executor", "tokio"] }
reactive_graph = { workspace = true, features = ["effects"] }
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -7,7 +7,6 @@ use reactive_graph::{
owner::Storage,
traits::{
DefinedAt, IsDisposed, Notify, ReadUntracked, Track, UntrackableGuard,
Write,
},
};
use std::{
@@ -26,14 +25,13 @@ pub struct ArcField<T>
where
T: 'static,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
path: StorePath,
trigger: StoreFieldTrigger,
get_trigger: Arc<dyn Fn(StorePath) -> StoreFieldTrigger + Send + Sync>,
read: Arc<dyn Fn() -> Option<StoreFieldReader<T>> + Send + Sync>,
pub(crate) write:
Arc<dyn Fn() -> Option<StoreFieldWriter<T>> + Send + Sync>,
write: Arc<dyn Fn() -> Option<StoreFieldWriter<T>> + Send + Sync>,
keys: Arc<dyn Fn() -> Option<KeyMap> + Send + Sync>,
track_field: Arc<dyn Fn() + Send + Sync>,
}
@@ -116,7 +114,7 @@ where
#[track_caller]
fn from(value: Store<T, S>) -> Self {
ArcField {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
path: value.path().into_iter().collect(),
trigger: value.get_trigger(value.path().into_iter().collect()),
@@ -136,7 +134,7 @@ where
#[track_caller]
fn from(value: ArcStore<T>) -> Self {
ArcField {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
path: value.path().into_iter().collect(),
trigger: value.get_trigger(value.path().into_iter().collect()),
@@ -174,7 +172,7 @@ where
#[track_caller]
fn from(value: Subfield<Inner, Prev, T>) -> Self {
ArcField {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
path: value.path().into_iter().collect(),
trigger: value.get_trigger(value.path().into_iter().collect()),
@@ -212,7 +210,7 @@ where
#[track_caller]
fn from(value: AtIndex<Inner, Prev>) -> Self {
ArcField {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
path: value.path().into_iter().collect(),
trigger: value.get_trigger(value.path().into_iter().collect()),
@@ -254,7 +252,7 @@ where
#[track_caller]
fn from(value: AtKeyed<Inner, Prev, K, T>) -> Self {
ArcField {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
path: value.path().into_iter().collect(),
trigger: value.get_trigger(value.path().into_iter().collect()),
@@ -285,7 +283,7 @@ where
impl<T> Clone for ArcField<T> {
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
path: self.path.clone(),
trigger: self.trigger.clone(),
@@ -300,11 +298,11 @@ impl<T> Clone for ArcField<T> {
impl<T> DefinedAt for ArcField<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -331,22 +329,6 @@ impl<T> ReadUntracked for ArcField<T> {
}
}
impl<T> Write for ArcField<T> {
type Value = T;
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
(self.write)()
}
fn try_write_untracked(
&self,
) -> Option<impl DerefMut<Target = Self::Value>> {
let mut guard = (self.write)()?;
guard.untrack();
Some(guard)
}
}
impl<T> IsDisposed for ArcField<T> {
fn is_disposed(&self) -> bool {
false

View File

@@ -6,18 +6,10 @@ use crate::{
};
use reactive_graph::{
owner::{ArenaItem, Storage, SyncStorage},
traits::{
DefinedAt, IsDisposed, Notify, ReadUntracked, Track, UntrackableGuard,
Write,
},
traits::{DefinedAt, IsDisposed, Notify, ReadUntracked, Track},
unwrap_signal,
};
use std::{
fmt::Debug,
hash::Hash,
ops::{DerefMut, IndexMut},
panic::Location,
};
use std::{fmt::Debug, hash::Hash, ops::IndexMut, panic::Location};
/// Wraps access to a single field of type `T`.
///
@@ -27,7 +19,7 @@ pub struct Field<T, S = SyncStorage>
where
T: 'static,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: ArenaItem<ArcField<T>, S>,
}
@@ -75,7 +67,7 @@ where
#[track_caller]
fn from(value: Store<T, S>) -> Self {
Field {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value.into()),
}
@@ -90,7 +82,7 @@ where
#[track_caller]
fn from(value: ArcStore<T>) -> Self {
Field {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value.into()),
}
@@ -108,7 +100,7 @@ where
#[track_caller]
fn from(value: Subfield<Inner, Prev, T>) -> Self {
Field {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value.into()),
}
@@ -126,7 +118,7 @@ where
#[track_caller]
fn from(value: AtIndex<Inner, Prev>) -> Self {
Field {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value.into()),
}
@@ -149,7 +141,7 @@ where
#[track_caller]
fn from(value: AtKeyed<Inner, Prev, K, T>) -> Self {
Field {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value.into()),
}
@@ -166,11 +158,11 @@ impl<T, S> Copy for Field<T, S> {}
impl<T, S> DefinedAt for Field<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -212,24 +204,6 @@ where
}
}
impl<T> Write for Field<T> {
type Value = T;
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
self.inner.try_get_value().and_then(|inner| (inner.write)())
}
fn try_write_untracked(
&self,
) -> Option<impl DerefMut<Target = Self::Value>> {
self.inner.try_get_value().and_then(|inner| {
let mut guard = (inner.write)()?;
guard.untrack();
Some(guard)
})
}
}
impl<T, S> IsDisposed for Field<T, S> {
fn is_disposed(&self) -> bool {
self.inner.is_disposed()

View File

@@ -23,7 +23,7 @@ use std::{
/// Provides access to the data at some index in another collection.
#[derive(Debug)]
pub struct AtIndex<Inner, Prev> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: Inner,
index: usize,
@@ -36,7 +36,7 @@ where
{
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
inner: self.inner.clone(),
index: self.index,
@@ -52,7 +52,7 @@ impl<Inner, Prev> AtIndex<Inner, Prev> {
#[track_caller]
pub fn new(inner: Inner, index: usize) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner,
index,
@@ -115,11 +115,11 @@ where
Inner: StoreField<Value = Prev>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -28,7 +28,7 @@ pub struct KeyedSubfield<Inner, Prev, K, T>
where
for<'a> &'a T: IntoIterator,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
path_segment: StorePathSegment,
inner: Inner,
@@ -44,7 +44,7 @@ where
{
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
path_segment: self.path_segment,
inner: self.inner.clone(),
@@ -76,7 +76,7 @@ where
write: fn(&mut Prev) -> &mut T,
) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner,
path_segment,
@@ -254,11 +254,11 @@ where
Inner: StoreField<Value = Prev>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -356,7 +356,7 @@ pub struct AtKeyed<Inner, Prev, K, T>
where
for<'a> &'a T: IntoIterator,
{
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: KeyedSubfield<Inner, Prev, K, T>,
key: K,
@@ -370,7 +370,7 @@ where
{
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
inner: self.inner.clone(),
key: self.key.clone(),
@@ -394,7 +394,7 @@ where
#[track_caller]
pub fn new(inner: KeyedSubfield<Inner, Prev, K, T>, key: K) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner,
key,
@@ -511,11 +511,11 @@ where
for<'a> &'a T: IntoIterator,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -623,15 +623,10 @@ where
.keys()
.expect("updating keys on a store with no keys");
// generating the latest keys out here means that if we have
// nested keyed fields, the second field will not try to take a
// read-lock on the key map to get the field while the first field
// is still holding the write-lock in the closure below
let latest = self.latest_keys();
keys.with_field_keys(
inner_path,
|keys| {
keys.update(latest);
keys.update(self.latest_keys());
},
|| self.latest_keys(),
);

View File

@@ -315,7 +315,7 @@ impl KeyMap {
/// This adds a getter method for each field to `Store<T>`, which allow accessing reactive versions
/// of each individual field of the struct.
pub struct ArcStore<T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
pub(crate) value: Arc<RwLock<T>>,
signals: Arc<RwLock<TriggerMap>>,
@@ -326,7 +326,7 @@ impl<T> ArcStore<T> {
/// Creates a new store from the initial value.
pub fn new(value: T) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
value: Arc::new(RwLock::new(value)),
signals: Default::default(),
@@ -338,7 +338,7 @@ impl<T> ArcStore<T> {
impl<T: Debug> Debug for ArcStore<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_struct("ArcStore");
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let f = f.field("defined_at", &self.defined_at);
f.field("value", &self.value)
.field("signals", &self.signals)
@@ -349,7 +349,7 @@ impl<T: Debug> Debug for ArcStore<T> {
impl<T> Clone for ArcStore<T> {
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
value: Arc::clone(&self.value),
signals: Arc::clone(&self.signals),
@@ -360,11 +360,11 @@ impl<T> Clone for ArcStore<T> {
impl<T> DefinedAt for ArcStore<T> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -433,7 +433,7 @@ impl<T: 'static> Notify for ArcStore<T> {
/// This follows the same ownership rules as arena-allocated types like
/// [`RwSignal`](reactive_graph::signal::RwSignal).
pub struct Store<T, S = SyncStorage> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
inner: ArenaItem<ArcStore<T>, S>,
}
@@ -445,7 +445,7 @@ where
/// Creates a new store with the initial value.
pub fn new(value: T) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcStore::new(value)),
}
@@ -461,7 +461,7 @@ where
/// This pins the value to the current thread. Accessing it from any other thread will panic.
pub fn new_local(value: T) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(ArcStore::new(value)),
}
@@ -474,7 +474,7 @@ where
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_struct("Store");
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
let f = f.field("defined_at", &self.defined_at);
f.field("inner", &self.inner).finish()
}
@@ -490,11 +490,11 @@ impl<T, S> Copy for Store<T, S> {}
impl<T, S> DefinedAt for Store<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}
@@ -569,20 +569,6 @@ where
}
}
impl<T, S> From<ArcStore<T>> for Store<T, S>
where
T: 'static,
S: Storage<ArcStore<T>>,
{
fn from(value: ArcStore<T>) -> Self {
Self {
#[cfg(debug_assertions)]
defined_at: value.defined_at,
inner: ArenaItem::new_with_storage(value),
}
}
}
#[cfg(test)]
mod tests {
use crate::{self as reactive_stores, Patch, Store, StoreFieldIterator};

View File

@@ -1,5 +1,5 @@
use crate::{StoreField, Subfield};
use reactive_graph::traits::{Read, ReadUntracked};
use reactive_graph::traits::Read;
use std::ops::Deref;
/// Extends optional store fields, with the ability to unwrap or map over them.
@@ -23,23 +23,12 @@ where
self,
map_fn: impl FnOnce(Subfield<Self, Option<Self::Output>, Self::Output>) -> U,
) -> Option<U>;
/// Unreactively maps over the field.
///
/// This returns `None` if the subfield is currently `None`,
/// and a new store subfield with the inner value if it is `Some`. This is an unreactive variant of
/// `[OptionStoreExt::map]`, and will not cause the reactive context to re-run if the field changes.
fn map_untracked<U>(
self,
map_fn: impl FnOnce(Subfield<Self, Option<Self::Output>, Self::Output>) -> U,
) -> Option<U>;
}
impl<T, S> OptionStoreExt for S
where
S: StoreField<Value = Option<T>> + Read + ReadUntracked,
S: StoreField<Value = Option<T>> + Read,
<S as Read>::Value: Deref<Target = Option<T>>,
<S as ReadUntracked>::Value: Deref<Target = Option<T>>,
{
type Output = T;
@@ -62,17 +51,6 @@ where
None
}
}
fn map_untracked<U>(
self,
map_fn: impl FnOnce(Subfield<S, Option<T>, T>) -> U,
) -> Option<U> {
if self.read_untracked().is_some() {
Some(map_fn(self.unwrap()))
} else {
None
}
}
}
#[cfg(test)]

View File

@@ -78,7 +78,6 @@ patch_primitives! {
Arc<str>,
Rc<str>,
Cow<'_, str>,
usize,
u8,
u16,
u32,

View File

@@ -18,7 +18,7 @@ use std::{iter, marker::PhantomData, ops::DerefMut, panic::Location};
/// Accesses a single field of a reactive structure.
#[derive(Debug)]
pub struct Subfield<Inner, Prev, T> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: &'static Location<'static>,
path_segment: StorePathSegment,
inner: Inner,
@@ -33,7 +33,7 @@ where
{
fn clone(&self) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: self.defined_at,
path_segment: self.path_segment,
inner: self.inner.clone(),
@@ -56,7 +56,7 @@ impl<Inner, Prev, T> Subfield<Inner, Prev, T> {
write: fn(&mut Prev) -> &mut T,
) -> Self {
Self {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
defined_at: Location::caller(),
inner,
path_segment,
@@ -119,11 +119,11 @@ where
Inner: StoreField<Value = Prev>,
{
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
None
}

View File

@@ -1,6 +1,6 @@
[package]
name = "reactive_stores_macro"
version = "0.1.0"
version = "0.1.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_router"
version = "0.7.2"
version = "0.7.0-rc1"
authors = ["Greg Johnston", "Ben Wishovich"]
license = "MIT"
readme = "../README.md"
@@ -19,9 +19,9 @@ reactive_graph = { workspace = true }
tachys = { workspace = true, features = ["reactive_graph"] }
futures = "0.3.31"
url = "2.5"
js-sys = { version = "0.3.74" }
wasm-bindgen = { version = "0.2.97" }
tracing = { version = "0.1.41", optional = true }
js-sys = { version = "0.3.72" }
wasm-bindgen = { version = "0.2.95" }
tracing = { version = "0.1.40", optional = true }
once_cell = "1.20"
send_wrapper = "0.6.0"
thiserror = "2.0"

View File

@@ -13,8 +13,8 @@ use crate::{
resolve_path::resolve_path,
ChooseView, MatchNestedRoutes, NestedRoute, RouteDefs, SsrMode,
};
use either_of::EitherOf3;
use leptos::{children, prelude::*};
use either_of::Either;
use leptos::prelude::*;
use reactive_graph::{
owner::{provide_context, use_context, Owner},
signal::ArcRwSignal,
@@ -389,9 +389,6 @@ pub fn ProtectedRoute<Segments, ViewFn, View, C, PathFn, P>(
condition: C,
/// The path that will be redirected to if the condition is `Some(false)`.
redirect_path: PathFn,
/// Will be displayed while the condition is pending. By default this is the empty view.
#[prop(optional, into)]
fallback: children::ViewFn,
/// The mode that this route prefers during server-side rendering.
/// Defaults to out-of-order streaming.
#[prop(optional)]
@@ -404,26 +401,23 @@ where
PathFn: Fn() -> P + Send + Clone + 'static,
P: Display + 'static,
{
let fallback = move || fallback.run();
let view = move || {
let condition = condition.clone();
let redirect_path = redirect_path.clone();
let view = view.clone();
let fallback = fallback.clone();
(view! {
<Transition fallback=fallback.clone()>
<Transition>
{move || {
let condition = condition();
let view = view.clone();
let redirect_path = redirect_path.clone();
let fallback = fallback.clone();
Unsuspend::new(move || match condition {
Some(true) => EitherOf3::A(view()),
Some(true) => Either::Left(view()),
#[allow(clippy::unit_arg)]
Some(false) => {
EitherOf3::B(view! { <Redirect path=redirect_path()/> }.into_inner())
Either::Right(view! { <Redirect path=redirect_path()/> }.into_inner())
}
None => EitherOf3::C(fallback()),
None => Either::Right(()),
})
}}
@@ -447,9 +441,6 @@ pub fn ProtectedParentRoute<Segments, ViewFn, View, C, PathFn, P, Children>(
/// the page, `Some(false)` means the user cannot access the page, and `None` means this
/// information is still loading.
condition: C,
/// Will be displayed while the condition is pending. By default this is the empty view.
#[prop(optional, into)]
fallback: children::ViewFn,
/// The path that will be redirected to if the condition is `Some(false)`.
redirect_path: PathFn,
/// Nested child routes.
@@ -466,21 +457,17 @@ where
PathFn: Fn() -> P + Send + Clone + 'static,
P: Display + 'static,
{
let fallback = move || fallback.run();
let children = children.into_inner();
let view = move || {
let condition = condition.clone();
let redirect_path = redirect_path.clone();
let fallback = fallback.clone();
let view = view.clone();
let owner = Owner::current().unwrap();
let view = {
let fallback = fallback.clone();
move || {
let condition = condition();
let view = view.clone();
let redirect_path = redirect_path.clone();
let fallback = fallback.clone();
let owner = owner.clone();
Unsuspend::new(move || match condition {
// reset the owner so that things like providing context work
@@ -489,16 +476,16 @@ where
//
// clippy: not redundant, a FnOnce vs FnMut issue
#[allow(clippy::redundant_closure)]
Some(true) => EitherOf3::A(owner.with(|| view())),
Some(true) => Either::Left(owner.with(|| view())),
#[allow(clippy::unit_arg)]
Some(false) => EitherOf3::B(
Some(false) => Either::Right(
view! { <Redirect path=redirect_path()/> }.into_inner(),
),
None => EitherOf3::C(fallback()),
None => Either::Right(()),
})
}
};
(view! { <Transition fallback>{view}</Transition> }).into_any()
(view! { <Transition>{view}</Transition> }).into_any()
};
NestedRoute::new(path, view).ssr_mode(ssr).child(children)
}

View File

@@ -92,9 +92,6 @@ pub fn A<H>(
/// a trailing slash.
#[prop(optional)]
strict_trailing_slash: bool,
/// If `true`, the router will scroll to the top of the window at the end of navigation. Defaults to `true`.
#[prop(default = true)]
scroll: bool,
/// The nodes or elements to be shown inside the link.
children: Children,
) -> impl IntoView
@@ -107,7 +104,6 @@ where
exact: bool,
children: Children,
strict_trailing_slash: bool,
scroll: bool,
) -> impl IntoView {
let RouterContext { current_url, .. } =
use_context().expect("tried to use <A/> outside a <Router/>.");
@@ -133,7 +129,6 @@ where
href=move || href.get().unwrap_or_default()
target=target
aria-current=move || if is_active() { Some("page") } else { None }
data-noscroll=!scroll
>
{children()}
@@ -142,7 +137,7 @@ where
}
let href = use_resolved_path(move || href.to_href()());
inner(href, target, exact, children, strict_trailing_slash, scroll)
inner(href, target, exact, children, strict_trailing_slash)
}
// Test if `href` is active for `location`. Assumes _both_ `href` and `location` begin with a `'/'`.

View File

@@ -359,8 +359,7 @@ where
let change = LocationChange {
value: to,
replace,
scroll: !a.has_attribute("noscroll")
&& !a.has_attribute("data-noscroll"),
scroll: true,
state: State::new(state),
};

View File

@@ -11,7 +11,7 @@ mod vertical;
use crate::{static_routes::RegenerationFn, Method, SsrMode};
pub use horizontal::*;
pub use nested::*;
use std::{borrow::Cow, collections::HashSet, sync::atomic::Ordering};
use std::{borrow::Cow, collections::HashSet};
pub use vertical::*;
#[derive(Debug)]
@@ -91,16 +91,6 @@ where
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RouteMatchId(pub(crate) u16);
impl RouteMatchId {
/// Creates a new match ID based on the current route ID used in nested route generation.
///
/// In general, you do not need this; it should only be used for custom route matching behavior
/// in a library that creates its own route types.
pub fn new_from_route_id() -> RouteMatchId {
RouteMatchId(ROUTE_ID.fetch_add(1, Ordering::Relaxed))
}
}
pub trait MatchInterface {
type Child: MatchInterface + MatchParams + 'static;

View File

@@ -13,7 +13,7 @@ use std::{
mod tuples;
pub(crate) static ROUTE_ID: AtomicU16 = AtomicU16::new(1);
static ROUTE_ID: AtomicU16 = AtomicU16::new(1);
#[derive(Debug, PartialEq, Eq)]
pub struct NestedRoute<Segments, Children, Data, View> {

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_router_macro"
version = "0.7.2"
version = "0.7.0-rc1"
authors = ["Greg Johnston", "Ben Wishovich"]
license = "MIT"
readme = "../README.md"
@@ -19,6 +19,3 @@ quote = "1.0"
[dev-dependencies]
leptos_router = { path = "../router" }
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

8
server_fn/Cargo.lock generated
View File

@@ -1190,7 +1190,7 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
@@ -1447,7 +1447,7 @@ dependencies = [
[[package]]
name = "radium"
version = "0.7.2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
@@ -1704,7 +1704,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sct"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
@@ -1810,7 +1810,7 @@ dependencies = [
[[package]]
name = "serde_urlencoded"
version = "0.7.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [

View File

@@ -30,7 +30,7 @@ once_cell = "1.20"
actix-web = { version = "4.9", optional = true }
# axum
axum = { version = "0.7.9", optional = true, default-features = false, features = [
axum = { version = "0.7.8", optional = true, default-features = false, features = [
"multipart",
] }
tower = { version = "0.5.1", optional = true }
@@ -49,16 +49,16 @@ http = { version = "1.1" }
ciborium = { version = "0.2.2", optional = true }
postcard = { version = "1", features = ["alloc"], optional = true }
hyper = { version = "1.5", optional = true }
bytes = "1.9"
bytes = "1.8"
http-body-util = { version = "0.1.2", optional = true }
rkyv = { version = "0.8.9", optional = true }
rkyv = { version = "0.8.8", optional = true }
rmp-serde = { version = "1.3.0", optional = true }
# client
gloo-net = { version = "0.6.0", optional = true }
js-sys = { version = "0.3.74", optional = true }
wasm-bindgen = { version = "0.2.97", optional = true }
wasm-bindgen-futures = { version = "0.4.47", optional = true }
js-sys = { version = "0.3.72", optional = true }
wasm-bindgen = { version = "0.2.95", optional = true }
wasm-bindgen-futures = { version = "0.4.45", optional = true }
wasm-streams = { version = "0.4.2", optional = true }
web-sys = { version = "0.3.72", optional = true, features = [
"console",
@@ -229,6 +229,3 @@ skip_feature_sets = [
"rkyv",
],
]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -1,7 +1,7 @@
use crate::{error::ServerFnError, request::Req};
use actix_web::{web::Payload, HttpRequest};
use bytes::Bytes;
use futures::{Stream, StreamExt};
use futures::Stream;
use send_wrapper::SendWrapper;
use std::{borrow::Cow, future::Future};
@@ -91,10 +91,6 @@ where
impl Stream<Item = Result<Bytes, ServerFnError>> + Send,
ServerFnError<CustErr>,
> {
let payload = self.0.take().1;
let stream = payload.map(|res| {
res.map_err(|e| ServerFnError::Deserialization(e.to_string()))
});
Ok(SendWrapper::new(stream))
Ok(futures::stream::once(async { todo!() }))
}
}

View File

@@ -188,20 +188,6 @@ pub fn server_macro_impl(
})
.collect::<Result<Vec<_>>>()?;
// we need to apply the same sort of Actix SendWrapper workaround here
// that we do for the body of the function provided in the trait (see below)
if cfg!(feature = "actix") {
let block = body.block.to_token_stream();
body.block = quote! {
{
#server_fn_path::actix::SendWrapper::new(async move {
#block
})
.await
}
};
}
let dummy = body.to_dummy_output();
let dummy_name = body.to_dummy_ident();
let args = syn::parse::<ServerFnArgs>(args.into())?;

View File

@@ -1,6 +1,6 @@
[package]
name = "tachys"
version = "0.1.2"
version = "0.1.0-rc1"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"
@@ -22,9 +22,9 @@ slotmap = { version = "1.0", optional = true }
oco_ref = { workspace = true, optional = true }
once_cell = "1.20"
paste = "1.0"
wasm-bindgen = "0.2.97"
wasm-bindgen = "0.2.95"
html-escape = "0.2.13"
js-sys = "0.3.74"
js-sys = "0.3.72"
web-sys = { version = "0.3.72", features = [
"Window",
"Document",
@@ -159,7 +159,7 @@ sledgehammer_bindgen = { version = "0.6.0", features = [
"web",
], optional = true }
sledgehammer_utils = { version = "0.3.1", optional = true }
tracing = { version = "0.1.41", optional = true }
tracing = { version = "0.1.40", optional = true }
[dev-dependencies]
tokio-test = "0.4.4"
@@ -196,6 +196,3 @@ skip_feature_sets = [
"delegation",
],
]
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }

View File

@@ -9,9 +9,8 @@ where
E: AsRef<str>,
{
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: std::panic::Location::caller(),
tag: Custom(tag),
attributes: (),
children: (),
}

View File

@@ -25,11 +25,10 @@ macro_rules! html_element_inner {
{
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: std::panic::Location::caller(),
tag: $struct_name,
attributes: (),
children: (),
}
}
@@ -56,17 +55,10 @@ macro_rules! html_element_inner {
At: NextTuple,
<At as NextTuple>::Output<Attr<$crate::html::attribute::[<$attr:camel>], V>>: Attribute,
{
let HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes
} = self;
let HtmlElement { tag, children, attributes } = self;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes: attributes.next_tuple($crate::html::attribute::$attr(value)),
}
@@ -126,16 +118,14 @@ macro_rules! html_self_closing_elements {
paste::paste! {
$(
#[$meta]
#[track_caller]
pub fn $tag() -> HtmlElement<[<$tag:camel>], (), ()>
where
{
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: std::panic::Location::caller(),
attributes: (),
children: (),
tag: [<$tag:camel>],
}
}
@@ -148,6 +138,7 @@ macro_rules! html_self_closing_elements {
impl<At> HtmlElement<[<$tag:camel>], At, ()>
where
At: Attribute,
{
$(
#[doc = concat!("The [`", stringify!($attr), "`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/", stringify!($tag), "#", stringify!($attr) ,") attribute on `<", stringify!($tag), ">`.")]
@@ -160,18 +151,13 @@ macro_rules! html_self_closing_elements {
V: AttributeValue,
At: NextTuple,
<At as NextTuple>::Output<Attr<$crate::html::attribute::[<$attr:camel>], V>>: Attribute,
{
let HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes,
let HtmlElement { tag, children, attributes,
} = self;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes: attributes.next_tuple($crate::html::attribute::$attr(value)),
}
@@ -250,7 +236,7 @@ html_elements! {
/// The `<body>` HTML element represents the content of an HTML document. There can be only one `<body>` element in a document.
body HtmlBodyElement [] true,
/// The `<button>` HTML element represents a clickable button, used to submit forms or anywhere in a document for accessible, standard button functionality.
button HtmlButtonElement [disabled, form, formaction, formenctype, formmethod, formnovalidate, formtarget, name, r#type, value, popovertarget, popovertargetaction] true,
button HtmlButtonElement [disabled, form, formaction, formenctype, formmethod, formnovalidate, formtarget, name, r#type, value] true,
/// Use the HTML `<canvas>` element with either the canvas scripting API or the WebGL API to draw graphics and animations.
canvas HtmlCanvasElement [height, width] true,
/// The `<caption>` HTML element specifies the caption (or title) of a table.
@@ -340,7 +326,7 @@ html_elements! {
/// The `<nav>` HTML element represents a section of a page whose purpose is to provide navigation links, either within the current document or to other documents. Common examples of navigation sections are menus, tables of contents, and indexes.
nav HtmlElement [] true,
/// The `<noscript>` HTML element defines a section of HTML to be inserted if a script type on the page is unsupported or if scripting is currently turned off in the browser.
noscript HtmlElement [] false,
noscript HtmlElement [] true,
/// The `<object>` HTML element represents an external resource, which can be treated as an image, a nested browsing context, or a resource to be handled by a plugin.
object HtmlObjectElement [data, form, height, name, r#type, usemap, width] true,
/// The `<ol>` HTML element represents an ordered list of items — typically rendered as a numbered list.

View File

@@ -1,8 +1,6 @@
#[cfg(any(debug_assertions, leptos_debuginfo))]
use crate::hydration::set_currently_hydrating;
use crate::{
html::attribute::Attribute,
hydration::{failed_to_cast_element, Cursor},
hydration::Cursor,
renderer::{CastFrom, Rndr},
ssr::StreamBuilder,
view::{
@@ -26,14 +24,10 @@ pub use custom::*;
pub use element_ext::*;
pub use elements::*;
pub use inner_html::*;
#[cfg(any(debug_assertions, leptos_debuginfo))]
use std::panic::Location;
/// The typed representation of an HTML element.
#[derive(Debug, PartialEq, Eq)]
pub struct HtmlElement<E, At, Ch> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) tag: E,
pub(crate) attributes: At,
pub(crate) children: Ch,
@@ -42,9 +36,8 @@ pub struct HtmlElement<E, At, Ch> {
impl<E: Clone, At: Clone, Ch: Clone> Clone for HtmlElement<E, At, Ch> {
fn clone(&self) -> Self {
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: self.defined_at,
tag: self.tag.clone(),
attributes: self.attributes.clone(),
children: self.children.clone(),
}
@@ -82,16 +75,14 @@ where
fn child(self, child: NewChild) -> Self::Output {
let HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
attributes,
children,
} = self;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
attributes,
children: children.next_tuple(child.into_render()),
}
@@ -112,15 +103,11 @@ where
attr: NewAttr,
) -> Self::Output<NewAttr> {
let HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
attributes,
children,
} = self;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
attributes: attributes.add_any_attr(attr),
children,
@@ -242,9 +229,8 @@ where
let (attributes, children) =
join(self.attributes.resolve(), self.children.resolve()).await;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: self.defined_at,
tag: self.tag,
attributes,
children,
}
@@ -350,11 +336,6 @@ where
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
set_currently_hydrating(Some(self.defined_at));
}
// non-Static custom elements need special support in templates
// because they haven't been inserted type-wise
if E::TAG.is_empty() && !FROM_SERVER {
@@ -368,9 +349,7 @@ where
cursor.sibling();
}
let el = crate::renderer::types::Element::cast_from(cursor.current())
.unwrap_or_else(|| {
failed_to_cast_element(E::TAG, cursor.current())
});
.unwrap();
let attrs = self.attributes.hydrate::<FROM_SERVER>(&el);

View File

@@ -2,11 +2,8 @@ use self::attribute::Attribute;
use crate::{
hydration::Cursor,
no_attrs,
prelude::{AddAnyAttr, Mountable},
renderer::{
dom::{Element, Node},
CastFrom, Rndr,
},
prelude::AddAnyAttr,
renderer::{CastFrom, Rndr},
view::{Position, PositionState, Render, RenderHtml},
};
use std::borrow::Cow;
@@ -93,41 +90,14 @@ impl InertElement {
}
}
/// Retained view state for [`InertElement`].
pub struct InertElementState(Cow<'static, str>, Element);
impl Mountable for InertElementState {
fn unmount(&mut self) {
self.1.unmount();
}
fn mount(&mut self, parent: &Element, marker: Option<&Node>) {
self.1.mount(parent, marker)
}
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
self.1.insert_before_this(child)
}
}
impl Render for InertElement {
type State = InertElementState;
type State = crate::renderer::types::Element;
fn build(self) -> Self::State {
let el = Rndr::create_element_from_html(&self.html);
InertElementState(self.html, el)
Rndr::create_element_from_html(&self.html)
}
fn rebuild(self, state: &mut Self::State) {
let InertElementState(prev, el) = state;
if &self.html != prev {
let mut new_el = Rndr::create_element_from_html(&self.html);
el.insert_before_this(&mut new_el);
el.unmount();
*el = new_el;
*prev = self.html;
}
}
fn rebuild(self, _state: &mut Self::State) {}
}
impl AddAnyAttr for InertElement {
@@ -187,6 +157,6 @@ impl RenderHtml for InertElement {
let el = crate::renderer::types::Element::cast_from(cursor.current())
.unwrap();
position.set(Position::NextChild);
InertElementState(self.html, el)
el
}
}

View File

@@ -2,10 +2,7 @@ use crate::{
renderer::{CastFrom, Rndr},
view::{Position, PositionState},
};
#[cfg(any(debug_assertions, leptos_debuginfo))]
use std::cell::Cell;
use std::{cell::RefCell, panic::Location, rc::Rc};
use web_sys::{Comment, Element, Node, Text};
use std::{cell::RefCell, rc::Rc};
/// Hydration works by walking over the DOM, adding interactivity as needed.
///
@@ -98,121 +95,13 @@ where
}
let marker = self.current();
position.set(Position::NextChild);
crate::renderer::types::Placeholder::cast_from(marker.clone())
.unwrap_or_else(|| failed_to_cast_marker_node(marker))
}
}
#[cfg(any(debug_assertions, leptos_debuginfo))]
thread_local! {
static CURRENTLY_HYDRATING: Cell<Option<&'static Location<'static>>> = const { Cell::new(None) };
}
pub(crate) fn set_currently_hydrating(
location: Option<&'static Location<'static>>,
) {
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
CURRENTLY_HYDRATING.set(location);
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
{
_ = location;
}
}
pub(crate) fn failed_to_cast_element(tag_name: &str, node: Node) -> Element {
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
{
_ = node;
unreachable!();
}
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
let hydrating = CURRENTLY_HYDRATING
.take()
.map(|n| n.to_string())
.unwrap_or_else(|| "{unknown}".to_string());
web_sys::console::error_3(
&wasm_bindgen::JsValue::from_str(&format!(
"A hydration error occurred while trying to hydrate an \
element defined at {hydrating}.\n\nThe framework expected an \
HTML <{tag_name}> element, but found this instead: ",
)),
&node,
&wasm_bindgen::JsValue::from_str(
"\n\nThe hydration mismatch may have occurred slightly \
earlier, but this is the first time the framework found a \
node of an unexpected type.",
),
);
panic!(
"Unrecoverable hydration error. Please read the error message \
directly above this for more details."
);
}
}
pub(crate) fn failed_to_cast_marker_node(node: Node) -> Comment {
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
{
_ = node;
unreachable!();
}
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
let hydrating = CURRENTLY_HYDRATING
.take()
.map(|n| n.to_string())
.unwrap_or_else(|| "{unknown}".to_string());
web_sys::console::error_3(
&wasm_bindgen::JsValue::from_str(&format!(
"A hydration error occurred while trying to hydrate an \
element defined at {hydrating}.\n\nThe framework expected a \
marker node, but found this instead: ",
)),
&node,
&wasm_bindgen::JsValue::from_str(
"\n\nThe hydration mismatch may have occurred slightly \
earlier, but this is the first time the framework found a \
node of an unexpected type.",
),
);
panic!(
"Unrecoverable hydration error. Please read the error message \
directly above this for more details."
);
}
}
pub(crate) fn failed_to_cast_text_node(node: Node) -> Text {
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
{
_ = node;
unreachable!();
}
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
let hydrating = CURRENTLY_HYDRATING
.take()
.map(|n| n.to_string())
.unwrap_or_else(|| "{unknown}".to_string());
web_sys::console::error_3(
&wasm_bindgen::JsValue::from_str(&format!(
"A hydration error occurred while trying to hydrate an \
element defined at {hydrating}.\n\nThe framework expected a \
text node, but found this instead: ",
)),
&node,
&wasm_bindgen::JsValue::from_str(
"\n\nThe hydration mismatch may have occurred slightly \
earlier, but this is the first time the framework found a \
node of an unexpected type.",
),
);
panic!(
"Unrecoverable hydration error. Please read the error message \
directly above this for more details."
);
crate::renderer::types::Placeholder::cast_from(marker)
.expect("could not convert current node into marker node")
/*let marker2 = marker.clone();
Rndr::Placeholder::cast_from(marker).unwrap_or_else(|| {
crate::dom::log("expecting to find a marker. instead, found");
Rndr::log_node(&marker2);
panic!("oops.");
})*/
}
}

View File

@@ -87,7 +87,7 @@ impl<T> UnwrapOrDebug for Result<T, JsValue> {
#[track_caller]
fn or_debug(self, el: &Node, name: &'static str) {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
if let Err(err) = self {
let location = std::panic::Location::caller();
@@ -101,7 +101,7 @@ impl<T> UnwrapOrDebug for Result<T, JsValue> {
);
}
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
_ = self;
}
@@ -113,7 +113,7 @@ impl<T> UnwrapOrDebug for Result<T, JsValue> {
el: &Node,
name: &'static str,
) -> Option<Self::Output> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
#[cfg(debug_assertions)]
{
if let Err(err) = &self {
let location = std::panic::Location::caller();
@@ -128,7 +128,7 @@ impl<T> UnwrapOrDebug for Result<T, JsValue> {
}
self.ok()
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
#[cfg(not(debug_assertions))]
{
self.ok()
}
@@ -139,7 +139,7 @@ impl<T> UnwrapOrDebug for Result<T, JsValue> {
#[macro_export]
macro_rules! or_debug {
($action:expr, $el:expr, $label:literal) => {
if cfg!(any(debug_assertions, leptos_debuginfo)) {
if cfg!(debug_assertions) {
$crate::UnwrapOrDebug::or_debug($action, $el, $label);
} else {
_ = $action;
@@ -151,7 +151,7 @@ macro_rules! or_debug {
#[macro_export]
macro_rules! ok_or_debug {
($action:expr, $el:expr, $label:literal) => {
if cfg!(any(debug_assertions, leptos_debuginfo)) {
if cfg!(debug_assertions) {
$crate::UnwrapOrDebug::ok_or_debug($action, $el, $label)
} else {
$action.ok()

View File

@@ -22,17 +22,10 @@ macro_rules! mathml_global {
At: NextTuple,
<At as NextTuple>::Output<Attr<$crate::html::attribute::[<$attr:camel>], V>>: Attribute,
{
let HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes
} = self;
let HtmlElement { tag, children, attributes } = self;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes: attributes.next_tuple($crate::html::attribute::$attr(value)),
}
@@ -53,11 +46,10 @@ macro_rules! mathml_elements {
{
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: std::panic::Location::caller(),
tag: [<$tag:camel>],
attributes: (),
children: (),
}
}
@@ -92,17 +84,10 @@ macro_rules! mathml_elements {
At: NextTuple,
<At as NextTuple>::Output<Attr<$crate::html::attribute::[<$attr:camel>], V>>: Attribute,
{
let HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes
} = self;
let HtmlElement { tag, children, attributes } = self;
HtmlElement {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at,
tag,
children,
attributes: attributes.next_tuple($crate::html::attribute::$attr(value)),
}

View File

@@ -9,15 +9,13 @@ use crate::{
renderer::{types::Element, RemoveEventHandler},
view::{Position, ToTemplate},
};
#[cfg(feature = "reactive_stores")]
use reactive_graph::owner::Storage;
use reactive_graph::{
signal::{ReadSignal, RwSignal, WriteSignal},
traits::{Get, Update},
wrappers::read::Signal,
};
#[cfg(feature = "reactive_stores")]
use reactive_stores::{ArcField, Field, KeyedSubfield, Subfield};
use reactive_stores::{KeyedSubfield, Subfield};
use send_wrapper::SendWrapper;
use wasm_bindgen::JsValue;
@@ -360,21 +358,6 @@ where
}
}
#[cfg(feature = "reactive_stores")]
impl<T, S> IntoSplitSignal for Field<T, S>
where
Self: Get<Value = T> + Update<Value = T> + Clone,
S: Storage<ArcField<T>>,
{
type Value = T;
type Read = Self;
type Write = Self;
fn into_split_signal(self) -> (Self::Read, Self::Write) {
(self, self)
}
}
#[cfg(feature = "reactive_stores")]
impl<Inner, Prev, K, T> IntoSplitSignal for KeyedSubfield<Inner, Prev, K, T>
where

View File

@@ -1,17 +1,12 @@
use crate::html::{element::ElementType, node_ref::NodeRefContainer};
use reactive_graph::{
effect::Effect,
signal::{
guards::{Derefable, ReadGuard},
RwSignal,
},
traits::{
DefinedAt, Get, Notify, ReadUntracked, Set, Track, UntrackableGuard,
Write,
},
traits::{DefinedAt, ReadUntracked, Set, Track},
};
use send_wrapper::SendWrapper;
use std::{cell::Cell, ops::DerefMut};
use wasm_bindgen::JsCast;
/// A reactive reference to a DOM node that can be used with the `node_ref` attribute.
@@ -31,25 +26,6 @@ where
pub fn new() -> Self {
Self(RwSignal::new(None))
}
/// Runs the provided closure when the `NodeRef` has been connected
/// with its element.
#[inline(always)]
pub fn on_load<F>(self, f: F)
where
E: 'static,
F: FnOnce(E::Output) + 'static,
E: ElementType,
E::Output: JsCast + Clone + 'static,
{
let f = Cell::new(Some(f));
Effect::new(move |_| {
if let Some(node_ref) = self.get() {
f.take().unwrap()(node_ref);
}
});
}
}
impl<E> Default for NodeRef<E>
@@ -102,34 +78,6 @@ where
}
}
impl<E> Notify for NodeRef<E>
where
E: ElementType,
E::Output: JsCast + Clone + 'static,
{
fn notify(&self) {
self.0.notify();
}
}
impl<E> Write for NodeRef<E>
where
E: ElementType,
E::Output: JsCast + Clone + 'static,
{
type Value = Option<SendWrapper<E::Output>>;
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
self.0.try_write()
}
fn try_write_untracked(
&self,
) -> Option<impl DerefMut<Target = Self::Value>> {
self.0.try_write_untracked()
}
}
impl<E> ReadUntracked for NodeRef<E>
where
E: ElementType,

Some files were not shown because too many files have changed in this diff Show More