Skip to content

Commit

Permalink
Binary size wins (#3566)
Browse files Browse the repository at this point in the history
* Random binary size opts

* [autofix.ci] apply automated fixes

* Stop autofixer removing an import

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
zakstucke and autofix-ci[bot] authored Feb 10, 2025
1 parent b4e683d commit 6ad300c
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 80 deletions.
94 changes: 52 additions & 42 deletions reactive_graph/src/effect/render_effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
},
owner::Owner,
};
use any_spawner::Executor;
use futures::StreamExt;
use or_poisoned::OrPoisoned;
use std::{
Expand Down Expand Up @@ -54,65 +53,76 @@ where
{
/// Creates a new render effect, which immediately runs `fun`.
pub fn new(fun: impl FnMut(Option<T>) -> T + 'static) -> Self {
Self::new_with_value(fun, None)
Self::new_with_value_erased(Box::new(fun), None)
}

/// Creates a new render effect with an initial value.
pub fn new_with_value(
fun: impl FnMut(Option<T>) -> T + 'static,
initial_value: Option<T>,
) -> Self {
fn erased<T>(
mut fun: Box<dyn FnMut(Option<T>) -> T + 'static>,
initial_value: Option<T>,
) -> RenderEffect<T> {
let (observer, mut rx) = channel();
let value = Arc::new(RwLock::new(None::<T>));
Self::new_with_value_erased(Box::new(fun), initial_value)
}

fn new_with_value_erased(
mut fun: Box<dyn FnMut(Option<T>) -> T + 'static>,
initial_value: Option<T>,
) -> Self {
// codegen optimisation:
fn prep() -> (Owner, Arc<RwLock<EffectInner>>, crate::channel::Receiver)
{
let (observer, rx) = channel();
let owner = Owner::new();
let inner = Arc::new(RwLock::new(EffectInner {
dirty: false,
observer,
sources: SourceSet::new(),
}));
(owner, inner, rx)
}

let initial_value = cfg!(feature = "effects").then(|| {
owner.with(|| {
inner
.to_any_subscriber()
.with_observer(|| fun(initial_value))
})
});
*value.write().or_poisoned() = initial_value;

if cfg!(feature = "effects") {
Executor::spawn_local({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();

async move {
while rx.next().await.is_some() {
if subscriber.with_observer(|| {
subscriber.update_if_necessary()
}) {
subscriber.clear_sources(&subscriber);

let old_value = mem::take(
&mut *value.write().or_poisoned(),
);
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
}
let (owner, inner, mut rx) = prep();

let value = Arc::new(RwLock::new(None::<T>));

#[cfg(not(feature = "effects"))]
{
let _ = initial_value;
let _ = owner;
let _ = &mut rx;
let _ = &mut fun;
}

#[cfg(feature = "effects")]
{
let subscriber = inner.to_any_subscriber();
*value.write().or_poisoned() = Some(
owner.with(|| subscriber.with_observer(|| fun(initial_value))),
);

any_spawner::Executor::spawn_local({
let value = Arc::clone(&value);

async move {
while rx.next().await.is_some() {
if subscriber
.with_observer(|| subscriber.update_if_necessary())
{
subscriber.clear_sources(&subscriber);

let old_value =
mem::take(&mut *value.write().or_poisoned());
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
}
}
});
}

RenderEffect { value, inner }
}
});
}

erased(Box::new(fun), initial_value)
RenderEffect { value, inner }
}

/// Mutably accesses the current value.
Expand Down
32 changes: 22 additions & 10 deletions reactive_graph/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,17 +206,29 @@ impl Owner {

/// Runs the given function with this as the current `Owner`.
pub fn with<T>(&self, fun: impl FnOnce() -> T) -> T {
let prev = {
OWNER.with(|o| {
mem::replace(&mut *o.borrow_mut(), Some(self.clone()))
})
};
#[cfg(feature = "sandboxed-arenas")]
Arena::set(&self.inner.read().or_poisoned().arena);
// codegen optimisation:
fn inner_1(self_: &Owner) -> Option<Owner> {
let prev = {
OWNER.with(|o| {
mem::replace(&mut *o.borrow_mut(), Some(self_.clone()))
})
};
#[cfg(feature = "sandboxed-arenas")]
Arena::set(&self_.inner.read().or_poisoned().arena);
prev
}
let prev = inner_1(self);

let val = fun();
OWNER.with(|o| {
*o.borrow_mut() = prev;
});

// monomorphisation optimisation:
fn inner_2(prev: Option<Owner>) {
OWNER.with(|o| {
*o.borrow_mut() = prev;
});
}
inner_2(prev);

val
}

Expand Down
68 changes: 46 additions & 22 deletions tachys/src/html/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,27 +360,43 @@ 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 {
panic!("Custom elements are not supported in ViewTemplate.");
}

let curr_position = position.get();
if curr_position == Position::FirstChild {
cursor.child();
} else if curr_position != Position::Current {
cursor.sibling();
// codegen optimisation:
fn inner_1(
cursor: &Cursor,
position: &PositionState,
tag_name: &str,
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: &'static std::panic::Location<'static>,
) -> crate::renderer::types::Element {
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
set_currently_hydrating(Some(defined_at));
}

let curr_position = position.get();
if curr_position == Position::FirstChild {
cursor.child();
} else if curr_position != Position::Current {
cursor.sibling();
}
crate::renderer::types::Element::cast_from(cursor.current())
.unwrap_or_else(|| {
failed_to_cast_element(tag_name, cursor.current())
})
}
let el = crate::renderer::types::Element::cast_from(cursor.current())
.unwrap_or_else(|| {
failed_to_cast_element(E::TAG, cursor.current())
});
let el = inner_1(
cursor,
position,
E::TAG,
#[cfg(any(debug_assertions, leptos_debuginfo))]
self.defined_at,
);

let attrs = self.attributes.hydrate::<FROM_SERVER>(&el);

Expand All @@ -392,14 +408,22 @@ where
Some(self.children.hydrate::<FROM_SERVER>(cursor, position))
};

// go to next sibling
cursor.set(
<crate::renderer::types::Element as AsRef<
crate::renderer::types::Node,
>>::as_ref(&el)
.clone(),
);
position.set(Position::NextChild);
// codegen optimisation:
fn inner_2(
cursor: &Cursor,
position: &PositionState,
el: &crate::renderer::types::Element,
) {
// go to next sibling
cursor.set(
<crate::renderer::types::Element as AsRef<
crate::renderer::types::Node,
>>::as_ref(el)
.clone(),
);
position.set(Position::NextChild);
}
inner_2(cursor, position, &el);

ElementState {
el,
Expand Down
31 changes: 25 additions & 6 deletions tachys/src/reactive_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,32 @@ where
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
let cursor = cursor.clone();
let position = position.clone();
let hook = throw_error::get_error_hook();
/// codegen optimisation:
fn prep(
cursor: &Cursor,
position: &PositionState,
) -> (
Cursor,
PositionState,
Option<Arc<dyn throw_error::ErrorHook>>,
) {
let cursor = cursor.clone();
let position = position.clone();
let hook = throw_error::get_error_hook();
(cursor, position, hook)
}
let (cursor, position, hook) = prep(cursor, position);

RenderEffect::new(move |prev| {
let _guard = hook
.as_ref()
.map(|h| throw_error::set_error_hook(Arc::clone(h)));
/// codegen optimisation:
fn get_guard(
hook: &Option<Arc<dyn throw_error::ErrorHook>>,
) -> Option<throw_error::ResetErrorHookOnDrop> {
hook.as_ref()
.map(|h| throw_error::set_error_hook(Arc::clone(h)))
}
let _guard = get_guard(&hook);

let value = self.invoke();
if let Some(mut state) = prev {
value.rebuild(&mut state);
Expand Down

0 comments on commit 6ad300c

Please sign in to comment.