mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
fix: reimplement Oco
cloning (#1749)
This commit is contained in:
parent
d651400fa2
commit
baa5ea83fa
7 changed files with 67 additions and 101 deletions
|
@ -929,7 +929,7 @@ thread_local! {
|
|||
/// This is cached as a thread-local variable, so calling `window()` multiple times
|
||||
/// requires only one call out to JavaScript.
|
||||
pub fn window() -> web_sys::Window {
|
||||
WINDOW.with(|window| window.clone())
|
||||
WINDOW.with(Clone::clone)
|
||||
}
|
||||
|
||||
/// Returns the [`Document`](https://developer.mozilla.org/en-US/docs/Web/API/Document).
|
||||
|
@ -937,7 +937,7 @@ pub fn window() -> web_sys::Window {
|
|||
/// This is cached as a thread-local variable, so calling `document()` multiple times
|
||||
/// requires only one call out to JavaScript.
|
||||
pub fn document() -> web_sys::Document {
|
||||
DOCUMENT.with(|document| document.clone())
|
||||
DOCUMENT.with(Clone::clone)
|
||||
}
|
||||
|
||||
/// Returns true if running on the server (SSR).
|
||||
|
|
|
@ -212,7 +212,7 @@ pub fn render_to_stream_with_prefix_undisposed_with_context_and_block_replacemen
|
|||
.push(async move { (fragment_id, data.out_of_order.await) });
|
||||
} else {
|
||||
fragments.push(Box::pin(async move {
|
||||
(fragment_id.clone(), data.out_of_order.await)
|
||||
(fragment_id, data.out_of_order.await)
|
||||
})
|
||||
as Pin<Box<dyn Future<Output = (String, String)>>>);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
|
|||
Owned(<T as ToOwned>::Owned),
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToOwned> Oco<'_, T> {
|
||||
impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
|
||||
/// Converts the value into an owned value.
|
||||
pub fn into_owned(self) -> <T as ToOwned>::Owned {
|
||||
match self {
|
||||
|
@ -211,15 +211,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
// Cloning (has to be implemented manually because of the `Rc<T>: From<&<T as ToOwned>::Owned>` bound)
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
impl Clone for Oco<'_, str> {
|
||||
impl<'a, T> Clone for Oco<'a, T>
|
||||
where
|
||||
T: ?Sized + ToOwned + 'a,
|
||||
for<'b> Rc<T>: From<&'b T>,
|
||||
{
|
||||
/// Returns a new [`Oco`] with the same value as this one.
|
||||
/// If the value is [`Oco::Owned`], this will convert it into
|
||||
/// [`Oco::Counted`], so that the next clone will be O(1).
|
||||
/// # Examples
|
||||
/// [`String`] :
|
||||
/// ```
|
||||
/// # use leptos_reactive::oco::Oco;
|
||||
/// let oco = Oco::<str>::Owned("Hello".to_string());
|
||||
|
@ -227,106 +228,48 @@ impl Clone for Oco<'_, str> {
|
|||
/// assert_eq!(oco, oco2);
|
||||
/// assert!(oco2.is_counted());
|
||||
/// ```
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Oco::Borrowed(v) => Oco::Borrowed(v),
|
||||
Oco::Counted(v) => Oco::Counted(v.clone()),
|
||||
Oco::Owned(v) => Oco::Counted(Rc::<str>::from(v.as_str())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Oco<'_, CStr> {
|
||||
/// Returns a new [`Oco`] with the same value as this one.
|
||||
/// If the value is [`Oco::Owned`], this will convert it into
|
||||
/// [`Oco::Counted`], so that the next clone will be O(1).
|
||||
/// # Examples
|
||||
/// [`Vec`] :
|
||||
/// ```
|
||||
/// # use leptos_reactive::oco::Oco;
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// let oco = Oco::<CStr>::Owned(
|
||||
/// CStr::from_bytes_with_nul(b"Hello\0").unwrap().to_owned(),
|
||||
/// );
|
||||
/// let oco = Oco::<[u8]>::Owned(b"Hello".to_vec());
|
||||
/// let oco2 = oco.clone();
|
||||
/// assert_eq!(oco, oco2);
|
||||
/// assert!(oco2.is_counted());
|
||||
/// ```
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Oco::Borrowed(v) => Oco::Borrowed(v),
|
||||
Oco::Counted(v) => Oco::Counted(v.clone()),
|
||||
Oco::Owned(v) => Oco::Counted(Rc::<CStr>::from(v.as_c_str())),
|
||||
Self::Borrowed(v) => Self::Borrowed(v),
|
||||
Self::Counted(v) => Self::Counted(Rc::clone(v)),
|
||||
Self::Owned(v) => Self::Counted(Rc::from(v.borrow())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Oco<'_, OsStr> {
|
||||
/// Returns a new [`Oco`] with the same value as this one.
|
||||
/// If the value is [`Oco::Owned`], this will convert it into
|
||||
/// [`Oco::Counted`], so that the next clone will be O(1).
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos_reactive::oco::Oco;
|
||||
/// use std::ffi::OsStr;
|
||||
///
|
||||
/// let oco = Oco::<OsStr>::Owned(OsStr::new("Hello").to_owned());
|
||||
/// let oco2 = oco.clone();
|
||||
/// assert_eq!(oco, oco2);
|
||||
/// assert!(oco2.is_counted());
|
||||
/// ```
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Oco::Borrowed(v) => Oco::Borrowed(v),
|
||||
Oco::Counted(v) => Oco::Counted(v.clone()),
|
||||
Oco::Owned(v) => Oco::Counted(Rc::<OsStr>::from(v.as_os_str())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Oco<'_, Path> {
|
||||
/// Returns a new [`Oco`] with the same value as this one.
|
||||
/// If the value is [`Oco::Owned`], this will convert it into
|
||||
/// [`Oco::Counted`], so that the next clone will be O(1).
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos_reactive::oco::Oco;
|
||||
/// use std::path::Path;
|
||||
///
|
||||
/// let oco = Oco::<Path>::Owned(Path::new("Hello").to_owned());
|
||||
/// let oco2 = oco.clone();
|
||||
/// assert_eq!(oco, oco2);
|
||||
/// assert!(oco2.is_counted());
|
||||
/// ```
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Oco::Borrowed(v) => Oco::Borrowed(v),
|
||||
Oco::Counted(v) => Oco::Counted(v.clone()),
|
||||
Oco::Owned(v) => Oco::Counted(Rc::<Path>::from(v.as_path())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Clone for Oco<'_, [T]>
|
||||
impl<'a, T> Oco<'a, T>
|
||||
where
|
||||
[T]: ToOwned<Owned = Vec<T>>,
|
||||
T: ?Sized + ToOwned + 'a,
|
||||
for<'b> Rc<T>: From<&'b T>,
|
||||
{
|
||||
/// Returns a new [`Oco`] with the same value as this one.
|
||||
/// If the value is [`Oco::Owned`], this will convert it into
|
||||
/// [`Oco::Counted`], so that the next clone will be O(1).
|
||||
/// Clones the value with inplace conversion into [`Oco::Counted`] if it
|
||||
/// was previously [`Oco::Owned`].
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos_reactive::oco::Oco;
|
||||
/// let oco = Oco::<[i32]>::Owned(vec![1, 2, 3]);
|
||||
/// let oco2 = oco.clone();
|
||||
/// assert_eq!(oco, oco2);
|
||||
/// let mut oco1 = Oco::<str>::Owned("Hello".to_string());
|
||||
/// let oco2 = oco1.clone_inplace();
|
||||
/// assert_eq!(oco1, oco2);
|
||||
/// assert!(oco1.is_counted());
|
||||
/// assert!(oco2.is_counted());
|
||||
/// ```
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Oco::Borrowed(v) => Oco::Borrowed(v),
|
||||
Oco::Counted(v) => Oco::Counted(v.clone()),
|
||||
Oco::Owned(v) => Oco::Counted(Rc::<[T]>::from(v.as_slice())),
|
||||
pub fn clone_inplace(&mut self) -> Self {
|
||||
match &*self {
|
||||
Self::Borrowed(v) => Self::Borrowed(v),
|
||||
Self::Counted(v) => Self::Counted(Rc::clone(v)),
|
||||
Self::Owned(v) => {
|
||||
let rc = Rc::from(v.borrow());
|
||||
*self = Self::Counted(rc.clone());
|
||||
Self::Counted(rc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -689,23 +632,46 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn cloned_owned_string_should_become_counted_str() {
|
||||
fn cloned_owned_string_should_make_counted_str() {
|
||||
let s: Oco<str> = Oco::Owned(String::from("hello"));
|
||||
assert!(s.clone().is_counted());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cloned_borrowed_str_should_remain_borrowed_str() {
|
||||
fn cloned_borrowed_str_should_make_borrowed_str() {
|
||||
let s: Oco<str> = Oco::Borrowed("hello");
|
||||
assert!(s.clone().is_borrowed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cloned_counted_str_should_remain_counted_str() {
|
||||
fn cloned_counted_str_should_make_counted_str() {
|
||||
let s: Oco<str> = Oco::Counted(Rc::from("hello"));
|
||||
assert!(s.clone().is_counted());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cloned_inplace_owned_string_should_make_counted_str_and_become_counted()
|
||||
{
|
||||
let mut s: Oco<str> = Oco::Owned(String::from("hello"));
|
||||
assert!(s.clone_inplace().is_counted());
|
||||
assert!(s.is_counted());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cloned_inplace_borrowed_str_should_make_borrowed_str_and_remain_borrowed(
|
||||
) {
|
||||
let mut s: Oco<str> = Oco::Borrowed("hello");
|
||||
assert!(s.clone_inplace().is_borrowed());
|
||||
assert!(s.is_borrowed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cloned_inplace_counted_str_should_make_counted_str_and_remain_counted() {
|
||||
let mut s: Oco<str> = Oco::Counted(Rc::from("hello"));
|
||||
assert!(s.clone_inplace().is_counted());
|
||||
assert!(s.is_counted());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialization_works() {
|
||||
let s = serde_json::to_string(&Oco::Borrowed("foo"))
|
||||
|
|
|
@ -82,11 +82,11 @@ pub fn Link(
|
|||
) -> impl IntoView {
|
||||
let meta = use_head();
|
||||
let next_id = meta.tags.get_next_id();
|
||||
let id: Oco<'static, str> =
|
||||
let mut id: Oco<'static, str> =
|
||||
id.unwrap_or_else(|| format!("leptos-link-{}", next_id.0).into());
|
||||
|
||||
let builder_el = leptos::leptos_dom::html::as_meta_tag({
|
||||
let id = id.clone();
|
||||
let id = id.clone_inplace();
|
||||
move || {
|
||||
leptos::leptos_dom::html::link()
|
||||
.attr("id", id)
|
||||
|
|
|
@ -64,11 +64,11 @@ pub fn Script(
|
|||
) -> impl IntoView {
|
||||
let meta = use_head();
|
||||
let next_id = meta.tags.get_next_id();
|
||||
let id: Oco<'static, str> =
|
||||
let mut id: Oco<'static, str> =
|
||||
id.unwrap_or_else(|| format!("leptos-link-{}", next_id.0).into());
|
||||
|
||||
let builder_el = leptos::leptos_dom::html::as_meta_tag({
|
||||
let id = id.clone();
|
||||
let id = id.clone_inplace();
|
||||
move || {
|
||||
leptos::leptos_dom::html::script()
|
||||
.attr("id", id)
|
||||
|
|
|
@ -43,11 +43,11 @@ pub fn Style(
|
|||
) -> impl IntoView {
|
||||
let meta = use_head();
|
||||
let next_id = meta.tags.get_next_id();
|
||||
let id: Oco<'static, str> =
|
||||
let mut id: Oco<'static, str> =
|
||||
id.unwrap_or_else(|| format!("leptos-link-{}", next_id.0).into());
|
||||
|
||||
let builder_el = leptos::leptos_dom::html::as_meta_tag({
|
||||
let id = id.clone();
|
||||
let id = id.clone_inplace();
|
||||
move || {
|
||||
leptos::leptos_dom::html::style()
|
||||
.attr("id", id)
|
||||
|
|
|
@ -51,13 +51,13 @@ pub fn create_query_signal<T>(
|
|||
where
|
||||
T: FromStr + ToString + PartialEq,
|
||||
{
|
||||
let key = key.into();
|
||||
let mut key: Oco<'static, str> = key.into();
|
||||
let query_map = use_query_map();
|
||||
let navigate = use_navigate();
|
||||
let location = use_location();
|
||||
|
||||
let get = create_memo({
|
||||
let key = key.clone();
|
||||
let key = key.clone_inplace();
|
||||
move |_| {
|
||||
query_map
|
||||
.with(|map| map.get(&key).and_then(|value| value.parse().ok()))
|
||||
|
|
Loading…
Reference in a new issue