Merge branch 'master' into jk/loop-allocation-strategy

This commit is contained in:
Jonathan Kelley committed 2023-10-17 15:27:20 -07:00
commit 55ad41b392
25 files changed
+160 -11

No files matched your search

+1 -1
View File
@@ -312,7 +312,7 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result<BuildResul
if !config.out_dir.is_dir() { if !config.out_dir.is_dir() {
create_dir_all(&config.out_dir)?; create_dir_all(&config.out_dir)?;
} }
copy(res_path, &config.out_dir.join(target_file))?; copy(res_path, config.out_dir.join(target_file))?;
// this code will copy all public file to the output dir // this code will copy all public file to the output dir
if config.asset_dir.is_dir() { if config.asset_dir.is_dir() {
+1
View File
@@ -28,6 +28,7 @@ impl CallbackApi {
} }
} }
#[must_use]
pub fn use_atom_context(cx: &ScopeState) -> &CallbackApi { pub fn use_atom_context(cx: &ScopeState) -> &CallbackApi {
todo!() todo!()
} }
+1
View File
@@ -13,6 +13,7 @@ use std::{
/// ///
/// ///
/// ///
#[must_use]
pub fn use_atom_ref<'a, T: 'static>( pub fn use_atom_ref<'a, T: 'static>(
cx: &'a ScopeState, cx: &'a ScopeState,
atom: &'static AtomRef<T>, atom: &'static AtomRef<T>,
+2
View File
@@ -2,10 +2,12 @@ use crate::{use_atom_root, AtomId, AtomRoot, Readable};
use dioxus_core::{ScopeId, ScopeState}; use dioxus_core::{ScopeId, ScopeState};
use std::rc::Rc; use std::rc::Rc;
#[must_use]
pub fn use_read<V: 'static>(cx: &ScopeState, f: impl Readable<V>) -> &V { pub fn use_read<V: 'static>(cx: &ScopeState, f: impl Readable<V>) -> &V {
use_read_rc(cx, f).as_ref() use_read_rc(cx, f).as_ref()
} }
#[must_use]
pub fn use_read_rc<V: 'static>(cx: &ScopeState, f: impl Readable<V>) -> &Rc<V> { pub fn use_read_rc<V: 'static>(cx: &ScopeState, f: impl Readable<V>) -> &Rc<V> {
let root = use_atom_root(cx); let root = use_atom_root(cx);
+1
View File
@@ -2,6 +2,7 @@ use crate::{use_atom_root, Writable};
use dioxus_core::ScopeState; use dioxus_core::ScopeState;
use std::rc::Rc; use std::rc::Rc;
#[must_use]
pub fn use_set<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &Rc<dyn Fn(T)> { pub fn use_set<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &Rc<dyn Fn(T)> {
let root = use_atom_root(cx); let root = use_atom_root(cx);
cx.use_hook(|| { cx.use_hook(|| {
+1
View File
@@ -30,6 +30,7 @@ use std::{
/// )) /// ))
/// } /// }
/// ``` /// ```
#[must_use]
pub fn use_atom_state<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &AtomState<T> { pub fn use_atom_state<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &AtomState<T> {
let root = crate::use_atom_root(cx); let root = crate::use_atom_root(cx);
@@ -22,6 +22,7 @@ use std::sync::Arc;
/// will be allowed to continue /// will be allowed to continue
/// ///
/// - dependencies: a tuple of references to values that are PartialEq + Clone /// - dependencies: a tuple of references to values that are PartialEq + Clone
#[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
pub fn use_server_future<T, F, D>( pub fn use_server_future<T, F, D>(
cx: &ScopeState, cx: &ScopeState,
dependencies: D, dependencies: D,
+4 -4
View File
@@ -184,7 +184,7 @@ impl<T: 'static> GenerationalBox<T> {
} }
/// Try to read the value. Returns None if the value is no longer valid. /// Try to read the value. Returns None if the value is no longer valid.
pub fn try_read(&self) -> Option<Ref<'_, T>> { pub fn try_read(&self) -> Option<Ref<'static, T>> {
self.validate() self.validate()
.then(|| { .then(|| {
Ref::filter_map(self.raw.data.borrow(), |any| { Ref::filter_map(self.raw.data.borrow(), |any| {
@@ -196,12 +196,12 @@ impl<T: 'static> GenerationalBox<T> {
} }
/// Read the value. Panics if the value is no longer valid. /// Read the value. Panics if the value is no longer valid.
pub fn read(&self) -> Ref<'_, T> { pub fn read(&self) -> Ref<'static, T> {
self.try_read().unwrap() self.try_read().unwrap()
} }
/// Try to write the value. Returns None if the value is no longer valid. /// Try to write the value. Returns None if the value is no longer valid.
pub fn try_write(&self) -> Option<RefMut<'_, T>> { pub fn try_write(&self) -> Option<RefMut<'static, T>> {
self.validate() self.validate()
.then(|| { .then(|| {
RefMut::filter_map(self.raw.data.borrow_mut(), |any| { RefMut::filter_map(self.raw.data.borrow_mut(), |any| {
@@ -213,7 +213,7 @@ impl<T: 'static> GenerationalBox<T> {
} }
/// Write the value. Panics if the value is no longer valid. /// Write the value. Panics if the value is no longer valid.
pub fn write(&self) -> RefMut<'_, T> { pub fn write(&self) -> RefMut<'static, T> {
self.try_write().unwrap() self.try_write().unwrap()
} }
+2
View File
@@ -37,6 +37,7 @@ use std::{
/// } /// }
/// } /// }
/// ``` /// ```
#[must_use]
pub fn use_tracked_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> &Tracked<T> { pub fn use_tracked_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> &Tracked<T> {
cx.use_hook(|| { cx.use_hook(|| {
let init = init(); let init = init();
@@ -160,6 +161,7 @@ impl<I> Drop for Tracker<I> {
} }
} }
#[must_use = "Consider using the `use_effect` hook to rerun an effect whenever the tracked state changes if you don't need the result of the computation"]
pub fn use_selector<I: 'static, O: Clone + PartialEq + 'static>( pub fn use_selector<I: 'static, O: Clone + PartialEq + 'static>(
cx: &ScopeState, cx: &ScopeState,
tracked: &Tracked<I>, tracked: &Tracked<I>,
+1
View File
@@ -24,6 +24,7 @@ macro_rules! use_callback {
) )
}; };
} }
pub fn use_callback<T, R, F>(cx: &ScopeState, make: impl FnOnce() -> R) -> impl FnMut(T) + '_ pub fn use_callback<T, R, F>(cx: &ScopeState, make: impl FnOnce() -> R) -> impl FnMut(T) + '_
where where
R: FnMut(T) -> F + 'static, R: FnMut(T) -> F + 'static,
+1
View File
@@ -3,6 +3,7 @@ use dioxus_core::ScopeState;
/// Consume some context in the tree, providing a sharable handle to the value /// Consume some context in the tree, providing a sharable handle to the value
/// ///
/// Does not regenerate the value if the value is changed at the parent. /// Does not regenerate the value if the value is changed at the parent.
#[must_use]
pub fn use_context<T: 'static + Clone>(cx: &ScopeState) -> Option<&T> { pub fn use_context<T: 'static + Clone>(cx: &ScopeState) -> Option<&T> {
cx.use_hook(|| cx.consume_context::<T>()).as_ref() cx.use_hook(|| cx.consume_context::<T>()).as_ref()
} }
+1
View File
@@ -79,6 +79,7 @@ where
/// Get a handle to a coroutine higher in the tree /// Get a handle to a coroutine higher in the tree
/// ///
/// See the docs for [`use_coroutine`] for more details. /// See the docs for [`use_coroutine`] for more details.
#[must_use]
pub fn use_coroutine_handle<M: 'static>(cx: &ScopeState) -> Option<&Coroutine<M>> { pub fn use_coroutine_handle<M: 'static>(cx: &ScopeState) -> Option<&Coroutine<M>> {
cx.use_hook(|| cx.consume_context::<Coroutine<M>>()) cx.use_hook(|| cx.consume_context::<Coroutine<M>>())
.as_ref() .as_ref()
+1
View File
@@ -28,6 +28,7 @@ use crate::UseFutureDep;
/// render!(Calculator { number: 0 }) /// render!(Calculator { number: 0 })
/// } /// }
/// ``` /// ```
#[must_use = "Consider using `use_effect` to run rerun a callback when dependencies change"]
pub fn use_memo<T, D>(cx: &ScopeState, dependencies: D, callback: impl FnOnce(D::Out) -> T) -> &T pub fn use_memo<T, D>(cx: &ScopeState, dependencies: D, callback: impl FnOnce(D::Out) -> T) -> &T
where where
T: 'static, T: 'static,
+1
View File
@@ -110,6 +110,7 @@ use std::{
/// } /// }
/// }) /// })
/// ``` /// ```
#[must_use]
pub fn use_ref<T: 'static>(cx: &ScopeState, initialize_refcell: impl FnOnce() -> T) -> &UseRef<T> { pub fn use_ref<T: 'static>(cx: &ScopeState, initialize_refcell: impl FnOnce() -> T) -> &UseRef<T> {
let hook = cx.use_hook(|| UseRef { let hook = cx.use_hook(|| UseRef {
update: cx.schedule_update(), update: cx.schedule_update(),
+1
View File
@@ -158,6 +158,7 @@ impl<T> ProvidedStateInner<T> {
/// Any time a component calls `write`, every consumer of the state will be notified - excluding the provider. /// Any time a component calls `write`, every consumer of the state will be notified - excluding the provider.
/// ///
/// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified. /// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified.
#[must_use]
pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<&UseSharedState<T>> { pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<&UseSharedState<T>> {
let state_owner: &mut Option<UseSharedStateOwner<T>> = &mut *cx.use_hook(move || { let state_owner: &mut Option<UseSharedStateOwner<T>> = &mut *cx.use_hook(move || {
let scope_id = cx.scope_id(); let scope_id = cx.scope_id();
+1
View File
@@ -30,6 +30,7 @@ use std::{
/// )) /// ))
/// } /// }
/// ``` /// ```
#[must_use]
pub fn use_state<T: 'static>( pub fn use_state<T: 'static>(
cx: &ScopeState, cx: &ScopeState,
initial_state_fn: impl FnOnce() -> T, initial_state_fn: impl FnOnce() -> T,
+1
View File
@@ -33,6 +33,7 @@ type EvalCreator = Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
/// parts is practically asking for a hacker to find an XSS vulnerability in /// parts is practically asking for a hacker to find an XSS vulnerability in
/// it. **This applies especially to web targets, where the JavaScript context /// it. **This applies especially to web targets, where the JavaScript context
/// has access to most, if not all of your application data.** /// has access to most, if not all of your application data.**
#[must_use]
pub fn use_eval(cx: &ScopeState) -> &EvalCreator { pub fn use_eval(cx: &ScopeState) -> &EvalCreator {
&*cx.use_hook(|| { &*cx.use_hook(|| {
let eval_provider = cx let eval_provider = cx
@@ -48,6 +48,7 @@ use crate::prelude::{Navigator, RouterContext};
/// # let mut vdom = VirtualDom::new(App); /// # let mut vdom = VirtualDom::new(App);
/// # let _ = vdom.rebuild(); /// # let _ = vdom.rebuild();
/// ``` /// ```
#[must_use]
pub fn use_navigator(cx: &ScopeState) -> &Navigator { pub fn use_navigator(cx: &ScopeState) -> &Navigator {
&*cx.use_hook(|| { &*cx.use_hook(|| {
let router = cx let router = cx
+1
View File
@@ -46,6 +46,7 @@ use crate::utils::use_router_internal::use_router_internal;
/// # let _ = vdom.rebuild(); /// # let _ = vdom.rebuild();
/// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><h2>Current Path</h2><p>/</p>") /// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><h2>Current Path</h2><p>/</p>")
/// ``` /// ```
#[must_use]
pub fn use_route<R: Routable + Clone>(cx: &ScopeState) -> Option<R> { pub fn use_route<R: Routable + Clone>(cx: &ScopeState) -> Option<R> {
match use_router_internal(cx) { match use_router_internal(cx) {
Some(r) => Some(r.current()), Some(r) => Some(r.current()),
+1
View File
@@ -3,6 +3,7 @@ use dioxus::prelude::ScopeState;
use crate::{prelude::RouterContext, utils::use_router_internal::use_router_internal}; use crate::{prelude::RouterContext, utils::use_router_internal::use_router_internal};
#[deprecated = "prefer the use_navigator or use_route functions"] #[deprecated = "prefer the use_navigator or use_route functions"]
#[must_use]
/// A hook that provides access to information about the router. /// A hook that provides access to information about the router.
pub fn use_router(cx: &ScopeState) -> &RouterContext { pub fn use_router(cx: &ScopeState) -> &RouterContext {
use_router_internal(cx) use_router_internal(cx)
+1 -1
View File
@@ -109,7 +109,7 @@ pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
let upper_cammel_case_name = Converter::new() let upper_cammel_case_name = Converter::new()
.from_case(Case::Snake) .from_case(Case::Snake)
.to_case(Case::UpperCamel) .to_case(Case::UpperCamel)
.convert(&sig.ident.to_string()); .convert(sig.ident.to_string());
args.struct_name = Some(Ident::new(&upper_cammel_case_name, sig.ident.span())); args.struct_name = Some(Ident::new(&upper_cammel_case_name, sig.ident.span()));
} }
let struct_name = args.struct_name.as_ref().unwrap(); let struct_name = args.struct_name.as_ref().unwrap();
+38 -3
View File
@@ -1,5 +1,7 @@
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
@@ -120,17 +122,17 @@ impl<T: 'static> CopyValue<T> {
} }
/// Read the value. If the value has been dropped, this will panic. /// Read the value. If the value has been dropped, this will panic.
pub fn read(&self) -> Ref<'_, T> { pub fn read(&self) -> Ref<'static, T> {
self.value.read() self.value.read()
} }
/// Try to write the value. If the value has been dropped, this will return None. /// Try to write the value. If the value has been dropped, this will return None.
pub fn try_write(&self) -> Option<RefMut<'_, T>> { pub fn try_write(&self) -> Option<RefMut<'static, T>> {
self.value.try_write() self.value.try_write()
} }
/// Write the value. If the value has been dropped, this will panic. /// Write the value. If the value has been dropped, this will panic.
pub fn write(&self) -> RefMut<'_, T> { pub fn write(&self) -> RefMut<'static, T> {
self.value.write() self.value.write()
} }
@@ -164,3 +166,36 @@ impl<T: 'static> PartialEq for CopyValue<T> {
self.value.ptr_eq(&other.value) self.value.ptr_eq(&other.value)
} }
} }
impl<T> Deref for CopyValue<T> {
type Target = dyn Fn() -> Ref<'static, T>;
fn deref(&self) -> &Self::Target {
// https://github.com/dtolnay/case-studies/tree/master/callable-types
// First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
let uninit_callable = MaybeUninit::<Self>::uninit();
// Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
// Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
let size_of_closure = std::mem::size_of_val(&uninit_closure);
assert_eq!(size_of_closure, std::mem::size_of::<Self>());
// Then cast the lifetime of the closure to the lifetime of &self.
fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
b
}
let reference_to_closure = cast_lifetime(
{
// The real closure that we will never use.
&uninit_closure
},
// We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self.
unsafe { std::mem::transmute(self) },
);
// Cast the closure to a trait object.
reference_to_closure as &Self::Target
}
}
+2
View File
@@ -21,6 +21,7 @@ use crate::{get_effect_stack, signal::SignalData, CopyValue, Effect, ReadOnlySig
/// render! { "{double}" } /// render! { "{double}" }
/// } /// }
/// ``` /// ```
#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
pub fn use_selector<R: PartialEq>( pub fn use_selector<R: PartialEq>(
cx: &ScopeState, cx: &ScopeState,
f: impl FnMut() -> R + 'static, f: impl FnMut() -> R + 'static,
@@ -44,6 +45,7 @@ pub fn use_selector<R: PartialEq>(
/// render! { "{double}" } /// render! { "{double}" }
/// } /// }
/// ``` /// ```
#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>( pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
cx: &ScopeState, cx: &ScopeState,
dependencies: D, dependencies: D,
+70 -2
View File
@@ -1,5 +1,6 @@
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, cell::{Ref, RefCell, RefMut},
mem::MaybeUninit,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
rc::Rc, rc::Rc,
sync::Arc, sync::Arc,
@@ -43,6 +44,7 @@ use crate::{CopyValue, Effect};
/// } /// }
/// } /// }
/// ``` /// ```
#[must_use]
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> { pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
*cx.use_hook(|| Signal::new(f())) *cx.use_hook(|| Signal::new(f()))
} }
@@ -275,6 +277,39 @@ impl<T: 'static> PartialEq for Signal<T> {
} }
} }
impl<T> Deref for Signal<T> {
type Target = dyn Fn() -> Ref<'static, T>;
fn deref(&self) -> &Self::Target {
// https://github.com/dtolnay/case-studies/tree/master/callable-types
// First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
let uninit_callable = MaybeUninit::<Self>::uninit();
// Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
// Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
let size_of_closure = std::mem::size_of_val(&uninit_closure);
assert_eq!(size_of_closure, std::mem::size_of::<Self>());
// Then cast the lifetime of the closure to the lifetime of &self.
fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
b
}
let reference_to_closure = cast_lifetime(
{
// The real closure that we will never use.
&uninit_closure
},
// We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self.
unsafe { std::mem::transmute(self) },
);
// Cast the closure to a trait object.
reference_to_closure as &Self::Target
}
}
struct SignalSubscriberDrop<T: 'static> { struct SignalSubscriberDrop<T: 'static> {
signal: Signal<T>, signal: Signal<T>,
} }
@@ -312,7 +347,7 @@ impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
} }
} }
impl<'a, T: 'static> Deref for Write<'a, T> { impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
type Target = T; type Target = T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@@ -320,7 +355,7 @@ impl<'a, T: 'static> Deref for Write<'a, T> {
} }
} }
impl<T> DerefMut for Write<'_, T> { impl<T, I> DerefMut for Write<'_, T, I> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.write &mut self.write
} }
@@ -365,3 +400,36 @@ impl<T: 'static> PartialEq for ReadOnlySignal<T> {
self.inner == other.inner self.inner == other.inner
} }
} }
impl<T> Deref for ReadOnlySignal<T> {
type Target = dyn Fn() -> Ref<'static, T>;
fn deref(&self) -> &Self::Target {
// https://github.com/dtolnay/case-studies/tree/master/callable-types
// First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
let uninit_callable = MaybeUninit::<Self>::uninit();
// Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
// Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
let size_of_closure = std::mem::size_of_val(&uninit_closure);
assert_eq!(size_of_closure, std::mem::size_of::<Self>());
// Then cast the lifetime of the closure to the lifetime of &self.
fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
b
}
let reference_to_closure = cast_lifetime(
{
// The real closure that we will never use.
&uninit_closure
},
// We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self.
unsafe { std::mem::transmute(self) },
);
// Cast the closure to a trait object.
reference_to_closure as &Self::Target
}
}
+24
View File
@@ -29,6 +29,30 @@ fn create_signals_global() {
} }
} }
#[test]
fn deref_signal() {
let mut dom = VirtualDom::new(|cx| {
render! {
for _ in 0..10 {
Child {}
}
}
});
fn Child(cx: Scope) -> Element {
let signal = Signal::new("hello world".to_string());
// You can call signals like functions to get a Ref of their value.
assert_eq!(&*signal(), "hello world");
render! {
"hello world"
}
}
let _edits = dom.rebuild().santize();
}
#[test] #[test]
fn drop_signals() { fn drop_signals() {
let mut dom = VirtualDom::new(|cx| { let mut dom = VirtualDom::new(|cx| {